sebastianbergmann/phpunit · error · ComparisonMethodDoesNotDeclareParameterTypeException

Parameter of comparison method %s::%s() does not have a decl

Error message

Parameter of comparison method %s::%s() does not have a declared type.

What it means

The single parameter of the comparison method used by assertObjectEquals() must have a declared type, so PHPUnit can verify the expected object is acceptable before invoking it. This variant is thrown when ReflectionParameter::hasType() is false, i.e. the parameter is untyped.

Source

Thrown at src/Framework/Constraint/Object/ObjectEquals.php:124

        if ($returnType->getName() !== 'bool') {
            throw new ComparisonMethodDoesNotDeclareBoolReturnTypeException(
                $other::class,
                $this->method,
            );
        }

        if ($method->getNumberOfParameters() !== 1 || $method->getNumberOfRequiredParameters() !== 1) {
            throw new ComparisonMethodDoesNotDeclareExactlyOneParameterException(
                $other::class,
                $this->method,
            );
        }

        assert(count($method->getParameters()) > 0);
        $parameter = $method->getParameters()[0];

        if (!$parameter->hasType()) {
            throw new ComparisonMethodDoesNotDeclareParameterTypeException(
                $other::class,
                $this->method,
            );
        }

        $type = $parameter->getType();

        if (!$type instanceof ReflectionNamedType) {
            throw new ComparisonMethodDoesNotDeclareParameterTypeException(
                $other::class,
                $this->method,
            );
        }

        $typeName = $type->getName();

        if ($typeName === 'self') {
            // @codeCoverageIgnoreStart

View on GitHub (pinned to f123cdb2a2)

Solutions

  1. Add a parameter type, ideally `self` or the concrete class: `public function equals(self $other): bool`
  2. If the method genuinely accepts any object, declare it explicitly: `public function equals(mixed $other): bool` — 'mixed' is a declared type and passes this check
  3. Note: with a wide type you may then hit the instanceof acceptance check; prefer self or the specific value class

Example fix

// before
class Sku
{
    public function equals($other): bool
    {
        return $other instanceof self && $this->code === $other->code;
    }
}

// after
class Sku
{
    public function equals(self $other): bool
    {
        return $this->code === $other->code;
    }
}
Defensive patterns

Strategy: type-guard

Type guard

function comparisonMethodParameterIsTyped(object $actual, string $method = 'equals'): bool
{
    $params = (new ReflectionObject($actual))->getMethod($method)->getParameters();
    return isset($params[0]) && $params[0]->hasType();
}

Prevention

When it happens

Trigger: equals() declared as `public function equals($other): bool` — the parameter has no type declaration, often because it was written to accept anything (Java `Object $other` style) or predates PHP 7 type hints.

Common situations: Legacy equals(mixed $other) implementations (here 'mixed' as an explicit declared type would be fine, absence of any hint is not); code style guides that banned parameter types; docblock-typed but not natively typed parameters.

Related errors


AI-assisted analysis of sebastianbergmann/phpunit@f123cdb2a2 (2026-08-23). Data as JSON: /api/errors/4e970cbe3147b2d4. Report an issue: GitHub.