phpstan / phpstan-symfony Goto Github PK
View Code? Open in Web Editor NEWSymfony extension for PHPStan
License: MIT License
Symfony extension for PHPStan
License: MIT License
At packagist.org the package phpstan/phpstan-symfony
is not available. For the installation you must type composer require --dev lookyman/phpstan-symfony
instead and also include the config from different namespace vendor/lookyman/phpstan-symfony/extension.neon
.
Designation | Value |
---|---|
php | 7.3 |
symfony/framework | 3.4 |
phpstan | 0.11.8 |
phpstan-symfony | 0.11.6 |
docker | docker run --rm -v `pwd`:/project cacahouete/phpaudit:latest php -d memory_limit=50000M /usr/local/src/vendor/bin/phpstan.phar analyse src -l 1 |
I don't know why, but when I use phpstan-symfony with following config:
symfony:
container_xml_path: /project/var/cache/dev/srcDevDebugProjectContainer.xml
console_application_loader: /project/tests/phpstan/console-application.php
I have the following error:
Line Xxxx/PaymentBundle/Command/SendTaxReceiptCommand.php
------ -----------------------------------------------------------------------
Internal error: Class
'Symfony\Component\DependencyInjection\DefinitionDecorator' not found
Run PHPStan with --debug option and post the stack trace to:
https://github.com/phpstan/phpstan/issues/new
(With option --debug)
Fatal error: Uncaught Error: Class 'Symfony\Component\DependencyInjection\DefinitionDecorator' not found in /project/vendor/hwi/oauth-bundle/DependencyInjection/Security/Factory/OAuthFactory.php:77
Stack trace:
#0 /project/vendor/hwi/oauth-bundle/DependencyInjection/Security/Factory/OAuthFactory.php(101): HWI\Bundle\OAuthBundle\DependencyInjection\Security\Factory\OAuthFactory->createResourceOwnerMap(Object(Symfony\Component\DependencyInjection\Compiler\MergeExtensionConfigurationContainerBuilder), 'main', Array)
#1 /project/vendor/symfony/security-bundle/DependencyInjection/Security/Factory/AbstractFactory.php(53): HWI\Bundle\OAuthBundle\DependencyInjection\Security\Factory\OAuthFactory->createAuthProvider(Object(Symfony\Component\DependencyInjection\Compiler\MergeExtensionConfigurationContainerBuilder), 'main', Array, '...')
#2 /project/vendor/symfony/security-bundle/DependencyInjection/SecurityExtension.php(534): Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\AbstractFactory->create(O in /project/vendor/hwi/oauth-bundle/DependencyInjection/Security/Factory/OAuthFactory.php on line 77
In class ChildDefinition I found class alias π
class_alias(ChildDefinition::class, DefinitionDecorator::class);
I don't understand why phpstan can't found this class :s
The collector for a test client in functional tests isn't using the argument to map to the actual return type, leading to false positives.
$client = static::createClient();
$client->enableProfiler();
$client->request('POST', '/api/1/company);
$this->assertSame(
0,
$client->getProfile()->getCollector('swiftmailer')->getMessageCount()
);
This results in:
Call to an undefined method Symfony\Component\HttpKernel\DataCollector\DataCollectorInterface::getMessageCount()
I have around 10 compiler passes in my code base.
I have NOT configured the path to container XML as I am not interested in testing for existing/non-existing services.
However, somehow, one and only one of my compiler passes fails with the message:
Call to method Symfony\Component\DependencyInjection\ContainerBuilder::has()
with 'fos_http_cache.cache_manager' will always evaluate to false.
The code in question is fairly standard:
if (!$container->has('fos_http_cache.cache_manager')) {
return;
}
Every other compiler pass uses the same pattern and does not fail.
Why?
Thanks!
I suppose to add a rule which override the return type according to the third argument.
It appears that PHPStan doesn't analyse correctly the inheritance in Symfony controllers' getSubscribedServices
method in subclasses of the abstract controller.
https://github.com/theplankmeister/phpstanerr/blob/master/src/Controller/DefaultController.php#L17
also see https://github.com/theplankmeister/phpstanerr/blob/master/src/Example/ExampleService.php
and the output of https://travis-ci.com/theplankmeister/phpstanerr/jobs/166870630 which demonstrates that the service DOES exist (via Cypress testing defined in https://github.com/theplankmeister/phpstanerr/blob/master/cypress/integration/whatevs.js) yet PHPStan still fails.
Expected PHPStan to not complain about Service "example_service" is not registered in the container.
When using the new SF4.3 EventDispatcher::dispatch method signature (https://symfony.com/blog/new-in-symfony-4-3-simpler-event-dispatching) it fails when using the second optional eventName parameter.
The error is the following :
Method
Symfony\Contracts\EventDispatcher\EventDispatcherInterface::dispatch()
invoked with 2 parameters, 1 required.
DynamicMethodReturnTypeExtension is needed.
Symfony 4.1 introduced new testing service container which allows to get private services in tests.
For example following code is correct:
namespace App\Tests\Controller;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Tools\SchemaTool;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Component\DependencyInjection\ContainerInterface;
class DefaultControllerTest extends WebTestCase
{
public function testIndex(): void
{
$client = static::createClient();
/** @var ContainerInterface $container */
$container = $client->getContainer();
$entityManager = $container->get(EntityManagerInterface::class);
// do something with entity manager
$client->request('GET', '/');
$this->assertSame(200, $client->getResponse()->getStatusCode());
}
}
But PHPStan throws error "Service "Doctrine\ORM\EntityManagerInterface" is private."
I have a RealImplementation
with potentially expensive calls that is registered for a ServiceInterface
in services.yml
file. This is overwritten for tests via services_test.yml
to instead use a MockImplentation
.
There's also a sanity check in relevant tests to ensure that the correct version is being used:
$service = $container->get(ServiceInterface::class);
\assert($service instanceof MockImplementation);
This assertion triggers the following error:
Call to function assert() with false will always evaluate to false.
Instanceof between RealImplementation and MockImplementation will always evaluate to false.
This can be worked around by manually widening the type of the variable like so:
/** @var ServiceInterface $service **/
$service = $container->get(ServiceInterface::class);
\assert($service instanceof MockImplementation);
Analysing this class gives the following error:
PHP Fatal error: Uncaught TypeError: Argument 1 passed to PHPStan\Analyser\MutatingScope::getType() must be an instance of PhpParser\Node\Expr, null given, called in development/dev-ops/analyze/vendor-bin/phpstan/vendor/phpstan/phpstan-symfony/src/Type/Symfony/SerializerDynamicReturnTypeExtension.php on line 42 and defined in phar:///development/dev-ops/analyze/vendor-bin/phpstan/vendor/phpstan/phpstan/phpstan/src/Analyser/MutatingScope.php:276
Stack trace:
#0 development/dev-ops/analyze/vendor-bin/phpstan/vendor/phpstan/phpstan-symfony/src/Type/Symfony/SerializerDynamicReturnTypeExtension.php(42): PHPStan\Analyser\MutatingScope->getType(NULL)
phpstan/phpstan#1 phar:///development/dev-ops/analyze/vendor-bin/phpstan/vendor/phpstan/phpstan/phpstan/src/Analyser/MutatingScope.php(2207): PHPStan\Type\Symfony\SerializerDynamicReturnTypeExtension->getTypeFromMethodCall(Object(PHPStan\Reflection\ObjectTypeMethodReflection), Object(PhpParser\Node\Expr\MethodCall), Object(PHPStan\Analyser\MutatingScop in phar:///development/dev-ops/analyze/vendor-bin/phpstan/vendor/phpstan/phpstan/phpstan/src/Analyser/MutatingScope.php on line 276
Happens here https://github.com/shopware/platform/blob/6.1/src/Core/Framework/Struct/Serializer/StructNormalizer.php
But I don't know the exact place. If you need more information, please let me know
it is common pattern to name services as class path, and then select them with SomeClass::class
.
symfony converts those dependencies to lower case before saving / resolving.
This causing errors like Service "SomeNamespace\SomeClass" is not registered in the container.
because in appDevDebugProjectContainer.xml
it is saved as: somenamespace\someclass
Hello, I'm encountering an issue with custom Validation Constraint.
PhpStan returns me this error:
------ -----------------------------------------------------------------------------------
Line common/Bundle/Common/CoreBundle/Validator/Constraints/IsStringValidator.php
------ -----------------------------------------------------------------------------------
21 Access to an undefined property Symfony\Component\Validator\Constraint::$message.
------ -----------------------------------------------------------------------------------
This is my code (just an example, not for production π) :
<?php
// packages/common/Bundle/Common/CoreBundle/Validator/Constraints/IsStringValidator.php
declare(strict_types=1);
namespace Yprox\Bundle\Common\CoreBundle\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
class IsStringValidator extends ConstraintValidator
{
/**
* {@inheritdoc}
*/
public function validate($value, Constraint $constraint)
{
if (null === $value || is_string($value)) {
return true;
}
$this->context->addViolation($constraint->message);
return false;
}
}
<?php
// packages/common/Bundle/Common/CoreBundle/Validator/Constraints/IsString.php
declare(strict_types=1);
namespace Yprox\Bundle\Common\CoreBundle\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
/**
* @Annotation
*/
class IsString extends Constraint
{
public $message = 'Value must be a string';
}
And this is normal, because there is no property $message
on abstrac class Symfony\Component\Validator\Constraint
.
I tried to update my code to this:
/**
* {@inheritdoc}
*/
public function validate($value, IsString $constraint)
but I can't because the declaration is not compatible with ConstraintValidatorInterface::validate($value, Constraint $constraint)
.
So I tried with a PHPDoc like this:
/**
* {@inheritdoc}
* @param IsString $constraint
*/
public function validate($value, Constraint $constraint)
but I still have the same error from PhpStan.
Is there any workaround for that? Should I ignore this error by configuring PhpStan?
Maybe PhpStan can automatically call Constraint#validatedBy()
? I'm not sure about that π ...
Thank you! π
Hi,
given the following code (see the gist https://gist.github.com/84m/1cb41b41fcacf65d1017f4f1c8c09700 for working example)
<?php declare(strict_types = 1);
require_once __DIR__ . '/vendor/autoload.php';
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class Controller
{
public function getFoo(Request $request)
{
$userId = $request->get('userid');
if (isset($userId)) {
$userId = (int)($userId);
}
// ...
$response = new Response();
if (isset($userId)) {
$response->headers->add(['userId' => $userId]);
}
return $response;
}
}
i was not getting an error on 0.10.8:
$ vendor/bin/phpstan analyse --level 1 Controller.php
1/1 [ββββββββββββββββββββββββββββ] 100%
[OK] No errors
After an update to 0.11. i get
$ vendor/bin/phpstan analyse --level 1 Controller.php
1/1 [ββββββββββββββββββββββββββββ] 100%
------ ----------------------------------------------------------------
Line Controller.php
------ ----------------------------------------------------------------
21 Variable $userId in isset() always exists and is not nullable.
------ ----------------------------------------------------------------
[ERROR] Found 1 error
I'm not sure what changed here, but if there's no userid within the request, the variable is still null
It would be nice it this plugin could allow to get User class declared in configuration (e.g. in config/packages/security.yaml
), so it can be retrieved instead of generic \Symfony\Component\Security\Core\User\UserInterface
.
Tipical scenarios are getting User calling $this->getUser()
from controller and calling $tokenStorage->getToken()->getUser()
from a service where token storage is injected.
Hello,
I am adding the console_application_loader
config part on my PHPStan configuration and I'm facing an issue with Symfony's defaults options not being found.
Command "..." does not define option "env".
We are using the env
options to hide some dynamic informations on test environment for our test suite.
My console-application.php
file
<?php
use Symfony\Bundle\FrameworkBundle\Console\Application;
require __DIR__.'/../vendor/autoload.php';
$kernel = new AppKernel('test', false);
return new Application($kernel);
I tried to create a patch, but without success. I don't find a way to retrieve those default options in the UndefinedOptionRule
class.
Hi,
I don't know if it is the correct repository for this issue.
I try to use phpstan in tests (phpunit) folder but I have this error :
with :
phpstan/phpstan 0.12.25 PHPStan - PHP Static Analysis Tool
phpstan/phpstan-doctrine 0.12.13 Doctrine extensions for PHPStan
phpstan/phpstan-phpunit 0.12.8 PHPUnit extensions and rules for PHPStan
phpstan/phpstan-symfony 0.12.6 Symfony Framework extensions and rules for PHPStan
symfony/phpunit-bridge v5.0.8 Symfony PHPUnit Bridge
I have already try to add phpstan-symfony and phpstan-phpunit but not working.
Maybe I forget or misunderstood anything ?
Thank you in advance
Currently, imports are not resolved:
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services
http://symfony.com/schema/dic/services/services-1.0.xsd">
<imports>
<import resource="foo.xml"/>
<import resource="bar.xml"/>
</imports>
</container>
Hello all,
I get a "Call to an undefined method Symfony\Component\Form\FormInterface::getClickedButton()." error when working with Symfony Forms using the following code (within a Symfony Controller class):
$form = $this->createForm(...); $clickedButton = $form->getClickedButton();
The second line will raise the error since the createForm
method returns a FormInterface
Hello,
We have the following error messages while using a command argument/option default value as a constant:
------ ------------------------------------------------------------------------------------------------------------------------------
42 Parameter #4 $default of method Symfony\Component\Console\Command\Command::addArgument() expects string|null, mixed given.
42 Parameter #5 $default of method Symfony\Component\Console\Command\Command::addOption() expects int|string|null, mixed given.
------ ------------------------------------------------------------------------------------------------------------------------------
The following code should return the error:
public const MODE_CREATED = 'created';
protected function configure()
{
$this
->setName('abc')
->addArgument('a', InputArgument::REQUIRED, '', static::MODE_CREATED)
->addOption('b', null, InputOption::VALUE_REQUIRED, '', static::MODE_CREATED)
;
}
Even if the constant value is a string, it's understood as mixed.
For the moment, to avoid the error message, I have a private method which returns the constant value and use it as default value.
Same error as described here: lookyman/phpstan-symfony#9
Code:
$this->get('session')->getFlashBag()->set('notice', 'Message');
Error:
Call to an undefined method object::getFlashBag().
It does work with $this->container->get('session')
.
I encountered this error:
In XmlServiceMapFactory.php line 26:
[PHPStan\Symfony\XmlContainerNotExistsException]
Container .../vendor/phpstan/phpstan/../../../app/cache/dev/appDevDebugProjectContainer.xml not exists
This is however not true, the file does exist. I removed the @
operator in XmlServiceMapFactory and got this:
PHP Warning: simplexml_load_file(): .../vendor/phpstan/phpstan/../../../app/cache/dev/appDevDebugProjectContainer.xml:235: parser error : PCDATA invalid Char value 27 in .../vendor/phpstan/phpstan-symfony/src/Symfony/XmlServiceMapFactory.ph</parameter> in .../vendor/phpstan/phpstan-symfony/src/Symfony/XmlServiceMapFactory.php on line 23
If I use $container->has() in a CompilerPass, php-stan says that is always true.
Example:
<?php declare(strict_types=1);
namespace Project\Web\CompilerPass;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
class ExceptionHandlerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if (!$container->has("project.exception_listener")) {
$definition = $container->findDefinition("project.exception_listener");
$taggedServices = $container->findTaggedServiceIds("project.exception_listener.handler");
foreach ($taggedServices as $id => $taggedService) {
$definition->addMethodCall("addExceptionHandler", [new Reference($id)]);
}
}
}
}
Error:
------ -------------------------------------------
Line src/CompilerPass/ExceptionHandlerPass.php
------ -------------------------------------------
14 Negated boolean is always false.
------ -------------------------------------------
Without the Symfony Plugin it works.
First off, is there a way to test the Symfony extension in the PHPStan Playground? In absence of that, here is the classic way of explaining the problem. We have a couple of conditional get
calls to the service container like so:
if ($container->has('doctrine.orm.entity_manager')) {
$em = $container->get('doctrine.orm.entity_manager');
// ...
}
Unfortunately, this conditional is not properly evaluated:
Service "doctrine.orm.entity_manager" is not registered in the container.
In this case, the get
should not cause an error since it will not be reached if there's no such service.
Symfony: 4.1
PhpStan: 0.10.5
Using the following code
<?php declare(strict_types=1);
// βοΈ
class EntitySearchSelectorController extends AbstractController
{
/**
* @param Request $request
* @param string $entityType
*
* @return JsonResponse
*/
public function doSearch (Request $request, string $entityType) : JsonResponse
{
switch ($entityType)
{
case "material":
$model = $this->get(MaterialModel::class);
break;
case "manufacturer":
$model = $this->get(ManufacturerModel::class);
break;
case "magazine":
$model = $this->get(MagazineContentModel::class);
break;
default:
throw $this->createNotFoundException(\sprintf(
"Unsupported entity type β%sβ.",
$entityType
));
}
// βοΈ
}
/**
* @inheritdoc
*/
public static function getSubscribedServices () : array
{
return \array_replace(parent::getSubscribedServices(), [
MagazineContentModel::class,
ManufacturerModel::class,
MaterialModel::class,
]);
}
}
I'll get an error where PhpStan complains that my services are private
- which is the default for Symfony services. In this example I've marked two of my three services explicitly as public
. However, it shouldn't be needed in this case. The code is working perfectly fine in both dev
and prod
environment. It's just PhpStan that is complaining.
In this project we've adopted the bundle-less approach, as recommended by Symfony.
The config/services.yaml
is also nothing fancy and looks like this:
services:
_defaults:
autowire: true
autoconfigure: true
public: false
App\:
resource: '../src/*'
exclude: '../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}'
# Uncommented for the sake of reproducing/reporting this issue
#App\Model\Magazine\MagazineContentModel:
# # required to keep PhpStan silent
# public: true
App\Model\ManufacturerModel:
# required to keep PhpStan silent
public: true
App\Model\Material\MaterialModel:
# required to keep PhpStan silent
public: true
https://github.com/symfony/framework-bundle/blob/master/Controller/Controller.php is marked as deprecated since 4.2 and there is a new way of defining a controller through https://github.com/symfony/framework-bundle/blob/master/Controller/AbstractController.php.
It also uses PSR-11 Container interface https://github.com/php-fig/container/blob/master/src/ContainerInterface.php, so currently phpstan not being able to find services.
Hi,
Since IΒ updated to version 0.11.4 on this package I have this error message.
#vendor/bin/phpstan analyse -l7 --debug -- src tests config
PHP Fatal error: Uncaught PHPStan\ShouldNotHappenException: Internal error. in /opt/project/vendor/phpstan/phpstan-symfony/src/Rules/Symfony/UndefinedArgumentRule.php:52
Stack trace:
#0 /opt/project/vendor/phpstan/phpstan/src/Analyser/Analyser.php(154): PHPStan\Rules\Symfony\UndefinedArgumentRule->processNode(Object(PhpParser\Node\Expr\MethodCall), Object(PHPStan\Analyser\Scope))
#1 /opt/project/vendor/phpstan/phpstan/src/Analyser/NodeScopeResolver.php(1691): PHPStan\Analyser\Analyser->PHPStan\Analyser\{closure}(Object(PhpParser\Node\Expr\MethodCall), Object(PHPStan\Analyser\Scope))
#2 /opt/project/vendor/phpstan/phpstan/src/Analyser/NodeScopeResolver.php(1139): PHPStan\Analyser\NodeScopeResolver->callNodeCallbackWithExpression(Object(Closure), Object(PhpParser\Node\Expr\MethodCall), Object(PHPStan\Analyser\Scope), Object(PHPStan\Analyser\ExpressionContext))
#3 /opt/project/vendor/phpstan/phpstan/src/Analyser/NodeScopeResolver.php(387): PHPStan\Analyser\NodeScopeResolver->processExprNode(Object(PhpParser\Node\Expr\MethodCall) in /opt/project/vendor/phpstan/phpstan-symfony/src/Rules/Symfony/UndefinedArgumentRule.php on line 52
My phpstan config:
includes:
- ./vendor/phpstan/phpstan-symfony/extension.neon
- ./vendor/phpstan/phpstan-webmozart-assert/extension.neon
- ./vendor/phpstan/phpstan-phpunit/extension.neon
- ./vendor/phpstan/phpstan-phpunit/rules.neon
- ./vendor/phpstan/phpstan-doctrine/extension.neon
- ./vendor/phpstan/phpstan-doctrine/rules.neon
- ./vendor/jangregor/phpstan-prophecy/src/extension.neon
- ./vendor/thecodingmachine/phpstan-safe-rule/phpstan-safe-rule.neon
parameters:
symfony:
container_xml_path: '%rootDir%/../../../var/cache/dev/srcApp_KernelDevDebugContainer.xml'
ignoreErrors:
- message: '#Service ".*" is private\.#'
path: '%currentWorkingDirectory%/tests'
- message: '#Cannot .* on Faker\\Generator\|null\.#'
path: '%currentWorkingDirectory%/tests'
- message: '#Service "test\..*" is not registered in the container\.#'
path: '%currentWorkingDirectory%/tests'
I am using symfony v4.2.6.
Let me know for anything.
Cheers!
Hi,
I don't know if it is the correct repository for this issue.
I try to use phpstan in tests (phpunit) folder but I have this error :
with :
phpstan/phpstan 0.12.25 PHPStan - PHP Static Analysis Tool
phpstan/phpstan-doctrine 0.12.13 Doctrine extensions for PHPStan
phpstan/phpstan-phpunit 0.12.8 PHPUnit extensions and rules for PHPStan
phpstan/phpstan-symfony 0.12.6 Symfony Framework extensions and rules for PHPStan
symfony/phpunit-bridge v5.0.8 Symfony PHPUnit Bridge
I have already try to add phpstan-symfony and phpstan-phpunit but not working.
Maybe I forget or misunderstood anything ?
Thank you in advance
The services defined in a ServiceLocator
are still detected as private.
Can you tag a new release? Or import the tags from the old repository? Currently composer cannot install this package because no versions are tagged.
composer require phpstan/phpstan-symfony
[InvalidArgumentException]
Could not find package phpstan/phpstan-symfony.
Did you mean this?
phpstan/phpstan-symfony
Call to method Symfony\Component\HttpFoundation\Request::hasSession() will always evaluate to true.
I recently ran into a version conflict between this package and phpDocumentor/Reflection
with respect to nikic/php-parser
.
This project's package requires ^4.0
, while the aforementioned package requires either ^1.0
or ^3.0
- depending on how bleeding edge you want to be.
The problem with this is that if nikic/php-parser
releases a major version faster than your library, and another package depends on that newer version, there will be a version conflict disallowing said package and this package from being installed. This in fact is the case for trying to install this package along side phpDocumentor/Reflection
(which is depended on by ramsey/jenkins-php
).
My suggestion, as a library, would be to use a less restrictive version constraint of >=4.0
so that your library can still take advantage of the minimum requirements while not conflicting with newer packages/libraries depending on newer versions.
Thank you.
Request's method getSession
can return null
value, so when I tried call code like this: $request->getSession()->set(...)
I got error:
Cannot call method set() on Symfony\Component\HttpFoundation\Session\SessionInterface|null.
I thought that checking if a request has sessions before call setter, resolve the problem, but unfortunately not. I created a repo which gives You a possibility to reproduce the problem:
https://github.com/plotek/symfony-phpstan
Possible workaround:
if ($request->hasSession()) {
$session = $request->getSession();
Assert::isInstanceOf($session, SessionInterface::class);
$session->set('Test', 'Value');
}
Hello, would it be possible to update dependencies requirements to support Symfony 5 distribution?
I am currently having a problem with phpstan/phpstan 0.11.19 requires symfony/console ~3.2 || ~4.0 -> no matching package found
To solve this symfony/console ^5.0
would be welcomed
However I believe there are more packages that would benefit from getting updated
Hey,
I would like to introduce this extension to Shopware 6.
Due to our plugin system, the cache directory and also the built Symfony DI container are not absolute (See Kernel::getCacheDir)
I understand that the file_get_contents here could not work with a wildcard, e.g. like this: %rootDir%/../../var/cache/dev*/srcShopware_Development_KernelDevDebugContainer.xml
Do you see a way to declare the absolute path on runtime of PHPStan before the Symfony rules are executed? Like a plugin or so, where I set the config container_xml_path
dynamically?
Since I updated my project to Symfony 4/Flex, I had to create .env
, ... files with some values.
For example I have
DATABASE_URL=mysql://user:[email protected]:3300/database
This file seems to not be loaded by phpstan
In EnvVarProcessor.php line 131:
Environment variable not found: "DATABASE_URL".
with this config (phpstan.neon)
includes:
- symfony/vendor/phpstan/phpstan-doctrine/extension.neon
- symfony/vendor/phpstan/phpstan-symfony/extension.neon
- symfony/vendor/phpstan/phpstan-phpunit/extension.neon
- symfony/vendor/phpstan/phpstan-phpunit/rules.neon
parameters:
autoload_directories:
- symfony/src/Migrations
doctrine:
objectManagerLoader: phpstanLoader.php
symfony:
container_xml_path: symfony/var/cache/dev/appAppKernelDevDebugContainer.xml
services:
-
class: PhpStan\ProxyQueryMethodsClassReflectionExtension
tags: [phpstan.broker.methodsClassReflectionExtension]
phpstanLoader.php
<?php
use AssuranceVie\Kernel;
require __DIR__.'/symfony/vendor/autoload.php';
$kernel = new Kernel('test', true);
$kernel->boot();
return $kernel->getContainer()->get('doctrine')->getManager();
What should I add ? I didn't find it in the documentation.
Hello.
When I have this code
$content = json_decode($request->getContent(), true);
and I get this error.
56 Parameter #1 $json of function json_decode expects string,
resource|string given.
It would be nice to have phpstan recognise that default request
returns string.
If you have for example a config/packages/framework.php
Phpstan will report Undefined variable $container
if possible this should always be defined in $container and be typed as ContainerBuilder.
Workaround:
# phpstan.neon
parameters:
# ...
ignoreErrors:
- message: '#Undefined variable: \$container#'
path: '%currentWorkingDirectory%/config/packages/*'
if (!$container->has('doctrine.orm.entity_manager')) {
throw new \InvalidArgumentException('Configure your entity manager correctly');
}
In my bundle I have a check for has
service the phpstan throw the following error: If condition is always true.
or Negated boolean is always false.
because I think the service exist in my current configured container file. But this check is needed as somebody which don't have the other library imported or configured it different.
I think has
should always be possible to be true
or false
.
My symfony services definition is in yaml format, but this seems to only support xml format via the container_xml_path
configuration option. Also does this support symfony 4+?
Thanks!
Symfony\Component\DependencyInjection\ContainerInterface::get()
can return null when using ContainerInterface::NULL_ON_INVALID_REFERENCE
$stack = $container->get('request_stack', ContainerInterface::NULL_ON_INVALID_REFERENCE);
if (null === $stack) {
return null;
}
Strict comparison using === between null and Symfony\Component\HttpFoundation\RequestStack will always evaluate to false.
This is a question, I'd be interested in implementing this, but not sure if its possible with Phpstan, so a point in the right direction would be useful.
In Symfony commands options (and arguments) are added in configure
function, and this affects the return type of $input->getOption
later.
class MyCommand {
protected function configure(): void
{
$this
->addOption('str', null, InputOption::VALUE_REQUIRED, 'This option will be ?string')
->addOption('bool', null, InputOption::VALUE_NONE, 'this option will be bool')
->addOption('arra', null, InputOption::VALUE_IS_ARRAY, 'this option will be ?(string[])')
;
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$str = $input->getOption('str');
}
}
So can I change the return type of getOption
, according to the options that are configured?
Symfony 4.0 documents Symfony\Component\Console\Command\Command::addOption()
's 5th parameter $default
as mixed
.
When using default values with InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL
mode, the $default
parameter expects array<int, string>|null
.
This is wrong because keys are irrelevant and leads to error like this:
Parameter #5 $default of method Symfony\Component\Console\Command\Command::addOption() expects array<int, string>|null, array<string> given.
Happens when $default
is given an array documented as string[]
.
Sample code:
/** @var string[] $default */
$default = getSomeDefaults();
$command->addOption(
'foo',
null,
InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL,
'foo bar',
$default
);
This error pops up at level 0 only with this extension enabled, not without it.
Since Symfony 3.4, services are private by default. However, the XmlServiceMapFactory
still assumes that a service is public if the public
attribute hasn't been set:
phpstan-symfony/src/Symfony/XmlServiceMapFactory.php
Lines 48 to 54 in a6d87e0
(the 3rd argument of the Service
constructor is bool $public
).
This means that the ContainerInterfacePrivateServiceRule
will only report private services if they are explicitly marked as private in their service configuration, but not if they are implicitly private.
In order to correctly report private services being fetched from the container, this logic should be reversed so that a service without a public
flag is considered private:
$service = new Service(
// ...
isset($attrs->public) && (string) $attrs->public !== 'false',
// ...
);
That will result in false positives for Symfony versions < 3.4, but those versions are no longer supported by Symfony itself. Alternatively, the XmlServiceMapFactory
would have to determine the Symfony version and switch it's logic based on that, but I'm not sure if that's even possible...
Hi! Amazing work at phpstan!!
I am using phpstan with symfony and doctrine extensions. I was trying to detect an error for objects injected/autowired through the __construct(). It seems that currently it can't derive the type of the local variable based on the type-hint of the injected parameter. I found out that if I set analysis level at 2 it detects undefined methods called for normal objects instantiated with new. Even at level 7 I couldn't detect undefined methods for injected services.
Thank you!
When using the KernelTestCase
and asking PhpStan to analyze a test, I have this error:
However, the static::$container
that is in the KernelTestCase
is supposed to be an instance of the TestContainer
but is typed as ContainerInterface
because it might happen that the test.container
service can be absent from the container, therefore making static::$container
be the full container (as of KernelTestCase here )
Here is the code that triggers the error: Pierstoval/AgateApps/.../RedeemerTest.php#L61-L79
If the test.container
service exists in the container AND for this specific case, I think there shouldn't be any error.
Please register this package on Packagist so it can be easily tested. π
https://packagist.org/packages/phpstan/phpstan-symfony No packages found.
Symfony\Component\Messenger\Envelope::all()
returns a different type based on whether or not an argument was passed to it. Currently PHPStan doesn't know that which results in errors like this:
Parameter #1 ... of method ... expects array<array<Symfony\Component\Messenger\Stamp\StampInterface>>, array<array<Symfony\Component\Messenger\Stamp\StampInterface>|Symfony\Component\Messenger\Stamp\StampInterface> given.
I'd send PR but I'm not sure how cases like these should be solved in PHPStan. If you can give me an advice how to do it, I'll send the PR.
Symfony had a few recent PRs to the Symfony console that impacted my PHPStan analysis due to PHPDoc changes:
symfony/symfony#28448
symfony/symfony#28374
symfony/symfony#28647
Bottom line:
InputInterface::getArgument
now returns string|string[]|null
InputInterface::getOption
returns string|string[]|bool|null
.In reality, they can return string[]
only if the relative argument/option is set as InputArgument::IS_ARRAY
/InputOption::VALUE_IS_ARRAY
.
Is it possible to add an aid in this package for this case? The minimum repro case is this one:
class PhpstanCommand extends \Symfony\Component\Console\Command\Command
{
protected function configure()
{
$this->addArgument('argument', InputArgument::REQUIRED);
$this->addOption('option', null, InputOption::VALUE_REQUIRED);
}
protected function execute(InputInterface $input, OutputInterface $output)
{
// Cannot cast array<string>|string|null to string.
$argument = (string) $input->getArgument('argument');
// Cannot cast array<string>|bool|string|null to string.
$option = (string) $input->getOption('option');
}
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.