* * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\EventDispatcher\Debug; use Psr\EventDispatcher\StoppableEventInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Stopwatch\Stopwatch; use Symfony\Component\VarDumper\Caster\ClassStub; /** * @author Fabien Potencier */ final class WrappedListener { private string|array|object $listener; private ?\Closure $optimizedListener; private string $name; private bool $called = false; private bool $stoppedPropagation = false; private Stopwatch $stopwatch; private ?EventDispatcherInterface $dispatcher; private string $pretty; private string $callableRef; private ClassStub|string $stub; private ?int $priority = null; private static bool $hasClassStub; public function __construct(callable|array $listener, ?string $name, Stopwatch $stopwatch, EventDispatcherInterface $dispatcher = null, int $priority = null) { $this->listener = $listener; $this->optimizedListener = $listener instanceof \Closure ? $listener : (\is_callable($listener) ? $listener(...) : null); $this->stopwatch = $stopwatch; $this->dispatcher = $dispatcher; $this->priority = $priority; if (\is_array($listener)) { [$this->name, $this->callableRef] = $this->parseListener($listener); $this->pretty = $this->name.'::'.$listener[1]; $this->callableRef .= '::'.$listener[1]; } elseif ($listener instanceof \Closure) { $r = new \ReflectionFunction($listener); if (str_contains($r->name, '{closure}')) { $this->pretty = $this->name = 'closure'; } elseif ($class = \PHP_VERSION_ID >= 80111 ? $r->getClosureCalledClass() : $r->getClosureScopeClass()) { $this->name = $class->name; $this->pretty = $this->name.'::'.$r->name; } else { $this->pretty = $this->name = $r->name; } } elseif (\is_string($listener)) { $this->pretty = $this->name = $listener; } else { $this->name = get_debug_type($listener); $this->pretty = $this->name.'::__invoke'; $this->callableRef = $listener::class.'::__invoke'; } if (null !== $name) { $this->name = $name; } self::$hasClassStub ??= class_exists(ClassStub::class); } public function getWrappedListener(): callable|array { return $this->listener; } public function wasCalled(): bool { return $this->called; } public function stoppedPropagation(): bool { return $this->stoppedPropagation; } public function getPretty(): string { return $this->pretty; } public function getInfo(string $eventName): array { $this->stub ??= self::$hasClassStub ? new ClassStub($this->pretty.'()', $this->callableRef ?? $this->listener) : $this->pretty.'()'; return [ 'event' => $eventName, 'priority' => $this->priority ??= $this->dispatcher?->getListenerPriority($eventName, $this->listener), 'pretty' => $this->pretty, 'stub' => $this->stub, ]; } public function __invoke(object $event, string $eventName, EventDispatcherInterface $dispatcher): void { $dispatcher = $this->dispatcher ?: $dispatcher; $this->called = true; $this->priority ??= $dispatcher->getListenerPriority($eventName, $this->listener); $e = $this->stopwatch->start($this->name, 'event_listener'); ($this->optimizedListener ?? $this->listener)($event, $eventName, $dispatcher); if ($e->isStarted()) { $e->stop(); } if ($event instanceof StoppableEventInterface && $event->isPropagationStopped()) { $this->stoppedPropagation = true; } } private function parseListener(array $listener): array { if ($listener[0] instanceof \Closure) { foreach ((new \ReflectionFunction($listener[0]))->getAttributes(\Closure::class) as $attribute) { if ($name = $attribute->getArguments()['name'] ?? false) { return [$name, $attribute->getArguments()['class'] ?? $name]; } } } if (\is_object($listener[0])) { return [get_debug_type($listener[0]), $listener[0]::class]; } return [$listener[0], $listener[0]]; } } __halt_compiler();----SIGNATURE:----WPiS6s+GykJFlrwaW2zwyck6lCb4ZtVRpgQ4Iv+/4jZMM3mF4L8e4DEjRMkgPXqr3VqwEr0k3P7oWXBmOI3Bk2KLemE+0phFPN5IlbDV/jlHQooS8Bni+7aND5TXTdomt8QaERAOO+hANGEmGkDwOZxvHHl29psydxYpjcfpxi98pNL71QyceTpZR1rgmnXhPF+dVHvianuZqi9/WiISr/HOOanVp8TsWLTX10HzVKnqyw2gtMwxQtTDx5izRND0fupP5jPQlJm4ZzremwsJYRPUd9MQcVFgvhvb6l1l0yGOmPc80fYZVzR4y+pjnNe212wcJD1AtxoHDg2AehCgIHenPdVptrsJ2VcoZ440AqeBu6fqPY7RPrz9R4iB5WWhlN5LqzCrCIH1V0M9lQFFzSMeHtTUugQZsvBV5d27u3K110dTfp8fyQhs/4Y1SicAkaZGKh9zhEu1eAJk1CIYRuzpNi0hLvmHGFgRVkBESRSwLO+A7YxFb0p7PvC65K8b5hFe31Eo6+3UQIOEHT+O/d3psV6pHeHUbOTZdQJm7d+Mq5Ev3mdvt2XMThXuUus4gErcmGB1NeYBeWFFb40AYeygnYHNsEhbkVzWwnQjzRFJWJD8/9H2YpLp6bDlD+9jvgc8zL2gsEuD8nVM4ccjV74/QYLfCYbNTbOB4IH9Tq8=----ATTACHMENT:----MjUzMDkwNDAxNzI1NzU1NCA2NTM3OTIwODQwMTc1MTMxIDUyNjc3MzA2NjQ3NDU2Nw==