PHP Static Analysis Tool - discover bugs in your code without running it!
@nem75 https://github.com/phpstan/phpstan/issues/4633
StrictComparisonOfDifferentTypesRule - tip about treatPhpDocTypesAsCertain
ConstantLooseComparisonRule - respect treatPhpDocTypesAsCertain
ConstantLooseComparisonRule - tip about treatPhpDocTypesAsCertain
Update phpstan-strict-rules
Test cases - make some methods static because of PHPUnit 10 dataProviders
DynamicCallOnStaticMethodsRule - do not report for methods declared on PHPStanTestCase and TypeInferenceTestCase
Yes, that's another solution that works :)
Consider this piece of code:
class ArrayLibrary
{
/**
* @param non-empty-list<int> $list
*/
public function getFirst(array $list): int
{
if (count($list) === 0) { // PHPStan Error: this condition is alway false
throw new \LogicException('empty array');
}
return $list[0];
}
}
Same code on the playground: https://phpstan.org/r/62c74bad-ba56-4825-b45a-a7819bede63b
Why Am I not allowed to add this additional check? I want to protect my code in any case. What if someone skips the PHPStan checks? What if my code is a library used in projects without PHPStan?
Yes, I know that I can I avoid using this annotation, but I think that this annotation is great: projects with PHPStan will benefit to know that getFirst()
needs a non-empty array without executing the code.
See: https://phpstan.org/config-reference#treatphpdoctypesascertain
Your project is broken. You're saying "the classes in 'tests' can be autoloaded with Composer" with:
"autoload-dev": {
"psr-4": {
"TimeToCode\\Tests\\": "tests/"
}
}
But when it comes to autoloading TimeToCode\Tests\FooTest
, it crashes because your promise isn't true - PHPUnit is missing in Composer.
Removing this section from composer.json also makes PHPStan work:
diff --git a/composer.json b/composer.json
index 970fd1e..66a1150 100644
--- a/composer.json
+++ b/composer.json
@@ -17,11 +17,6 @@
"TimeToCode\\": "src/"
}
},
- "autoload-dev": {
- "psr-4": {
- "TimeToCode\\Tests\\": "tests/"
- }
- },
"scripts": {
"phpstan": "vendor/bin/phpstan analyze"
}
Test PHPUnit 10 with failed scenario
We'd have to rework how trait analysis works once again: https://phpstan.org/blog/how-phpstan-analyses-traits
Feel free to ignore this error for now: https://phpstan.org/user-guide/ignoring-errors#ignoring-in-code-using-phpdocs
We use phive to install PHPUnit in our project. When using PHPStan with the PHPStan Doctrine extension, we get an error when we try to define a property in a test case:
#0 phar:///home/vagrant/sources-work/phpstan-phpunit-phar-testcase-members/vendor/phpstan/phpstan/phpstan.phar/vendor/composer/ClassLoader.php(582): include()
#1 phar:///home/vagrant/sources-work/phpstan-phpunit-phar-testcase-members/vendor/phpstan/phpstan/phpstan.phar/vendor/composer/ClassLoader.php(433): Composer\Autoload\{closure}()
#2 [internal function]: Composer\Autoload\ClassLoader->loadClass()
#3 /home/vagrant/sources-work/phpstan-phpunit-phar-testcase-members/vendor/phpstan/phpstan-doctrine/src/Type/Doctrine/ObjectMetadataResolver.php(68): class_exists()
#4 /home/vagrant/sources-work/phpstan-phpunit-phar-testcase-members/vendor/phpstan/phpstan-doctrine/src/Type/Doctrine/ObjectMetadataResolver.php(110):
PHPStan\Type\Doctrine\ObjectMetadataResolver->isTransient()
#5 /home/vagrant/sources-work/phpstan-phpunit-phar-testcase-members/vendor/phpstan/phpstan-doctrine/src/Rules/Doctrine/ORM/PropertiesExtension.php(70):
PHPStan\Type\Doctrine\ObjectMetadataResolver->getClassMetadata()
#6 phar:///home/vagrant/sources-work/phpstan-phpunit-phar-testcase-members/vendor/phpstan/phpstan/phpstan.phar/src/Node/ClassPropertiesNode.php(130):
PHPStan\Rules\Doctrine\ORM\PropertiesExtension->isInitialized()
#7 phar:///home/vagrant/sources-work/phpstan-phpunit-phar-testcase-members/vendor/phpstan/phpstan/phpstan.phar/src/Rules/DeadCode/UnusedPrivatePropertyRule.php(157):
PHPStan\Node\ClassPropertiesNode->getUninitializedProperties()
#8 phar:///home/vagrant/sources-work/phpstan-phpunit-phar-testcase-members/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/FileAnalyser.php(106):
PHPStan\Rules\DeadCode\UnusedPrivatePropertyRule->processNode()
#9 phar:///home/vagrant/sources-work/phpstan-phpunit-phar-testcase-members/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScopeResolver.php(602):
PHPStan\Analyser\FileAnalyser->PHPStan\Analyser\{closure}()
#10 phar:///home/vagrant/sources-work/phpstan-phpunit-phar-testcase-members/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScopeResolver.php(362):
PHPStan\Analyser\NodeScopeResolver->processStmtNode()
#11 phar:///home/vagrant/sources-work/phpstan-phpunit-phar-testcase-members/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScopeResolver.php(573):
PHPStan\Analyser\NodeScopeResolver->processStmtNodes()
#12 phar:///home/vagrant/sources-work/phpstan-phpunit-phar-testcase-members/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScopeResolver.php(331):
PHPStan\Analyser\NodeScopeResolver->processStmtNode()
#13 phar:///home/vagrant/sources-work/phpstan-phpunit-phar-testcase-members/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/FileAnalyser.php(175): PHPStan\Analyser\NodeScopeResolver->processNodes()
#14 phar:///home/vagrant/sources-work/phpstan-phpunit-phar-testcase-members/vendor/phpstan/phpstan/phpstan.phar/src/Command/WorkerCommand.php(130): PHPStan\Analyser\FileAnalyser->analyseFile()
#15 phar:///home/vagrant/sources-work/phpstan-phpunit-phar-testcase-members/vendor/phpstan/phpstan/phpstan.phar/vendor/evenement/evenement/src/Evenement/EventEmitterTrait.php(97):
PHPStan\Command\WorkerCommand->PHPStan\Command\{closure}()
#16 phar:///home/vagrant/sources-work/phpstan-phpunit-phar-testcase-members/vendor/phpstan/phpstan/phpstan.phar/vendor/clue/ndjson-react/src/Decoder.php(110):
_PHPStan_cbfb23d84\Evenement\EventEmitter->emit()
#17 phar:///home/vagrant/sources-work/phpstan-phpunit-phar-testcase-members/vendor/phpstan/phpstan/phpstan.phar/vendor/evenement/evenement/src/Evenement/EventEmitterTrait.php(97):
_PHPStan_cbfb23d84\Clue\React\NDJson\Decoder->handleData()
#18 phar:///home/vagrant/sources-work/phpstan-phpunit-phar-testcase-members/vendor/phpstan/phpstan/phpstan.phar/vendor/react/stream/src/Util.php(62): _PHPStan_cbfb23d84\Evenement\EventEmitter->emit()
#19 phar:///home/vagrant/sources-work/phpstan-phpunit-phar-testcase-members/vendor/phpstan/phpstan/phpstan.phar/vendor/evenement/evenement/src/Evenement/EventEmitterTrait.php(97):
_PHPStan_cbfb23d84\React\Stream\Util::_PHPStan_cbfb23d84\React\Stream\{closure}()
#20 phar:///home/vagrant/sources-work/phpstan-phpunit-phar-testcase-members/vendor/phpstan/phpstan/phpstan.phar/vendor/react/stream/src/DuplexResourceStream.php(154):
_PHPStan_cbfb23d84\Evenement\EventEmitter->emit()
#21 phar:///home/vagrant/sources-work/phpstan-phpunit-phar-testcase-members/vendor/phpstan/phpstan/phpstan.phar/vendor/react/event-loop/src/StreamSelectLoop.php(201):
_PHPStan_cbfb23d84\React\Stream\DuplexResourceStream->handleData()
#22 phar:///home/vagrant/sources-work/phpstan-phpunit-phar-testcase-members/vendor/phpstan/phpstan/phpstan.phar/vendor/react/event-loop/src/StreamSelectLoop.php(173):
_PHPStan_cbfb23d84\React\EventLoop\StreamSelectLoop->waitForStreamActivity()
#23 phar:///home/vagrant/sources-work/phpstan-phpunit-phar-testcase-members/vendor/phpstan/phpstan/phpstan.phar/src/Command/WorkerCommand.php(96): _PHPStan_cbfb23d84\React\EventLoop\StreamSelectLoop->run()
#24 phar:///home/vagrant/sources-work/phpstan-phpunit-phar-testcase-members/vendor/phpstan/phpstan/phpstan.phar/vendor/symfony/console/Command/Command.php(259): PHPStan\Command\WorkerCommand->execute()
#25 phar:///home/vagrant/sources-work/phpstan-phpunit-phar-testcase-members/vendor/phpstan/phpstan/phpstan.phar/vendor/symfony/console/Application.php(870):
_PHPStan_cbfb23d84\Symfony\Component\Console\Command\Command->run()
#26 phar:///home/vagrant/sources-work/phpstan-phpunit-phar-testcase-members/vendor/phpstan/phpstan/phpstan.phar/vendor/symfony/console/Application.php(261):
_PHPStan_cbfb23d84\Symfony\Component\Console\Application->doRunCommand()
#27 phar:///home/vagrant/sources-work/phpstan-phpunit-phar-testcase-members/vendor/phpstan/phpstan/phpstan.phar/vendor/symfony/console/Application.php(157):
_PHPStan_cbfb23d84\Symfony\Component\Console\Application->doRun()
#28 phar:///home/vagrant/sources-work/phpstan-phpunit-phar-testcase-members/vendor/phpstan/phpstan/phpstan.phar/bin/phpstan(124): _PHPStan_cbfb23d84\Symfony\Component\Console\Application->run()
#29 phar:///home/vagrant/sources-work/phpstan-phpunit-phar-testcase-members/vendor/phpstan/phpstan/phpstan.phar/bin/phpstan(125): _PHPStan_cbfb23d84\{closure}()
#30 /home/vagrant/sources-work/phpstan-phpunit-phar-testcase-members/vendor/phpstan/phpstan/phpstan(8): require('...')
#31 /home/vagrant/sources-work/phpstan-phpunit-phar-testcase-members/vendor/bin/phpstan(120): include('...')
#32 {main}
Please see https://github.com/timetocodeNL/phpstan-phpunit-phar-testcase-members to reproduce this issue.
You're missing phpunit/phpunit
in your dependencies: composer require --dev phpunit/phpunit
After this command it works.
Test for PHPUnit 10 + TypeInferenceTestcase
Thank you!
Update functionMap.php
Just like parse
, format
and formatCurrency
the parseCurrency
method can also return false
in the case of failure.
https://www.php.net/manual/en/numberformatter.parsecurrency.php
What's your expectation? The problem is that this parse error is thrown by Doctrine itself, which means that Doctrine doesn't like your annotation.
Do you expect PHPStan not to crash (but print an error about a syntax error), or do you expect this parse error to not happen at all?
Adding [#AllowDynamicProperties]
on top of a class isn't the same as saying "this class has all the properties". It just alows properties on PHP 8.2+ that are not declared to be added with:
@property
: https://phpstan.org/writing-php-code/phpdocs-basics#magic-propertiesIf a class has the [#AllowDynamicProperties]
attribute, phpstan still warns about the use of those dynamic properties.
https://phpstan.org/r/840776cc-6b9b-4ff8-b680-58e44f24aacb
PHPStan detected the use of dynamic properties, when it should not have done.
It's been very useful for us. We're trying to adopt it across out huge codebase :)
I think the best way for you is to get inspired by the current rules in PHPStan, and implement it your own way. They are easy and small: https://github.com/phpstan/phpstan-src/tree/1.10.x/src/Rules/Exceptions
I'd like to document @throws
.
I use bleeding edge and
exceptions:
check:
missingCheckedExceptionInThrows: true
tooWideThrowType: true
I've found out that
/**
* @throws RuntimeException
* @throws InvalidArgumentException
* @throws TypeErrorException
*/
and
/**
* @throws Exception
*/
are ~same for phpstan.
Would it be possible for phpstan to require having only those exceptions that are actually thrown in @throws
, instead of being satisfied by its parent?
That said \Exception
is parent for all exceptions. So when there's following code:
function foo(int $x): never {
if ($x === 1) {
throw new A();
}
if ($x === 1) {
throw new B();
}
throw new C();
}
phpstan is satisfied by having @throws \Exception
.
Would it be possible to require only @throws A, B, C
and not @throws \Exception
.
The point is to always list all lowest level exceptions that are thrown.
Is it possible or am I missing something?
Fix pg_pconnect function signature
https://www.php.net/manual/en/function.pg-pconnect.php
https://www.php.net/manual/en/function.pg-pconnect.php
Integration project for efabrica/phpstan-latte
Integration project for tomasvotruba/bladestan
Update Larastan
Update Doctrine ORM baseline
Update Carbon baseline
Update Rector
Update Composer
Update Nextras ORM
Fix rendering multiple tips
Revert "Newlines between tips in playground"
This reverts commit 0cb880930eb429549e74b269cda80246c514dcd8.