diff --git a/src/Symfony/Component/EventDispatcher/EventDispatcher.php b/src/Symfony/Component/EventDispatcher/EventDispatcher.php index 0c87a350a3de4..b82fc60689d71 100644 --- a/src/Symfony/Component/EventDispatcher/EventDispatcher.php +++ b/src/Symfony/Component/EventDispatcher/EventDispatcher.php @@ -29,6 +29,7 @@ class EventDispatcher implements EventDispatcherInterface { private $listeners = array(); private $sorted = array(); + private $listenerCaller; /** * {@inheritdoc} @@ -155,6 +156,11 @@ public function removeSubscriber(EventSubscriberInterface $subscriber) } } + public function setListenerCaller(EventListenerCallerInterface $listenerCaller) + { + $this->listenerCaller = $listenerCaller; + } + /** * Triggers the listeners of an event. * @@ -167,12 +173,27 @@ public function removeSubscriber(EventSubscriberInterface $subscriber) */ protected function doDispatch($listeners, $eventName, Event $event) { + $listenerCaller = $this->getListenerCaller(); + foreach ($listeners as $listener) { if ($event->isPropagationStopped()) { break; } - call_user_func($listener, $event, $eventName, $this); + + $listenerCaller->call($listener, $event, $eventName, $this); + } + } + + /** + * @return EventListenerCallerInterface + */ + private function getListenerCaller() + { + if (null === $this->listenerCaller) { + $this->listenerCaller = new StandardEventListenerCaller(); } + + return $this->listenerCaller; } /** diff --git a/src/Symfony/Component/EventDispatcher/EventListenerCallerInterface.php b/src/Symfony/Component/EventDispatcher/EventListenerCallerInterface.php new file mode 100644 index 0000000000000..4ff44b665b3a4 --- /dev/null +++ b/src/Symfony/Component/EventDispatcher/EventListenerCallerInterface.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher; + +/** + * + */ +interface EventListenerCallerInterface +{ + /** + * @param callable $listener + * @param Event $event + * @param string $eventName + * @param EventDispatcherInterface $eventDispatcher + */ + public function call(callable $listener, Event $event, $eventName, EventDispatcherInterface $eventDispatcher); +} diff --git a/src/Symfony/Component/EventDispatcher/StandardEventListenerCaller.php b/src/Symfony/Component/EventDispatcher/StandardEventListenerCaller.php new file mode 100644 index 0000000000000..9522aa9e93ffb --- /dev/null +++ b/src/Symfony/Component/EventDispatcher/StandardEventListenerCaller.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher; + +/** + * + */ +final class StandardEventListenerCaller implements EventListenerCallerInterface +{ + /** + * {@inheritdoc} + */ + public function call(callable $listener, Event $event, $eventName, EventDispatcherInterface $eventDispatcher) + { + call_user_func($listener, $event, $eventName, $eventDispatcher); + } +} diff --git a/src/Symfony/Component/EventDispatcher/Tests/EventDispatcherTest.php b/src/Symfony/Component/EventDispatcher/Tests/EventDispatcherTest.php index 5faa5c8be876a..3edfccde24a3f 100644 --- a/src/Symfony/Component/EventDispatcher/Tests/EventDispatcherTest.php +++ b/src/Symfony/Component/EventDispatcher/Tests/EventDispatcherTest.php @@ -11,7 +11,9 @@ namespace Symfony\Component\EventDispatcher\Tests; +use Symfony\Component\EventDispatcher\Event; use Symfony\Component\EventDispatcher\EventDispatcher; +use Symfony\Component\EventDispatcher\EventListenerCallerInterface; class EventDispatcherTest extends AbstractEventDispatcherTest { @@ -19,4 +21,25 @@ protected function createEventDispatcher() { return new EventDispatcher(); } + + public function testCustomEventListenerCaller() + { + $listenerCallerMock = $this->getMockForAbstractClass(EventListenerCallerInterface::class); + $listenerCallerMock + ->expects($this->once()) + ->method('call') + ->will($this->returnCallback(function ($listener, Event $event) { + $listener($event); + })); + + $dispatcher = new EventDispatcher(); + $dispatcher->setListenerCaller($listenerCallerMock); + $dispatcher->addListener('foo', function (Event $event) { + $event->stopPropagation(); + }); + + $event = $dispatcher->dispatch('foo', new Event()); + + $this->assertTrue($event->isPropagationStopped()); + } }