sebastianbergmann/phpunit · error · PropertyCannotBeDoubledException

Trying to double property "%s" of class "%s" with doubleProp

Error message

Trying to double property "%s" of class "%s" with doubleProperties(), but it does not declare a type

What it means

Thrown by TestDoubleBuilder::doubleProperties() when the target property declares no type. Doubling works by redeclaring the property with generated hooks, and a hooked property in PHP must have a declared type, so PHPUnit rejects untyped properties via ReflectionProperty::hasType().

Source

Thrown at src/Framework/MockObject/TestDoubleBuilder.php:147

            if (!$property->isPublic()) {
                throw new PropertyCannotBeDoubledException($this->type, $propertyName, 'it is not public');
            }

            if ($property->isStatic()) {
                throw new PropertyCannotBeDoubledException($this->type, $propertyName, 'it is static');
            }

            if ($property->isReadOnly()) {
                throw new PropertyCannotBeDoubledException($this->type, $propertyName, 'it is readonly');
            }

            if ($property->isFinal()) {
                throw new PropertyCannotBeDoubledException($this->type, $propertyName, 'it is final');
            }

            if (!$property->hasType()) {
                throw new PropertyCannotBeDoubledException($this->type, $propertyName, 'it does not declare a type');
            }
        }

        $this->doubledProperties = array_merge($this->doubledProperties, $properties);

        return $this;
    }

    /**
     * Specifies the arguments for the constructor.
     *
     * @param array<mixed> $arguments
     *
     * @return $this
     */
    public function setConstructorArgs(array $arguments): static
    {
        $this->constructorArgs = $arguments;

View on GitHub (pinned to f123cdb2a2)

Solutions

  1. Add a native type declaration to the property in the production class, then keep it in doubleProperties()
  2. Remove the untyped property from the doubling list
  3. If the type cannot be added, double a method that returns the value instead of the property

Example fix

// before
class Settings {
    public $cache; // no type -> PropertyCannotBeDoubledException
}

// after
class Settings {
    public ?array $cache = null; // typed, now doublable
}
Defensive patterns

Strategy: validation

Validate before calling

$property = new ReflectionProperty(Settings::class, 'cache');
if (!$property->hasType()) {
    // add a native type to Settings::$cache before doubling it
}

Type guard

function isTypedProperty(string $class, string $property): bool
{
    return (new ReflectionClass($class))
        ->getProperty($property)
        ->hasType();
}

Prevention

When it happens

Trigger: Calling doubleProperties([...]) with a property that has no type declaration (e.g. 'public $cache;' or a property only documented with a docblock like @var).

Common situations: Legacy classes with untyped properties or properties typed only in docblocks; migrating old tests to the new property-doubling API.

Related errors


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