Reputation: 20469
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
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