^ null
^ null
^ null
^ null
Symfony Profiler
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\EventDispatcher ;
use Psr\EventDispatcher\StoppableEventInterface ;
use Symfony\Component\EventDispatcher\Debug\WrappedListener ;
use Symfony\Contracts\EventDispatcher\Event as ContractsEvent ;
/**
* The EventDispatcherInterface is the central point of Symfony's event listener system.
*
* Listeners are registered on the manager and events are dispatched through the
* manager.
*
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Jonathan Wage <jonwage@gmail.com>
* @author Roman Borschel <roman@code-factory.org>
* @author Bernhard Schussek <bschussek@gmail.com>
* @author Fabien Potencier <fabien@symfony.com>
* @author Jordi Boggiano <j.boggiano@seld.be>
* @author Jordan Alliot <jordan.alliot@gmail.com>
* @author Nicolas Grekas <p@tchwork.com>
*/
class EventDispatcher implements EventDispatcherInterface
{
private $listeners = [];
private $sorted = [];
private $optimized ;
public function __construct ()
{
if ( __CLASS__ === static::class) {
$this -> optimized = [];
}
}
/**
* {@inheritdoc}
*
* @param string|null $eventName
*/
public function dispatch ( $event /*, string $eventName = null*/ )
{
$eventName = 1 < \func_num_args () ? func_get_arg ( 1 ) : null ;
if ( \is_object ( $event )) {
$eventName = $eventName ?? \get_class ( $event );
} elseif ( \is_string ( $event ) && ( null === $eventName || $eventName instanceof ContractsEvent || $eventName instanceof Event )) {
@ trigger_error ( sprintf ( 'Calling the "%s::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.' , EventDispatcherInterface ::class), \E_USER_DEPRECATED );
$swap = $event ;
$event = $eventName ?? new Event ();
$eventName = $swap ;
} else {
throw new \TypeError ( sprintf ( 'Argument 1 passed to "%s::dispatch()" must be an object, "%s" given.' , EventDispatcherInterface ::class, \is_object ( $event ) ? \get_class ( $event ) : \gettype ( $event )));
}
if ( null !== $this -> optimized && null !== $eventName ) {
$listeners = $this -> optimized [ $eventName ] ?? (empty( $this -> listeners [ $eventName ]) ? [] : $this -> optimizeListeners ( $eventName ));
} else {
$listeners = $this -> getListeners ( $eventName );
}
if ( $listeners ) {
$this -> callListeners ( $listeners , $eventName , $event );
}
return $event ;
}
/**
* {@inheritdoc}
*/
public function getListeners ( $eventName = null )
{
if ( null !== $eventName ) {
if (empty( $this -> listeners [ $eventName ])) {
return [];
}
if (!isset( $this -> sorted [ $eventName ])) {
$this -> sortListeners ( $eventName );
}
return $this -> sorted [ $eventName ];
}
foreach ( $this -> listeners as $eventName => $eventListeners ) {
if (!isset( $this -> sorted [ $eventName ])) {
$this -> sortListeners ( $eventName );
}
}
return array_filter ( $this -> sorted );
}
/**
* {@inheritdoc}
*/
public function getListenerPriority ( $eventName , $listener )
{
if (empty( $this -> listeners [ $eventName ])) {
return null ;
}
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 && 2 >= \count ( $v )) {
$v [ 0 ] = $v [ 0 ]();
$v [ 1 ] = $v [ 1 ] ?? '__invoke' ;
}
if ( $v === $listener ) {
return $priority ;
}
}
}
return null ;
}
/**
* {@inheritdoc}
*/
public function hasListeners ( $eventName = null )
{
if ( null !== $eventName ) {
return !empty( $this -> listeners [ $eventName ]);
}
foreach ( $this -> listeners as $eventListeners ) {
if ( $eventListeners ) {
return true ;
}
}
return false ;
}
/**
* {@inheritdoc}
*/
public function addListener ( $eventName , $listener , $priority = 0 )
{
$this -> listeners [ $eventName ][ $priority ][] = $listener ;
unset( $this -> sorted [ $eventName ], $this -> optimized [ $eventName ]);
}
/**
* {@inheritdoc}
*/
public function removeListener ( $eventName , $listener )
{
if (empty( $this -> listeners [ $eventName ])) {
return;
}
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 && 2 >= \count ( $v )) {
$v [ 0 ] = $v [ 0 ]();
$v [ 1 ] = $v [ 1 ] ?? '__invoke' ;
}
if ( $v === $listener ) {
unset( $listeners [ $k ], $this -> sorted [ $eventName ], $this -> optimized [ $eventName ]);
}
}
if (! $listeners ) {
unset( $this -> listeners [ $eventName ][ $priority ]);
}
}
}
/**
* {@inheritdoc}
*/
public function addSubscriber ( EventSubscriberInterface $subscriber )
{
foreach ( $subscriber -> getSubscribedEvents () as $eventName => $params ) {
if ( \is_string ( $params )) {
$this -> addListener ( $eventName , [ $subscriber , $params ]);
} elseif ( \is_string ( $params [ 0 ])) {
$this -> addListener ( $eventName , [ $subscriber , $params [ 0 ]], $params [ 1 ] ?? 0 );
} else {
foreach ( $params as $listener ) {
$this -> addListener ( $eventName , [ $subscriber , $listener [ 0 ]], $listener [ 1 ] ?? 0 );
}
}
}
}
/**
* {@inheritdoc}
*/
public function removeSubscriber ( EventSubscriberInterface $subscriber )
{
foreach ( $subscriber -> getSubscribedEvents () as $eventName => $params ) {
if ( \is_array ( $params ) && \is_array ( $params [ 0 ])) {
foreach ( $params as $listener ) {
$this -> removeListener ( $eventName , [ $subscriber , $listener [ 0 ]]);
}
} else {
$this -> removeListener ( $eventName , [ $subscriber , \is_string ( $params ) ? $params : $params [ 0 ]]);
}
}
}
/**
* Triggers the listeners of an event.
*
* This method can be overridden to add functionality that is executed
* for each listener.
*
* @param callable[] $listeners The event listeners
* @param string $eventName The name of the event to dispatch
* @param object $event The event object to pass to the event handlers/listeners
*/
protected function callListeners ( iterable $listeners , string $eventName , $event )
{
if ( $event instanceof Event ) {
$this -> doDispatch ( $listeners , $eventName , $event );
return;
}
$stoppable = $event instanceof ContractsEvent || $event instanceof StoppableEventInterface ;
foreach ( $listeners as $listener ) {
if ( $stoppable && $event -> isPropagationStopped ()) {
break;
}
// @deprecated: the ternary operator is part of a BC layer and should be removed in 5.0
$listener ( $listener instanceof WrappedListener ? new LegacyEventProxy ( $event ) : $event , $eventName , $this );
}
}
/**
* @deprecated since Symfony 4.3, use callListeners() instead
*/
protected function doDispatch ( $listeners , $eventName , Event $event )
{
foreach ( $listeners as $listener ) {
if ( $event -> isPropagationStopped ()) {
break;
}
$listener ( $event , $eventName , $this );
}
}
/**
* Sorts the internal list of listeners for the given event by priority.
*/
private function sortListeners ( string $eventName )
{
krsort ( $this -> listeners [ $eventName ]);
$this -> sorted [ $eventName ] = [];
foreach ( $this -> listeners [ $eventName ] as & $listeners ) {
foreach ( $listeners as $k => & $listener ) {
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 ;
}
}
}
/**
* Optimizes the internal list of listeners for the given event by priority.
*/
private function optimizeListeners ( string $eventName ): array
{
krsort ( $this -> listeners [ $eventName ]);
$this -> optimized [ $eventName ] = [];
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 && 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 );
};
} else {
$closure = $listener instanceof \Closure || $listener instanceof WrappedListener ? $listener : \Closure :: fromCallable ( $listener );
}
}
}
return $this -> optimized [ $eventName ];
}
}