Lecture : 2 min. Auteur(s) : Tags :

Edit 2019–07–08: Good news! PHPStan 0.11.10 includes support for inferring private property type from constructor! https://github.com/phpstan/phpstan/releases/tag/0.11.10:

Turn on with inferPrivatePropertyTypeFromConstructor: true

We use PHPStan a lot and we love it. Some of us even donate each month some money via Patreon.

I faced an issue few months ago, and I hit the very same one today while I started a big refactoring of an application. And I totally forgot about it 😂 Memory sucks :)

So let’s talk about it, and see how to solve it. And now I hope I will remember to fix it on every project I’m working on.

Consider this piece of code:

class Model { } class ServiceA { private $serviceB; public function __construct(ServiceB $serviceB) { $this->serviceB = $serviceB; } public function init() { // This line will generate a FatalError (DateTime != Model) $this->serviceB->process(new DateTime()); } } class ServiceB { public function process(Model $model) { } }

I’m expecting to get this error:

Parameter #1 $model of method ServiceB::process() expects Model, DateTime given.

But why is it valid? Because PHPStan does not infer type from constructor argument. And this is totally valid to not do so.

A solution would be to add some PHPDoc:

class ServiceA { /** @var ServiceB */ private $serviceB; }

In the Symfony community, we have some standards. Additionally, I hate useless PHPDoc. I don’t want to pollute my code by adding them everywhere.

Symfony’s coding standards state to not add the PHPDoc to a property if it can be inferred from the constructor, it is also the default configuration of PHP CS Fixer and it is considered a best practice by some.

Since PHPStan has a nice plugin system, I wrote a plugin to automatically add theses type-hint in PHPStan engine few months ago. I used it in my current application and I was able to find 45 new violations \o/

You can read the code and add it to your project if you want to.