代码之家  ›  专栏  ›  技术社区  ›  marcosh

检查callable是否可以在php中接收类作为参数

  •  0
  • marcosh  · 技术社区  · 6 年前

    我有一个电话号码 $f 我想知道它是否可以接收某个类的实例 Foo 作为输入。

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

    有没有一种方法可以在不调用callable的情况下进行检查?也许是反射或者其他的黑魔法?

    2 回复  |  直到 6 年前
        1
  •  1
  •   iainn    5 年前

    如果希望能够反映任何类型的可调用性,则需要将逻辑封装在一个小函数中。根据您是拥有数组、函数名还是匿名函数,您需要创建 ReflectionFunction ReflectionMethod . 幸运的是,这两者都扩展了 ReflectionFunctionAbstract ,因此我们可以键入hint返回值。

    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

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

    它目前不支持实现 __invoke 或静态调用定义为 "Foo::bar" ,但如果有必要的话,它们也不会太难添加。 https://github.com/twigphp/Twig/blob/v2.8.0/src/Node/Expression/CallExpression.php#L280

        2
  •  1
  •   Barry    6 年前

    你可以用 ReflectionParameter::getType

    $f = function(Foo $foo) {};
    
    $reflectionFunc = new ReflectionFunction($f);
    $reflectionParams = $reflectionFunc->getParameters();
    $reflectionType1 = $reflectionParams[0]->getType();
    
    echo $reflectionType1;
    

    输出: