Skip to content

Commit

Permalink
minor #34027 [EventDispatcher] handle lazy-callable invokable (nicola…
Browse files Browse the repository at this point in the history
…s-grekas)

This PR was merged into the 4.4 branch.

Discussion
----------

[EventDispatcher] handle lazy-callable invokable

| Q             | A
| ------------- | ---
| Branch?       | 4.4
| Bug fix?      | no
| New feature?  | yes
| Deprecations? | no
| Tickets       | -
| License       | MIT
| Doc PR        | -

Extracted from #34013, for consistency mostly.

Commits
-------

9df4c7d [EventDispatcher] handle lazy-callable invokable
  • Loading branch information
nicolas-grekas committed Oct 22, 2019
2 parents a721a50 + 9df4c7d commit c86271e
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 8 deletions.
18 changes: 12 additions & 6 deletions src/Symfony/Component/EventDispatcher/EventDispatcher.php
Expand Up @@ -111,14 +111,16 @@ public function getListenerPriority($eventName, $listener)
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;
Expand Down Expand Up @@ -165,14 +167,16 @@ public function removeListener($eventName, $listener)
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]);
Expand Down Expand Up @@ -271,8 +275,9 @@ private function sortListeners(string $eventName)

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;
}
Expand All @@ -290,10 +295,11 @@ private function optimizeListeners(string $eventName): array
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);
};
Expand Down
Expand Up @@ -334,17 +334,26 @@ public function testHasListenersIsLazy()

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()
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit c86271e

Please sign in to comment.