问题
I have a callable $f
and I would like to know if it can receive an instance of a certain class Foo
as input.
At the moment I'm doing something like
try {
$f($foo);
} catch (\TypeError $e) {
throw new \InvalidArgumentException('The provided function can not evaluate inputs of this type');
}
Is there a way to check this WITHOUT actually invoking the callable? Maybe with reflection or some other dark magic?
回答1:
If you want to be able to reflect any kind of callable, you'll need to wrap up the logic in a small function. Depending on whether you've got an array, a function name or an anonymous function, you need to create either a ReflectionFunction or ReflectionMethod. Fortunately, these both extend ReflectionFunctionAbstract, so we can type-hint the return value.
function reflectCallable($arg): ReflectionFunctionAbstract {
if (is_array($arg)) {
$ref = new ReflectionMethod(...$arg);
} elseif (is_callable($arg)) {
$ref = new ReflectionFunction($arg);
}
return $ref;
}
This will return you the appropriate object for your callable value, which you can then use to fetch the parameters and act accordingly:
function definedFunc(Foo $foo) {}
$callable = function(Foo $foo) {};
class Bar { public function baz(Foo $foo) {} }
foreach (['definedFunc', $callable, ['Bar', 'baz']] as $callable) {
$reflected = reflectCallable($callable);
if ((string) $reflected->getParameters()[0]->getType() === 'Foo') {
echo 'Callable takes Foo', PHP_EOL;
}
}
See https://3v4l.org/c5vmM
Note that this doesn't do any error handling - you'll probably get warnings/notices if the callable doesn't take any parameters or the first parameter doesn't have a type. It also requires PHP 7+, but hopefully that's not an issue.
It doesn't currently support objects that implement I've just found something very similar in the source of Twig, which does a more thorough job: https://github.com/twigphp/Twig/blob/v2.8.0/src/Node/Expression/CallExpression.php#L280__invoke
or static calls defined as "Foo::bar"
, but they wouldn't be too hard to add if necessary.
回答2:
You can with ReflectionParameter::getType:
$f = function(Foo $foo) {};
$reflectionFunc = new ReflectionFunction($f);
$reflectionParams = $reflectionFunc->getParameters();
$reflectionType1 = $reflectionParams[0]->getType();
echo $reflectionType1;
output:
Foo
来源:https://stackoverflow.com/questions/52200682/check-if-callable-can-receive-class-as-parameter-in-php