{"record":{"id":"fd4b6277fb4803b8","repo":"sebastianbergmann/phpunit","slug":"comparison-method-s-s-does-not-declare-bool-r","errorCode":null,"errorMessage":"Comparison method %s::%s() does not declare bool return type.","messagePattern":"Comparison method (.+?)::(.+?)\\(\\) does not declare bool return type\\.","errorType":"exception","errorClass":"ComparisonMethodDoesNotDeclareBoolReturnTypeException","httpStatus":null,"severity":"error","filePath":"src/Framework/Constraint/Object/ObjectEquals.php","lineNumber":84,"sourceCode":"    protected function matches(mixed $other): bool\n    {\n        if (!is_object($other)) {\n            throw new ActualValueIsNotAnObjectException;\n        }\n\n        $object = new ReflectionObject($other);\n\n        if (!$object->hasMethod($this->method)) {\n            throw new ComparisonMethodDoesNotExistException(\n                $other::class,\n                $this->method,\n            );\n        }\n\n        $method = $object->getMethod($this->method);\n\n        if (!$method->hasReturnType()) {\n            throw new ComparisonMethodDoesNotDeclareBoolReturnTypeException(\n                $other::class,\n                $this->method,\n            );\n        }\n\n        $returnType = $method->getReturnType();\n\n        if (!$returnType instanceof ReflectionNamedType) {\n            throw new ComparisonMethodDoesNotDeclareBoolReturnTypeException(\n                $other::class,\n                $this->method,\n            );\n        }\n\n        if ($returnType->allowsNull()) {\n            throw new ComparisonMethodDoesNotDeclareBoolReturnTypeException(\n                $other::class,\n                $this->method,","sourceCodeStart":66,"sourceCodeEnd":102,"githubUrl":"https://github.com/sebastianbergmann/phpunit/blob/f123cdb2a2d49f15025794166cfed8bda8627dd2/src/Framework/Constraint/Object/ObjectEquals.php#L66-L102","documentation":"For assertObjectEquals(), PHPUnit requires the comparison method on the actual object to declare an explicit bool return type, because the constraint's return value drives pass/fail. This variant is thrown when ReflectionMethod::hasReturnType() is false, i.e. the method exists but has no return type at all.","triggerScenarios":"assertObjectEquals($expected, $actual) where the actual class's equals() (or custom-named method) is declared without a return type, e.g. `public function equals($other)` or `public function equals(self $other) { ... }` with no `: bool`.","commonSituations":"Legacy pre-PHP-7.4 codebases where return types were not used; equals() methods ported from Java that return bool but never declared the type; generated code or DTO builders that omit return types; teams adding assertObjectEquals() to an existing untyped codebase.","solutions":["Add the bool return type to the comparison method: `public function equals(self $other): bool`","If you cannot change the class, use assertEquals() instead of assertObjectEquals()"],"exampleFix":"// before\nclass Email\n{\n    public function equals(self $other) // no return type\n    {\n        return $this->value === $other->value;\n    }\n}\n\n// after\nclass Email\n{\n    public function equals(self $other): bool\n    {\n        return $this->value === $other->value;\n    }\n}","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"function comparisonMethodHasReturnType(object $actual, string $method = 'equals'): bool\n{\n    $m = (new ReflectionObject($actual))->getMethod($method);\n    return $m->hasReturnType()\n        && $m->getReturnType() instanceof \\ReflectionNamedType\n        && $m->getReturnType()->getName() === 'bool'\n        && !$m->getReturnType()->allowsNull();\n}\n\nif (!comparisonMethodHasReturnType($actual)) {\n    $this->markTestIncomplete('equals() must declare `: bool`');\n}","tryCatchPattern":null,"preventionTips":["Use the exact template `public function equals(self $other): bool` for every comparator intended for assertObjectEquals()","Enforce native return types project-wide (PHP 7.4+ / PS-12 style) so untyped methods cannot survive"],"tags":["php","phpunit","assertobjectequals","return-type","equals-method"],"backgroundTag":"equals-method-contract-violation","analyzedSha":"f123cdb2a2d49f15025794166cfed8bda8627dd2","analyzedAt":"2026-08-23T01:20:58.058Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}