sebastianbergmann/phpunit · error · ComparisonMethodDoesNotDeclareBoolReturnTypeException
Comparison method %s::%s() does not declare bool return type
Error message
Comparison method %s::%s() does not declare bool return type.
What it means
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.
Source
Thrown at src/Framework/Constraint/Object/ObjectEquals.php:84
protected function matches(mixed $other): bool
{
if (!is_object($other)) {
throw new ActualValueIsNotAnObjectException;
}
$object = new ReflectionObject($other);
if (!$object->hasMethod($this->method)) {
throw new ComparisonMethodDoesNotExistException(
$other::class,
$this->method,
);
}
$method = $object->getMethod($this->method);
if (!$method->hasReturnType()) {
throw new ComparisonMethodDoesNotDeclareBoolReturnTypeException(
$other::class,
$this->method,
);
}
$returnType = $method->getReturnType();
if (!$returnType instanceof ReflectionNamedType) {
throw new ComparisonMethodDoesNotDeclareBoolReturnTypeException(
$other::class,
$this->method,
);
}
if ($returnType->allowsNull()) {
throw new ComparisonMethodDoesNotDeclareBoolReturnTypeException(
$other::class,
$this->method,View on GitHub (pinned to f123cdb2a2)
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()
Example fix
// before
class Email
{
public function equals(self $other) // no return type
{
return $this->value === $other->value;
}
}
// after
class Email
{
public function equals(self $other): bool
{
return $this->value === $other->value;
}
} Defensive patterns
Strategy: type-guard
Type guard
function comparisonMethodHasReturnType(object $actual, string $method = 'equals'): bool
{
$m = (new ReflectionObject($actual))->getMethod($method);
return $m->hasReturnType()
&& $m->getReturnType() instanceof \ReflectionNamedType
&& $m->getReturnType()->getName() === 'bool'
&& !$m->getReturnType()->allowsNull();
}
if (!comparisonMethodHasReturnType($actual)) {
$this->markTestIncomplete('equals() must declare `: bool`');
} Prevention
- 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
When it happens
Trigger: 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`.
Common situations: 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.
Related errors
- Comparison method %s::%s() does not exist.
- Comparison method %s::%s() does not declare exactly one para
- Parameter of comparison method %s::%s() does not have a decl
- %s is not an accepted argument type for comparison method %s
- Subscriber "%s" does not implement any known interface - did
AI-assisted analysis of sebastianbergmann/phpunit@f123cdb2a2 (2026-08-23).
Data as JSON: /api/errors/fd4b6277fb4803b8.
Report an issue: GitHub.