检查可调用是否可以在PHP中接收类作为参数

时间:2018-09-06 09:16:25

标签: php types callable

我有一个可调用的$f,我想知道它是否可以接收某个类Foo的实例作为输入。

此刻我正在做类似的事情

try {
    $f($foo);
} catch (\TypeError $e) {
    throw new \InvalidArgumentException('The provided function can not evaluate inputs of this type');
}

有没有一种方法可以在不实际调用可调用对象的情况下进行检查?也许有反射或其他一些黑魔法?

2 个答案:

答案 0 :(得分:1)

您可以使用ReflectionParameter::getType

$f = function(Foo $foo) {};

$reflectionFunc = new ReflectionFunction($f);
$reflectionParams = $reflectionFunc->getParameters();
$reflectionType1 = $reflectionParams[0]->getType();

echo $reflectionType1;

输出:

  

Foo

答案 1 :(得分:1)

如果您希望能够反映任何类型的可调用对象,则需要将逻辑包装在一个小函数中。根据是否具有数组,函数名称或匿名函数,您需要创建ReflectionFunctionReflectionMethod。幸运的是,它们都扩展了ReflectionFunctionAbstract,因此我们可以键入提示返回值。

function reflectCallable($arg): ReflectionFunctionAbstract {
    if (is_array($arg)) {
        $ref = new ReflectionMethod(...$arg);
    } elseif (is_callable($arg)) {
        $ref = new ReflectionFunction($arg);
    }

    return $ref;
}

这将为您返回适合您可调用值的对象,然后您可以使用该对象来获取参数并采取相应的行动:

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;
    }
}

请参见https://3v4l.org/c5vmM

请注意,这不会进行任何错误处理-如果可调用对象没有任何参数或第一个参数没有类型,则可能会收到警告/通知。它还需要PHP 7+,但希望这不是问题。

它目前不支持实现__invoke的对象或定义为"Foo::bar"的静态调用,但是在必要时添加它们并不难。 ve在Twig的来源中发现了非常相似的内容,它做了更彻底的工作:https://github.com/twigphp/Twig/blob/2.x/lib/Twig/Node/Expression/Call.php#L262