Search code examples
phpzend-framework2phpstormtype-hinting

Zend Framework 2 – type hinting in constructor – IDE complains about type


In a Zend Framework 2 module, I use a closure as factory:

'controllers' => [
    'factories' => [
        'ZendSkeletonModule\Controller\Skeleton' => function(AbstractPluginManager $pm) {
            return new Controller\SkeletonController($pm->getServiceLocator()->get('Doctrine\ORM\EntityManager'));
        },
    ],
],

While this works without any problems, my IDE (PHP Storm) complains at $pm->getServiceLocator()->get('Doctrine\ORM\EntityManager') with the following message:

Expected \Doctrine\ORM\EntityManagerInterface, got array|object.
Invocation parameter types are not compatible with declared.

That is because in the controller, I use Doctrine\ORM\EntityManagerInterface as a type hint, I get that.

But why does PHP Storm complain, I don't see anything wrong here? Also, the code works fine, so I am a bit puzzled. Do I need to add some kind of special comment or something to 'help' the IDE?


Solution

  • Assign the EntityManager to a variable with an annotation that PhpStorm's static analysis can use. The get method on its own is opaque to it:

    use Doctrine\ORM\EntityManager;
    // snip
    'controllers' => [
        'factories' => [
            'ZendSkeletonModule\Controller\Skeleton' => function(AbstractPluginManager $pm) {
                /** @var EntityManager $entityManager */
                $entityManager = $pm->getServiceLocator()->get(EntityManager::class);
                return new Controller\SkeletonController($entityManager);
            },
        ],
    ],
    

    A couple additional suggestions:

    1. Rather than using a closure, use a concrete factory class. This is because closures cannot be opcode cached, and also your config array cannot be cached if it contains closures.

    2. A small thing, but assuming PHP 5.5+, consider using \Doctrine\ORM\EntityManager::class like I did in the example above, instead of a string literal for the get method on the ServiceLocator.