order[] = 'm1_before'; $result = $next($event); $this->order[] = 'm1_after'; return $result; } }; $middleware2 = new class($order) implements DispatchMiddlewareInterface { public function __construct(private array &$order) {} public function handle(object $event, callable $next): object { $this->order[] = 'm2_before'; $result = $next($event); $this->order[] = 'm2_after'; return $result; } }; $dispatcher->addMiddleware($middleware1); $dispatcher->addMiddleware($middleware2); $provider->addListener('stdClass', function() use (&$order) { $order[] = 'listener'; }); $dispatcher->dispatch(new \stdClass()); $expected = [ 'm1_before', 'm2_before', 'listener', 'm2_after', 'm1_after' ]; $this->assertEquals($expected, $order); } public function test_middleware_can_modify_event(): void { $provider = new ListenerProvider(); $dispatcher = new EventDispatcher($provider); $middleware = new class implements DispatchMiddlewareInterface { public function handle(object $event, callable $next): object { $event->modified = true; return $next($event); } }; $dispatcher->addMiddleware($middleware); $event = new \stdClass(); $event->modified = false; $dispatcher->dispatch($event); $this->assertTrue($event->modified); } public function test_telemetry_middleware_records_data(): void { $provider = new ListenerProvider(); $dispatcher = new EventDispatcher($provider); $telemetry = new TelemetryMiddleware(); $dispatcher->addMiddleware($telemetry); $provider->addListener('stdClass', function() { usleep(1000); // 1ms }); $event = new \stdClass(); $dispatcher->dispatch($event); $data = $telemetry->getData(); $this->assertArrayHasKey('stdClass', $data); $this->assertGreaterThan(0, $data['stdClass']['time']); } }