Вход Регистрация
Файл: vendor/symfony/event-dispatcher/EventDispatcher.php
Строк: 370
<?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 SymfonyComponentEventDispatcher;

use 
PsrEventDispatcherStoppableEventInterface;
use 
SymfonyComponentEventDispatcherDebugWrappedListener;

/**
 * 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 array 
$listeners = [];
    private array 
$sorted = [];
    private array 
$optimized;

    public function 
__construct()
    {
        if (
__CLASS__ === static::class) {
            
$this->optimized = [];
        }
    }

    public function 
dispatch(object $event, ?string $eventName null): object
    
{
        
$eventName ??= $event::class;

        if (isset(
$this->optimized)) {
            
$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;
    }

    public function 
getListeners(?string $eventName null): array
    {
        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);
    }

    public function 
getListenerPriority(string $eventName, callable|array $listener): ?int
    
{
        if (empty(
$this->listeners[$eventName])) {
            return 
null;
        }

        if (
is_array($listener) && isset($listener[0]) && $listener[0] instanceof Closure && >= count($listener)) {
            
$listener[0] = $listener[0]();
            
$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 && >= count($v)) {
                    
$v[0] = $v[0]();
                    
$v[1] ??= '__invoke';
                }
                if (
$v === $listener || ($listener instanceof Closure && $v == $listener)) {
                    return 
$priority;
                }
            }
        }

        return 
null;
    }

    public function 
hasListeners(?string $eventName null): bool
    
{
        if (
null !== $eventName) {
            return !empty(
$this->listeners[$eventName]);
        }

        foreach (
$this->listeners as $eventListeners) {
            if (
$eventListeners) {
                return 
true;
            }
        }

        return 
false;
    }

    
/**
     * @return void
     */
    
public function addListener(string $eventName, callable|array $listenerint $priority 0)
    {
        
$this->listeners[$eventName][$priority][] = $listener;
        unset(
$this->sorted[$eventName], $this->optimized[$eventName]);
    }

    
/**
     * @return void
     */
    
public function removeListener(string $eventName, callable|array $listener)
    {
        if (empty(
$this->listeners[$eventName])) {
            return;
        }

        if (
is_array($listener) && isset($listener[0]) && $listener[0] instanceof Closure && >= count($listener)) {
            
$listener[0] = $listener[0]();
            
$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 && >= count($v)) {
                    
$v[0] = $v[0]();
                    
$v[1] ??= '__invoke';
                }
                if (
$v === $listener || ($listener instanceof Closure && $v == $listener)) {
                    unset(
$listeners[$k], $this->sorted[$eventName], $this->optimized[$eventName]);
                }
            }

            if (!
$listeners) {
                unset(
$this->listeners[$eventName][$priority]);
            }
        }
    }

    
/**
     * @return void
     */
    
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);
                }
            }
        }
    }

    
/**
     * @return void
     */
    
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, [$subscriberis_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
     *
     * @return void
     */
    
protected function callListeners(iterable $listenersstring $eventNameobject $event)
    {
        
$stoppable $event instanceof StoppableEventInterface;

        foreach (
$listeners as $listener) {
            if (
$stoppable && $event->isPropagationStopped()) {
                break;
            }
            
$listener($event$eventName$this);
        }
    }

    
/**
     * Sorts the internal list of listeners for the given event by priority.
     */
    
private function sortListeners(string $eventName): void
    
{
        
krsort($this->listeners[$eventName]);
        
$this->sorted[$eventName] = [];

        foreach (
$this->listeners[$eventName] as &$listeners) {
            foreach (
$listeners as &$listener) {
                if (
is_array($listener) && isset($listener[0]) && $listener[0] instanceof Closure && >= count($listener)) {
                    
$listener[0] = $listener[0]();
                    
$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 && >= count($listener)) {
                    
$closure = static function (...$args) use (&$listener, &$closure) {
                        if (
$listener[0] instanceof Closure) {
                            
$listener[0] = $listener[0]();
                            
$listener[1] ??= '__invoke';
                        }
                        (
$closure $listener(...))(...$args);
                    };
                } else {
                    
$closure $listener instanceof WrappedListener $listener $listener(...);
                }
            }
        }

        return 
$this->optimized[$eventName];
    }
}
Онлайн: 0
Реклама