{"record":{"id":"274f0b087ddad5c2","repo":"sebastianbergmann/phpunit","slug":"interfaces-must-not-declare-the-same-method","errorCode":null,"errorMessage":"Interfaces must not declare the same method","messagePattern":"Interfaces must not declare the same method","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"src/Framework/MockObject/Generator/Generator.php","lineNumber":162,"sourceCode":"            throw new RuntimeException('At least two interfaces must be specified');\n        }\n\n        foreach ($interfaces as $interface) {\n            if (!interface_exists($interface)) {\n                throw new UnknownInterfaceException($interface);\n            }\n        }\n\n        sort($interfaces);\n\n        $methods = [];\n\n        foreach ($interfaces as $interface) {\n            $methods = array_merge($methods, $this->namesOfMethodsIn($interface));\n        }\n\n        if (count(array_unique($methods)) < count($methods)) {\n            throw new RuntimeException('Interfaces must not declare the same method');\n        }\n\n        $unqualifiedNames = [];\n\n        foreach ($interfaces as $interface) {\n            $parts              = explode('\\\\', $interface);\n            $unqualifiedNames[] = array_pop($parts);\n        }\n\n        sort($unqualifiedNames);\n\n        do {\n            $intersectionName = sprintf(\n                'Intersection_%s_%s',\n                implode('_', $unqualifiedNames),\n                substr(md5((string) mt_rand()), 0, 8),\n            );\n        } while (interface_exists($intersectionName, false));","sourceCodeStart":144,"sourceCodeEnd":180,"githubUrl":"https://github.com/sebastianbergmann/phpunit/blob/f123cdb2a2d49f15025794166cfed8bda8627dd2/src/Framework/MockObject/Generator/Generator.php#L144-L180","documentation":"When building an intersection test double, PHPUnit collects the method names of every listed interface and requires them to be disjoint (count(array_unique($methods)) === count($methods)). If two interfaces in the list declare a method with the same name — even with identical signatures — it refuses, because the generated combined interface cannot redeclare a method and PHP's own intersection semantics do not resolve which method wins.","triggerScenarios":"createMockForIntersectionOfInterfaces([A::class, B::class]) where both A and B declare e.g. getName(), reset(), or jsonSerialize() (common with JsonSerializable plus a custom HasToArray interface), including cases where both interfaces inherit the method from a shared parent — actually shared parents dedupe only by name; identical names from any source collide.","commonSituations":"Combining generic framework interfaces (SessionHandlerInterface, LoggerAwareInterface->setLogger, JsonSerializable::jsonSerialize) with domain interfaces that reuse the same short names; RFC-style value interfaces both declaring id(); interfaces designed before intersection doubles existed.","solutions":["Rename the colliding method in one of your own interfaces (e.g. getDisplayName() vs getName())","Drop one of the colliding interfaces from the list and mock it separately, or mock only their common subset","If both interfaces come from third parties and cannot change, write a small named interface of your own combining the needed methods and mock that instead"],"exampleFix":"// before\ninterface HasName { public function getName(): string; }\ninterface NamedEntity { public function getName(): string; }\n$mock = $this->createMockForIntersectionOfInterfaces([HasName::class, NamedEntity::class]); // collision\n\n// after\ninterface HasName { public function getName(): string; }\ninterface NamedEntity { public function getEntityName(): string; }\n$mock = $this->createMockForIntersectionOfInterfaces([HasName::class, NamedEntity::class]);","handlingStrategy":"validation","validationCode":"// Reject colliding method names up front:\n$methods = [];\nforeach ($interfaces as $iface) {\n    foreach (get_class_methods($iface) as $m) {\n        if (isset($methods[$m])) {\n            throw new InvalidArgumentException(\"Method '$m' declared by both {$methods[$m]} and $iface\");\n        }\n        $methods[$m] = $iface;\n    }\n}\n$double = $this->createMockForIntersectionOfInterfaces($interfaces);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Design small, role-specific interfaces with unique method names (avoid generic getName/reset on multiple roles)","Before combining third-party interfaces, diff their method lists with get_class_methods()"],"tags":["php","phpunit","mockbuilder","interface-intersection","method-collision"],"backgroundTag":"duplicate-method-declaration","analyzedSha":"f123cdb2a2d49f15025794166cfed8bda8627dd2","analyzedAt":"2026-08-23T01:20:58.058Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}