vendor/symfony/event-dispatcher/Debug/WrappedListener.php line 118

Open in your IDE?
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\EventDispatcher\Debug;
  11. use Psr\EventDispatcher\StoppableEventInterface;
  12. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  13. use Symfony\Component\Stopwatch\Stopwatch;
  14. use Symfony\Component\VarDumper\Caster\ClassStub;
  15. /**
  16. * @author Fabien Potencier <fabien@symfony.com>
  17. */
  18. final class WrappedListener
  19. {
  20. private $listener;
  21. private $optimizedListener;
  22. private $name;
  23. private $called;
  24. private $stoppedPropagation;
  25. private $stopwatch;
  26. private $dispatcher;
  27. private $pretty;
  28. private $stub;
  29. private $priority;
  30. private static $hasClassStub;
  31. public function __construct($listener, ?string $name, Stopwatch $stopwatch, ?EventDispatcherInterface $dispatcher = null)
  32. {
  33. $this->listener = $listener;
  34. $this->optimizedListener = $listener instanceof \Closure ? $listener : (\is_callable($listener) ? \Closure::fromCallable($listener) : null);
  35. $this->stopwatch = $stopwatch;
  36. $this->dispatcher = $dispatcher;
  37. $this->called = false;
  38. $this->stoppedPropagation = false;
  39. if (\is_array($listener)) {
  40. $this->name = \is_object($listener[0]) ? get_debug_type($listener[0]) : $listener[0];
  41. $this->pretty = $this->name.'::'.$listener[1];
  42. } elseif ($listener instanceof \Closure) {
  43. $r = new \ReflectionFunction($listener);
  44. if (str_contains($r->name, '{closure')) {
  45. $this->pretty = $this->name = 'closure';
  46. } elseif ($class = \PHP_VERSION_ID >= 80111 ? $r->getClosureCalledClass() : $r->getClosureScopeClass()) {
  47. $this->name = $class->name;
  48. $this->pretty = $this->name.'::'.$r->name;
  49. } else {
  50. $this->pretty = $this->name = $r->name;
  51. }
  52. } elseif (\is_string($listener)) {
  53. $this->pretty = $this->name = $listener;
  54. } else {
  55. $this->name = get_debug_type($listener);
  56. $this->pretty = $this->name.'::__invoke';
  57. }
  58. if (null !== $name) {
  59. $this->name = $name;
  60. }
  61. if (null === self::$hasClassStub) {
  62. self::$hasClassStub = class_exists(ClassStub::class);
  63. }
  64. }
  65. public function getWrappedListener()
  66. {
  67. return $this->listener;
  68. }
  69. public function wasCalled(): bool
  70. {
  71. return $this->called;
  72. }
  73. public function stoppedPropagation(): bool
  74. {
  75. return $this->stoppedPropagation;
  76. }
  77. public function getPretty(): string
  78. {
  79. return $this->pretty;
  80. }
  81. public function getInfo(string $eventName): array
  82. {
  83. if (null === $this->stub) {
  84. $this->stub = self::$hasClassStub ? new ClassStub($this->pretty.'()', $this->listener) : $this->pretty.'()';
  85. }
  86. return [
  87. 'event' => $eventName,
  88. 'priority' => null !== $this->priority ? $this->priority : (null !== $this->dispatcher ? $this->dispatcher->getListenerPriority($eventName, $this->listener) : null),
  89. 'pretty' => $this->pretty,
  90. 'stub' => $this->stub,
  91. ];
  92. }
  93. public function __invoke(object $event, string $eventName, EventDispatcherInterface $dispatcher): void
  94. {
  95. $dispatcher = $this->dispatcher ?: $dispatcher;
  96. $this->called = true;
  97. $this->priority = $dispatcher->getListenerPriority($eventName, $this->listener);
  98. $e = $this->stopwatch->start($this->name, 'event_listener');
  99. try {
  100. ($this->optimizedListener ?? $this->listener)($event, $eventName, $dispatcher);
  101. } finally {
  102. if ($e->isStarted()) {
  103. $e->stop();
  104. }
  105. }
  106. if ($event instanceof StoppableEventInterface && $event->isPropagationStopped()) {
  107. $this->stoppedPropagation = true;
  108. }
  109. }
  110. }