{"record":{"id":"1d11bdccf1fb4187","repo":"sebastianbergmann/phpunit","slug":"event-s-does-not-implement-event-interface","errorCode":null,"errorMessage":"Event \"%s\" does not implement Event interface","messagePattern":"Event \"(.+?)\" does not implement Event interface","errorType":"exception","errorClass":"InvalidEventException","httpStatus":null,"severity":"error","filePath":"src/Event/TypeMap.php","lineNumber":148,"sourceCode":"        if (!in_array(Subscriber::class, class_implements($subscriberInterface), true)) {\n            throw new InvalidSubscriberException(\n                sprintf(\n                    'Subscriber \"%s\" does not extend Subscriber interface',\n                    $subscriberInterface,\n                ),\n            );\n        }\n    }\n\n    /**\n     * @param class-string $eventClass\n     *\n     * @throws InvalidEventException\n     */\n    private function ensureEventClassImplementsEventInterface(string $eventClass): void\n    {\n        if (!in_array(Event::class, class_implements($eventClass), true)) {\n            throw new InvalidEventException(\n                sprintf(\n                    'Event \"%s\" does not implement Event interface',\n                    $eventClass,\n                ),\n            );\n        }\n    }\n\n    /**\n     * @param class-string $subscriberInterface\n     *\n     * @throws SubscriberTypeAlreadyRegisteredException\n     */\n    private function ensureSubscriberWasNotAlreadyRegistered(string $subscriberInterface): void\n    {\n        if (array_key_exists($subscriberInterface, $this->mapping)) {\n            throw new SubscriberTypeAlreadyRegisteredException(\n                sprintf(","sourceCodeStart":130,"sourceCodeEnd":166,"githubUrl":"https://github.com/sebastianbergmann/phpunit/blob/f123cdb2a2d49f15025794166cfed8bda8627dd2/src/Event/TypeMap.php#L130-L166","documentation":"An event class passed to TypeMap::addMapping() must implement the marker interface PHPUnit\\Event\\Event; InvalidEventException is thrown when class_implements($eventClass) does not contain it. This keeps the dispatcher's dispatch(Event $event) type guarantee meaningful for custom events registered in the map.","triggerScenarios":"Mapping a plain DTO or value class that has no 'implements Event'; mapping an enum or an interface instead of a concrete class; an event class whose parent implements a custom base event that itself does not extend PHPUnit\\Event\\Event.","commonSituations":"Bringing existing domain events into PHPUnit's emitter without adopting the Event contract; refactoring an event hierarchy and dropping the implements clause; wrapping third-party event objects instead of composing them.","solutions":["Add 'implements PHPUnit\\Event\\Event' to the event class.","If the class wraps another library's event, make the wrapper implement Event and expose the wrapped object via a getter.","Verify with in_array(Event::class, class_implements($eventClass), true) when in doubt."],"exampleFix":"// before\nfinal class OrderPlaced { public function __construct(public string $id) {} }\n$typeMap->addMapping(OrderPlacedSubscriber::class, OrderPlaced::class); // throws\n\n// after\nuse PHPUnit\\Event\\Event;\n\nfinal class OrderPlaced implements Event { public function __construct(public string $id) {} }\n$typeMap->addMapping(OrderPlacedSubscriber::class, OrderPlaced::class);","handlingStrategy":"validation","validationCode":"if (!in_array(PHPUnit\\Event\\Event::class, class_implements($eventClass), true)) {\n    throw new InvalidArgumentException($eventClass . ' must implement PHPUnit\\\\Event\\\\Event');\n}\n\n$typeMap->addMapping($subscriberInterface, $eventClass);","typeGuard":"function implementsEventContract(string $class): bool\n{\n    return in_array(PHPUnit\\Event\\Event::class, class_implements($class), true);\n}","tryCatchPattern":null,"preventionTips":["Add 'implements Event' to every custom event class when it is created.","When wrapping foreign event objects, make the wrapper implement Event rather than mapping the foreign class.","Re-run mapping bootstrap tests after event-hierarchy refactors."],"tags":["phpunit","type-map","event","interface-contract","php"],"backgroundTag":"interface-contract-violation","analyzedSha":"f123cdb2a2d49f15025794166cfed8bda8627dd2","analyzedAt":"2026-08-23T01:20:58.058Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}