У меня есть вызов $f
и я хотел бы знать, может ли он получить экземпляр определенного класса Foo
в качестве ввода.
На данный момент я делаю что-то вроде
try {
$f($foo);
} catch (\TypeError $e) {
throw new \InvalidArgumentException('The provided function can not evaluate inputs of this type');
}
Есть ли способ проверить это БЕЗ фактического вызова вызываемого? Может быть, с отражением или какой-то другой темной магией?
Если вы хотите, чтобы можно было отразить любой вызываемый тип, вам нужно заключить логику в небольшую функцию. В зависимости от того, есть ли у вас массив, имя функции или анонимная функция, вам нужно создать ReflectionFunction
или же ReflectionMethod
. К счастью, оба они расширяются 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+, но, надеюсь, это не проблема.
В настоящее время он не поддерживает объекты, которые реализуют Я только что нашел что-то очень похожее в источнике Twig, который выполняет более тщательную работу: https://github.com/twigphp/Twig/blob/2.x/lib/Twig/Node/Expression/Call.php#L262__invoke
или статические вызовы, определенные как "Foo::bar"
, но их не будет слишком сложно добавить в случае необходимости.
Вы можете с ReflectionParameter :: GetType:
$f = function(Foo $foo) {};
$reflectionFunc = new ReflectionFunction($f);
$reflectionParams = $reflectionFunc->getParameters();
$reflectionType1 = $reflectionParams[0]->getType();
echo $reflectionType1;
выход:
Foo