Какой сценарий требует использования call_user_func () в php - PullRequest
4 голосов
/ 13 февраля 2012

Я не понимаю функцию call_user_func () в том смысле, что я понимаю, как она работает, но я не уверен, почему она требуется или в каком контексте использовать ее в php.Насколько я понимаю, почему бы просто не вызвать функцию вместо вызова функции с функцией?Thnx!

Ответы [ 3 ]

2 голосов
/ 14 февраля 2012

call_user_func дает PHP возможность рассматривать методы и функции как квази-первоклассных граждан.В функциональных языках, таких как javascript, нет необходимости в этих специальных инструментах как таковых, потому что функция - это объект, который может быть вызван.

Хотя PHP становится ближе к такому понятию, особенно с замыканиемподдержка, которая пришла вместе с PHP5.3.Посмотрите на комментарий, который я поместил под ответом @ deceze.Существуют некоторые другие инструменты (а именно функции переменных , отражение и теперь замыкания ), которые предлагают те же основные функции.

Наиболее заметная вещьо call_user_func , хотя и позволяет обрабатывать глобальные функции, статические классы и объекты с единым интерфейсом.Это, вероятно, самая близкая вещь, которую они имеют к единому интерфейсу для вызова функций независимо от того, как они реализованы.Внутренне группа разработчиков ядра PHP работает над гомогенизацией своего рода «вызываемого» или «вызываемого» интерфейса для языка , я уверен, что мы увидим чистое предложение в PHP5.4 илиследующий основной выпуск.

1 голос
/ 13 февраля 2012

У меня была пара ситуаций, когда это было очень необходимо. Например, когда я создавал проект, который позволял пользователю создавать части языка программирования, система включала определение «тега» в функцию, прежде чем запускать его из соображений безопасности. Однако, делая это, я не могу просто вызывать эти функции, потому что я не знаю, когда мне нужно их вызывать, или даже каковы будут имена. Введите call_user_func () ...

Итак, я уверен, что вы сейчас запутались. Позволь мне объяснить. Что моя система сделала, так это взяла немного XML и преобразовала его в PHP / HTML / JS с PHP. Это позволило быстро создавать графические интерфейсы (что и было целью). Возьмите этот XML, например:

<window id="login-win" title="Access Restricted" width="310" height="186" layout="accordion" layoutConfig="animate:true">
    <panel id="login-panel" title="User Login">
        <form id="login-form" title="Credentials">
            <textbox id="login-uname" label="Username"/>
            <password id="login-pass" label="Password"/>
            <submit text="Login"/>
        </form>
    </panel>
    <panel id="login-register" title="Register">
        Nothing, you can't register!
    </panel>
</window>

Каждый тег XML будет прочитан, а затем передан в соответствующую ему функцию PHP. Эта функция будет определять, что делать с этим 1 тегом. Для этого у меня были файлы, названные в честь тега, который он обрабатывал. Так, например, файл тега был «submit.php». Содержимое этого файла будет заключено в сгенерированную функцию, что-то вроде:

function tag_submit($variables, $parent, $children){

    // deal with the data, then echo what is needed

}

Имя этой функции будет сохранено в массиве с соответствующим именем тега вместе с остальными сгенерированными функциями. Это делает так, что функция генерируется один раз и создается только при необходимости, экономя память, так как я бы сделал вызов if (func_exists ()), чтобы определить, нужно мне это или нет.

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

Надеюсь, что все это имело смысл. В принципе, да, это редко используемая функция, но она все еще очень и очень полезна.

0 голосов
/ 28 июня 2014

Именованные функции, анонимные функции, статические методы, методы экземпляров и объекты с методом «__invoke» вместе называются «вызываемыми». Если у меня есть вызываемый объект, то должен быть в состоянии вызвать его, поставив после него круглые скобки "()" (я предполагаю, что аргументы не нужны) Это работает, когда наш вызываемый объект хранится в переменной, например:

$f();  // Call $f

Однако, что если я сохраню вызываемый объект в свойстве объекта?

$obj = new stdClass;
$obj->my_func = function() {};
$obj->my_func();  // Error: stdClass does not have a "my_func" method

Проблема в том, что синтаксический анализатор PHP запутывается, потому что код неоднозначен, это может означать вызов вызываемого свойства или вызов метода. PHP всегда рассматривает этот вид кода как вызов метода, поэтому мы не можем вызывать вызываемые свойства таким образом. Вот почему нам нужен call_user_func:

call_user_func($obj->my_func); // Calls $obj->my_func

В других случаях PHP не понимает нормальный синтаксис скобок; например, PHP в настоящее время (5.5) не знает, как вызвать возвращаемое значение другого вызываемого объекта:

get_a_callable()();  // Parse error, unexpected "("
call_user_func(get_a_callable());  // Calls the return value of get_a_callable

В настоящее время также невозможно напрямую вызывать определение функции, что полезно для обхода отсутствия в PHP операторов «let», например:

function($x) { echo $x . $x; }('hello');  // Parse error, unexpected "("
call_user_func(function($x) { echo $x . $x; }, 'hello'); // Calls the function

В некоторых случаях полезно иметь вызовы функций / reified / в качестве функции call_user_func. Например, при использовании функций высшего порядка, таких как array_map:

$funcs = [function() { return 'hello'; },
          function() { return 'world'; }];
array_map('call_user_func', $funcs);  // ['hello', 'world']

Это также полезно, когда мы не знаем, сколько параметров потребуется, т.е. мы не можем заменить нашу собственную "функцию ($ f, $ x, $ y, ...) {return $ f ($ x, $ y, ...);}".

Одно особенно приятное определение - это частичное приложение, которое занимает всего несколько строк благодаря call_user_func и call_user_func_array:

function partial() {
  $args1 = func_get_args();  // $f, $a, $b, $c, ...
  return function() use ($args1) {
    // Returns $f($a, $b, $c, ..., $d, $e, $f, ...)
    $args2 = func_get_args();  // $d, $e, $f, ...
    return call_user_func_array('call_user_func',
                                array_merge($args1, $args2));
  };
}
...