diff --git a/src/Symfony/Component/EventDispatcher/EventDispatcher.php b/src/Symfony/Component/EventDispatcher/EventDispatcher.php index ebfd1ec6d5..816a0ea904 100644 --- a/src/Symfony/Component/EventDispatcher/EventDispatcher.php +++ b/src/Symfony/Component/EventDispatcher/EventDispatcher.php @@ -111,14 +111,16 @@ class EventDispatcher implements EventDispatcherInterface return null; } - if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure) { + if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure && 2 >= \count($listener)) { $listener[0] = $listener[0](); + $listener[1] = $listener[1] ?? '__invoke'; } foreach ($this->listeners[$eventName] as $priority => &$listeners) { foreach ($listeners as &$v) { - if ($v !== $listener && \is_array($v) && isset($v[0]) && $v[0] instanceof \Closure) { + if ($v !== $listener && \is_array($v) && isset($v[0]) && $v[0] instanceof \Closure && 2 >= \count($v)) { $v[0] = $v[0](); + $v[1] = $v[1] ?? '__invoke'; } if ($v === $listener) { return $priority; @@ -165,14 +167,16 @@ class EventDispatcher implements EventDispatcherInterface return; } - if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure) { + if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure && 2 >= \count($listener)) { $listener[0] = $listener[0](); + $listener[1] = $listener[1] ?? '__invoke'; } foreach ($this->listeners[$eventName] as $priority => &$listeners) { foreach ($listeners as $k => &$v) { - if ($v !== $listener && \is_array($v) && isset($v[0]) && $v[0] instanceof \Closure) { + if ($v !== $listener && \is_array($v) && isset($v[0]) && $v[0] instanceof \Closure && 2 >= \count($v)) { $v[0] = $v[0](); + $v[1] = $v[1] ?? '__invoke'; } if ($v === $listener) { unset($listeners[$k], $this->sorted[$eventName], $this->optimized[$eventName]); @@ -271,8 +275,9 @@ class EventDispatcher implements EventDispatcherInterface foreach ($this->listeners[$eventName] as &$listeners) { foreach ($listeners as $k => $listener) { - if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure) { + if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure && 2 >= \count($listener)) { $listener[0] = $listener[0](); + $listener[1] = $listener[1] ?? '__invoke'; } $this->sorted[$eventName][] = $listener; } @@ -290,10 +295,11 @@ class EventDispatcher implements EventDispatcherInterface foreach ($this->listeners[$eventName] as &$listeners) { foreach ($listeners as &$listener) { $closure = &$this->optimized[$eventName][]; - if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure) { + if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure && 2 >= \count($listener)) { $closure = static function (...$args) use (&$listener, &$closure) { if ($listener[0] instanceof \Closure) { $listener[0] = $listener[0](); + $listener[1] = $listener[1] ?? '__invoke'; } ($closure = \Closure::fromCallable($listener))(...$args); }; diff --git a/src/Symfony/Component/EventDispatcher/Tests/EventDispatcherTest.php b/src/Symfony/Component/EventDispatcher/Tests/EventDispatcherTest.php index bc2287303d..215afcd5b8 100644 --- a/src/Symfony/Component/EventDispatcher/Tests/EventDispatcherTest.php +++ b/src/Symfony/Component/EventDispatcher/Tests/EventDispatcherTest.php @@ -334,17 +334,26 @@ class EventDispatcherTest extends TestCase public function testDispatchLazyListener() { + $dispatcher = new TestWithDispatcher(); $called = 0; - $factory = function () use (&$called) { + $factory = function () use (&$called, $dispatcher) { ++$called; - return new TestWithDispatcher(); + return $dispatcher; }; $this->dispatcher->addListener('foo', [$factory, 'foo']); $this->assertSame(0, $called); $this->dispatcher->dispatch(new Event(), 'foo'); + $this->assertFalse($dispatcher->invoked); $this->dispatcher->dispatch(new Event(), 'foo'); $this->assertSame(1, $called); + + $this->dispatcher->addListener('bar', [$factory]); + $this->assertSame(1, $called); + $this->dispatcher->dispatch(new Event(), 'bar'); + $this->assertTrue($dispatcher->invoked); + $this->dispatcher->dispatch(new Event(), 'bar'); + $this->assertSame(2, $called); } public function testRemoveFindsLazyListeners() @@ -472,12 +481,20 @@ class TestWithDispatcher { public $name; public $dispatcher; + public $invoked = false; public function foo($e, $name, $dispatcher) { $this->name = $name; $this->dispatcher = $dispatcher; } + + public function __invoke($e, $name, $dispatcher) + { + $this->name = $name; + $this->dispatcher = $dispatcher; + $this->invoked = true; + } } class TestEventSubscriber implements EventSubscriberInterface