Steve
Steve

Reputation: 20469

How can i typehint a string as a method name on a class for static analysis with phpstan / phpstorm

I am currently upgrading a project to use phpstan to better catch type errors, @template and class-string have been particularly helpfull

However, I have a method on the projects router, that takes two string parameters for a controller action.

Those parameters map to a controller class name, and method, eg:

    /**
     * @param class-string<Controller> $controllerName
     * @param string $methodName
     * @return Route
     */
     public function toController(string $controllerName, string $methodName) : Route

I can tell phpstan that the first parameter $controllerName must be a class name, and a subtype of Controller. However the $methodName param is currently just an untyped string.

I would like to be able to say it must be a public method on the class $className, but cannot find anything in the docs, or google searching.

I did find key-of<Type::ARRAY_CONST> which seems close, but works on const arrays.

Does anything exist to handle this at present?

Upvotes: 0

Views: 148

Answers (1)

Alex Howansky
Alex Howansky

Reputation: 53636

If, instead of two strings, you took one callable, then you could still use the same strings on invocation (i.e., the "class name and method name in an array" variant of callable) and PHPStan would enforce the actual callability of the args in a static context:

class Controller
{
    public function bar(): void
    {
    }
}

class Caller
{
    public static function toController(callable $thing): void
    {
        call_user_func($thing);
    }
}

class Main
{
    protected function test(): void
    {
        Caller::toController(['Controller', 'bar']); // valid class and method
        Caller::toController(['Controller', 'baq']); // bad method
        Caller::toController(['NotAController', 'foo']); // bad class
    }
}

PHPStan output:

 ------ ---------------------------------------------------------------------
  Line   Main.php
 ------ ---------------------------------------------------------------------
  8      Parameter #1 $thing of static method Caller::toController() expects
         callable(): mixed, array{'Controller', 'baq'} given.
  9      Parameter #1 $thing of static method Caller::toController() expects
         callable(): mixed, array{'NotAController', 'foo'} given.
 ------ ---------------------------------------------------------------------

Upvotes: 3

Related Questions