Подтвердить что ты не робот

Как получить количество заданных параметров времени исполнения?

ПРИМЕЧАНИЕ. В силу написания этого quesiton я уже понял, что я чрезмерно терпеливо отношусь к использованию новой языковой функции. В гораздо более чистом решении вместо этого использовался шаблон стратегии... тем не менее, мне любопытно, есть ли способ решить эту проблему.

TL; DR: Можете ли вы задуматься об общем вызове в PHP, не прибегая к ручному методу проверки типов всех видов?

В PHP 5.4 у нас есть новый тип: callable. Это кажется очень забавным. Я думал, что воспользуюсь этим через:

<?php
    public function setCredentialTreatment(callable $credentialTreatment) {
       // Verify $credentialTreatment can be used (ie: accepts 2 params)
       ... magic here ...
    }
?>

До сих пор моя мысль заключалась в том, чтобы сделать серию проверок типов на вызываемых и вывести из того, что использовать класс Reflection *:

<?php
if(is_array($callable)) {
    $reflector = new ReflectionMethod($callable[0], $callable[1]);
} elseif(is_string($callable)) {
    $reflector = new ReflectionFunction($callable);
} elseif(is_a($callable, 'Closure') || is_callable($callable, '__invoke')) {
    $objReflector = new ReflectionObject($callable);
    $reflector    = $objReflector->getMethod('__invoke');
}

// Array of ReflectionParameters. Yay!
$parameters = $reflector->getParameters();
// Inspect parameters. Throw invalidArgumentException if not valid.
?>

Теперь для меня это слишком сложно. Я пропустил какой-то яркий способ достичь того, что я пытаюсь сделать здесь? Любое понимание будет приветствоваться:)

4b9b3361

Ответ 1

Я создал более короткую версию, которая работает так же, как call_user_func(), и протестировала ее на всех разных типах в руководстве PHP для обратных вызовов/вызовов. Таким образом, вы можете использовать его практически в любом месте. call_user_func() не принимает только объекты, и мне не показалось, что эта функция должна либо, так как она обрабатывает только обратные вызовы.

Тесты и предложения о том, как их использовать, приведены ниже, и я надеюсь, что это поможет:

function getNrOfParams($callable)
{
    $CReflection = is_array($callable) ? 
    new ReflectionMethod($callable[0], $callable[1]) : 
    new ReflectionFunction($callable);
    return $CReflection->getNumberOfParameters();
}

Тест и его результат целиком:

<?php   
class Smart
{
    public function __invoke($name)
    {

    }

    public function my_callable($one, $two, $three)
    {

    }

    public static function myCallableMethod($one, $two) 
    {

    }

    public static function who()
    {
            echo "smart the parent class";
    }
}

class Smarter extends Smart
{
    public static function who()
    {
        echo "smarter";
    }
}

function my_ca($one)
{

}

function getNrOfParams($callable)
{
    $CReflection = is_array($callable) ? new ReflectionMethod($callable[0], $callable[1]) : new ReflectionFunction($callable);
    return $CReflection->getNumberOfParameters();
}
// Test 1 Callable Function
echo "Test 1 - Callable function:" . getNrOfParams('my_ca');

// Test 2 Static method
echo " Test 2 - Static class method:" . getNrOfParams(array('Smart', 'myCallableMethod'));

// Test 3 Object method
$smart = new Smart();
echo " Test 3 - Object method:" . getNrOfParams(array($smart, 'my_callable'));

// Test 4 Static method call (As of PHP 5.2.3)
//echo " Test 4 - Static class method call:" . getNrOfParams('Smart::myCallableMethod');
// Calling a static method this way does not work in ReflectionFunction.
// However, Test 2 provides a solution.

// Test 5 Relative static method (As of PHP 5.3.0)
//echo " Test 5 - Relative static class method:" . getNrOfParams(array('Smarter', 'parent::who'));
// Calling a relative static method doesn't work either. ReflectionMethod lacks support.
// All other tests work.

// Tesy 6 __invoke
echo " Test 6 - __invoke:" . getNrOfParams(array($smart, '__invoke'));

// Test 7 Closure
$closure = function($one, $two, $three)
{
    // Magic
};
echo " Test 7 - Closure:" . getNrOfParams($closure);

Ответ 2

Вы можете передать массив с аргументом и можете подсчитать значения массива, чтобы узнать аргумент, переданный функции обратного вызова.