dunglas / DunglasActionBundle

Symfony controllers, redesigned
https://dunglas.fr/2016/01/dunglasactionbundle-symfony-controllers-redesigned/
MIT License
256 stars 14 forks source link

Anonymous classes are also autowired #70

Closed bpolaszek closed 7 years ago

bpolaszek commented 7 years ago

Hi there,

PHP7 introduced anonymous classes and I wanted to play with them, until I found a bug related to DunglasActionBundle (at first I thought the problem came from Symfony DI component)

When using an anonymous class inside an autowired-class, the bundle also tries to autowire the anonymous object, which can lead the autowiring to fail.

Let's assume the following configuration:

# app/config/config.yml
dunglas_action:
    directories:
        - ../src/AppBundle/Services

And the following code:

# src/AppBundle/Services/MyService.php

namespace AppBundle\Services;

use Psr\Log\LoggerAwareTrait;
use Psr\Log\LoggerInterface;
use Webmozart\Assert\Assert;

class MyService {

    use LoggerAwareTrait;

    /**
     * MyService constructor.
     * @param LoggerInterface $logger
     */
    public function __construct(LoggerInterface $logger) {
        $this->logger = $logger;
    }

    public function doSomething() {

        Assert::isInstanceOf($this->logger, LoggerInterface::class); // true, Logger has been autowired at that point

        $generator = function () {
            yield 'hello';
        };
        $dummyAnonymousObject = new class($generator) implements \IteratorAggregate {

            /**
             * @var callable
             */
            private $generator;

            public function __construct(callable $generator) {
                $this->generator = $generator;
            }

            public function getIterator() {
                $generator = $this->generator;
                return $generator();
            }

        };

        foreach ($dummyAnonymousObject AS $message) {
            $this->logger->info($message);
        }

    }
}

You'll get the following exception:

RuntimeException in AutowirePass.php line 114:
Unable to autowire argument index 0 ($generator) for the service "class@anonymousc:\www\dev\bug-di\src\appbundle\services\myservice.php000000128974043d". If this is an object, give it a type-hint. Otherwise, specify this argument's value explicitly.

Since anonymous classes are pretty runtime-specific, shouldn't they be ignored by the autowire pass?

Thanks, Ben

dunglas commented 7 years ago

Indeed, they should be excluded.