Skip to content

Commit

Permalink
[EventDispatcher] Fix removing listeners when using first-class calla…
Browse files Browse the repository at this point in the history
…ble syntax
  • Loading branch information
javer authored and nicolas-grekas committed May 5, 2022
1 parent 3ccfcfb commit 708e761
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 5 deletions.
6 changes: 3 additions & 3 deletions Debug/TraceableEventDispatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public function removeListener($eventName, $listener)
{
if (isset($this->wrappedListeners[$eventName])) {
foreach ($this->wrappedListeners[$eventName] as $index => $wrappedListener) {
if ($wrappedListener->getWrappedListener() === $listener) {
if ($wrappedListener->getWrappedListener() === $listener || ($listener instanceof \Closure && $wrappedListener->getWrappedListener() == $listener)) {
$listener = $wrappedListener;
unset($this->wrappedListeners[$eventName][$index]);
break;
Expand Down Expand Up @@ -110,8 +110,8 @@ public function getListenerPriority($eventName, $listener)
// we might have wrapped listeners for the event (if called while dispatching)
// in that case get the priority by wrapper
if (isset($this->wrappedListeners[$eventName])) {
foreach ($this->wrappedListeners[$eventName] as $index => $wrappedListener) {
if ($wrappedListener->getWrappedListener() === $listener) {
foreach ($this->wrappedListeners[$eventName] as $wrappedListener) {
if ($wrappedListener->getWrappedListener() === $listener || ($listener instanceof \Closure && $wrappedListener->getWrappedListener() == $listener)) {
return $this->dispatcher->getListenerPriority($eventName, $wrappedListener);
}
}
Expand Down
4 changes: 2 additions & 2 deletions EventDispatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ public function getListenerPriority($eventName, $listener)
$v[0] = $v[0]();
$v[1] = $v[1] ?? '__invoke';
}
if ($v === $listener) {
if ($v === $listener || ($listener instanceof \Closure && $v == $listener)) {
return $priority;
}
}
Expand Down Expand Up @@ -178,7 +178,7 @@ public function removeListener($eventName, $listener)
$v[0] = $v[0]();
$v[1] = $v[1] ?? '__invoke';
}
if ($v === $listener) {
if ($v === $listener || ($listener instanceof \Closure && $v == $listener)) {
unset($listeners[$k], $this->sorted[$eventName], $this->optimized[$eventName]);
}
}
Expand Down
29 changes: 29 additions & 0 deletions Tests/EventDispatcherTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,35 @@ public function testMutatingWhilePropagationIsStopped()
$this->assertTrue($testLoaded);
}

/**
* @requires PHP 8.1
*/
public function testNamedClosures()
{
$listener = new TestEventListener();

$callback1 = \Closure::fromCallable($listener);
$callback2 = \Closure::fromCallable($listener);
$callback3 = \Closure::fromCallable(new TestEventListener());

$this->assertNotSame($callback1, $callback2);
$this->assertNotSame($callback1, $callback3);
$this->assertNotSame($callback2, $callback3);
$this->assertTrue($callback1 == $callback2);
$this->assertFalse($callback1 == $callback3);

$this->dispatcher->addListener('foo', $callback1, 3);
$this->dispatcher->addListener('foo', $callback2, 2);
$this->dispatcher->addListener('foo', $callback3, 1);

$this->assertSame(3, $this->dispatcher->getListenerPriority('foo', $callback1));
$this->assertSame(3, $this->dispatcher->getListenerPriority('foo', $callback2));

$this->dispatcher->removeListener('foo', $callback1);

$this->assertSame(['foo' => [$callback3]], $this->dispatcher->getListeners());
}

/**
* @group legacy
* @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.
Expand Down

0 comments on commit 708e761

Please sign in to comment.