Check if callable can receive class as parameter in php

痴心易碎 提交于 2019-12-08 10:58:17

问题


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 __invoke or static calls defined as "Foo::bar", but they wouldn't be too hard to add if necessary. 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




回答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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!