Skip to content

Commit 708e761

Browse files
javernicolas-grekas
authored andcommitted
[EventDispatcher] Fix removing listeners when using first-class callable syntax
1 parent 3ccfcfb commit 708e761

File tree

3 files changed

+34
-5
lines changed

3 files changed

+34
-5
lines changed

Debug/TraceableEventDispatcher.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ public function removeListener($eventName, $listener)
7575
{
7676
if (isset($this->wrappedListeners[$eventName])) {
7777
foreach ($this->wrappedListeners[$eventName] as $index => $wrappedListener) {
78-
if ($wrappedListener->getWrappedListener() === $listener) {
78+
if ($wrappedListener->getWrappedListener() === $listener || ($listener instanceof \Closure && $wrappedListener->getWrappedListener() == $listener)) {
7979
$listener = $wrappedListener;
8080
unset($this->wrappedListeners[$eventName][$index]);
8181
break;
@@ -110,8 +110,8 @@ public function getListenerPriority($eventName, $listener)
110110
// we might have wrapped listeners for the event (if called while dispatching)
111111
// in that case get the priority by wrapper
112112
if (isset($this->wrappedListeners[$eventName])) {
113-
foreach ($this->wrappedListeners[$eventName] as $index => $wrappedListener) {
114-
if ($wrappedListener->getWrappedListener() === $listener) {
113+
foreach ($this->wrappedListeners[$eventName] as $wrappedListener) {
114+
if ($wrappedListener->getWrappedListener() === $listener || ($listener instanceof \Closure && $wrappedListener->getWrappedListener() == $listener)) {
115115
return $this->dispatcher->getListenerPriority($eventName, $wrappedListener);
116116
}
117117
}

EventDispatcher.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ public function getListenerPriority($eventName, $listener)
122122
$v[0] = $v[0]();
123123
$v[1] = $v[1] ?? '__invoke';
124124
}
125-
if ($v === $listener) {
125+
if ($v === $listener || ($listener instanceof \Closure && $v == $listener)) {
126126
return $priority;
127127
}
128128
}
@@ -178,7 +178,7 @@ public function removeListener($eventName, $listener)
178178
$v[0] = $v[0]();
179179
$v[1] = $v[1] ?? '__invoke';
180180
}
181-
if ($v === $listener) {
181+
if ($v === $listener || ($listener instanceof \Closure && $v == $listener)) {
182182
unset($listeners[$k], $this->sorted[$eventName], $this->optimized[$eventName]);
183183
}
184184
}

Tests/EventDispatcherTest.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,35 @@ public function testMutatingWhilePropagationIsStopped()
421421
$this->assertTrue($testLoaded);
422422
}
423423

424+
/**
425+
* @requires PHP 8.1
426+
*/
427+
public function testNamedClosures()
428+
{
429+
$listener = new TestEventListener();
430+
431+
$callback1 = \Closure::fromCallable($listener);
432+
$callback2 = \Closure::fromCallable($listener);
433+
$callback3 = \Closure::fromCallable(new TestEventListener());
434+
435+
$this->assertNotSame($callback1, $callback2);
436+
$this->assertNotSame($callback1, $callback3);
437+
$this->assertNotSame($callback2, $callback3);
438+
$this->assertTrue($callback1 == $callback2);
439+
$this->assertFalse($callback1 == $callback3);
440+
441+
$this->dispatcher->addListener('foo', $callback1, 3);
442+
$this->dispatcher->addListener('foo', $callback2, 2);
443+
$this->dispatcher->addListener('foo', $callback3, 1);
444+
445+
$this->assertSame(3, $this->dispatcher->getListenerPriority('foo', $callback1));
446+
$this->assertSame(3, $this->dispatcher->getListenerPriority('foo', $callback2));
447+
448+
$this->dispatcher->removeListener('foo', $callback1);
449+
450+
$this->assertSame(['foo' => [$callback3]], $this->dispatcher->getListeners());
451+
}
452+
424453
/**
425454
* @group legacy
426455
* @expectedDeprecation Calling the "Symfony\Component\EventDispatcher\EventDispatcherInterface::dispatch()" method with the event name as the first argument is deprecated since Symfony 4.3, pass it as the second argument and provide the event object as the first argument instead.

0 commit comments

Comments
 (0)