sebastianbergmann/phpunit · error · InvalidMethodNameException

Cannot double method with invalid name "%s"

Error message

Cannot double method with invalid name "%s"

What it means

Thrown by Generator::ensureValidMethods() when a method name in the list of methods to double does not match the PHP identifier regex ^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$. PHPUnit validates every entry of the method list (e.g. onlyMethods()/addMethods()) before generating a test double class, so this always signals bad input from the caller: a typo, a name assembled from data, or a signature string pasted instead of a bare method name.

Source

Thrown at src/Framework/MockObject/Generator/Generator.php:715

            throw new UnknownTypeException($type);
        }
    }

    /**
     * @param ?list<non-empty-string> $methods
     *
     * @throws DuplicateMethodException
     * @throws InvalidMethodNameException
     */
    private function ensureValidMethods(?array $methods): void
    {
        if ($methods === null) {
            return;
        }

        foreach ($methods as $method) {
            if (preg_match('~\A[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*\z~', (string) $method) === 0) {
                throw new InvalidMethodNameException((string) $method);
            }
        }

        if ($methods !== array_unique($methods)) {
            throw new DuplicateMethodException($methods);
        }
    }

    /**
     * @throws InvalidClassNameException
     */
    private function ensureValidNameForTestDoubleClass(string $className): void
    {
        if ($className === '') {
            return;
        }

        if (preg_match('~\A[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*\z~', $className) === 0) {

View on GitHub (pinned to f123cdb2a2)

Solutions

  1. Correct the entry to the exact bare method name (no parentheses, no arguments, no $ prefix): 'doStuff' not 'doStuff()'.
  2. If names come from a dynamic source, filter them first with the same regex PHPUnit uses: preg_match('~\A[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*\z~', $name).
  3. If you meant an existing method of the mocked type, get real names from reflection instead of typing them: (new ReflectionClass(C::class))->getMethods().
  4. For a method that does not exist yet on the class, add it to the class/interface or use addMethods() with a valid identifier.

Example fix

// before
$mock = $this->getMockBuilder(Greeter::class)
    ->onlyMethods(['say-hello'])
    ->getMock();

// after
$mock = $this->getMockBuilder(Greeter::class)
    ->onlyMethods(['sayHello'])
    ->getMock();
Defensive patterns

Strategy: validation

Validate before calling

$methods = ['doStuff', 'save'];
$valid = preg_filter('~\A[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*\z~', '', $methods) ?? [];
if (count($valid) !== count($methods)) {
    throw new InvalidArgumentException('method list contains invalid names');
}

Type guard

function isPhpMethodName(string $name): bool
{
    return (bool) preg_match('~\A[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*\z~', $name);
}

Try / catch

try {
    $mock = $this->getMockBuilder(C::class)->onlyMethods($methods)->getMock();
} catch (PHPUnit\Framework\MockObject\InvalidMethodNameException $e) {
    // log which dynamic source produced the bad name and skip/fail gracefully
}

Prevention

When it happens

Trigger: Calling $this->getMockBuilder(C::class)->onlyMethods(['do-stuff']) or ->addMethods(['123abc', 'foo()', '$bar', '']) with any string that is not a valid PHP method identifier; calling Generator::testDouble()/getMock() directly with a $methods array containing such a value. Values are cast to string, so numbers pass but strings like 'method()' or ' method' fail.

Common situations: Method names built dynamically from configuration, CSV, or data providers; copy-pasting a full signature 'handleRequest($req)' instead of 'handleRequest'; kebab-case names from route names used as method names; refactored method names that no longer compile as identifiers.

Related errors


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