PHP call_user_func против простого вызова функции

92

Я уверен, что этому есть очень простое объяснение. В чем разница между этим:

function barber($type){
    echo "You wanted a $type haircut, no problem\n";
}
call_user_func('barber', "mushroom");
call_user_func('barber', "shave");

... и это (и каковы преимущества?):

function barber($type){
    echo "You wanted a $type haircut, no problem\n";
}
barber('mushroom');
barber('shave');
сойка
источник

Ответы:

88

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

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

Кай
источник
44
call_user_funcне обязательно нужен. Вы всегда можете вызвать функцию с помощью функции переменных: $some_func(). call_user_func_arrayдействительно полезен.
Ionuț G. Stan
23
php всегда необходимо «искать функцию во время выполнения»
VolkerK
2
@Pacerier Неверно. Анонимные функции все еще находятся в переменных, то есть $func = function(){};. Любой возможный параметр call_user_func должен быть вызываемым, что означает, что он содержит достаточно данных для прямого доступа к нему, будь то это $func()или $obj->{$func}()что-то еще.
Benubird
2
«Менее эффективное» на самом деле очень мало, особенно с учетом php7, это примерно несколько мс / миллион вызовов: github.com/fab2s/call_user_func
fab2s 05
1
Согласно одному источнику , «вызов несуществующей функции через переменную вызывает фатальную ошибку, а call_user_func () возвращает предупреждение». Так что это одно отличие.
mbomb007
32

Хотя вы можете вызывать имена функций переменных так:

function printIt($str) { print($str); }

$funcname = 'printIt';
$funcname('Hello world!');

бывают случаи, когда вы не знаете, сколько аргументов вы передаете. Обратите внимание на следующее:

function someFunc() {
  $args = func_get_args();
  // do something
}

call_user_func_array('someFunc',array('one','two','three'));

Это также удобно для вызова статических и объектных методов соответственно:

call_user_func(array('someClass','someFunc'),$arg);
call_user_func(array($myObj,'someFunc'),$arg);
Лукас Оман
источник
8
Я знаю, что это много лет, но нигде не нашел статей. Более выгодно использовать call_user_func ('customFunction') вместо $ variableFunction ()? Какие отличия? Благодарность!
Дэвид Хобс
14

call_user_funcвариант есть , так что вы можете сделать такие вещи , как:

$dynamicFunctionName = "barber";

call_user_func($dynamicFunctionName, 'mushroom');

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

Брайан Шрот
источник
2
Похоже, что в этом сценарии можно использовать переменную функцию.
Энтони Ратледж
5

Я полагаю, это полезно для вызова функции, название которой вы заранее не знаете ... Что-то вроде:

switch($value):
{
  case 7:
  $func = 'run';
  break;
  default:
  $func = 'stop';
  break;
}

call_user_func($func, 'stuff');
ключевой
источник
6
Неа. Мы все еще можем сделать$func('stuff');
ankush981
1
Да, но разница в том, что использование переменной вызовет фатальную ошибку PHP по сравнению с предупреждением PHP, если используется call_user_func.
Роберт Бризита
Это не отменяет значения функций переменных call_user_func()в данном сценарии.
Энтони Ратледж
5

В PHP 7 вы можете везде использовать более удобный синтаксис переменной-функции. Он работает со статическими функциями / функциями экземпляра и может принимать массив параметров. Больше информации на https://trowski.com/2015/06/20/php-callable-paradox

$ret = $callable(...$params);
милы
источник
AFAICT, это единственный ответ, который действительно отвечает на вопрос.
Mormegil
3

Нет никаких преимуществ при вызове такой функции, потому что я думаю, что она в основном используется для вызова "пользовательской" функции (например, плагина), потому что редактирование основного файла не является хорошим вариантом. вот грязный пример, используемый Wordpress

<?php
/* 
* my_plugin.php
*/

function myLocation($content){
  return str_replace('@', 'world', $content);
}

function myName($content){
  return $content."Tasikmalaya";
}

add_filter('the_content', 'myLocation');
add_filter('the_content', 'myName');

?>

...

<?php
/*
* core.php
* read only
*/

$content = "hello @ my name is ";
$listFunc = array();

// store user function to array (in my_plugin.php)
function add_filter($fName, $funct)
{
  $listFunc[$fName]= $funct;
}

// execute list user defined function
function apply_filter($funct, $content)
{
  global $listFunc;

  if(isset($listFunc))
  {
    foreach($listFunc as $key => $value)
    {
      if($key == $funct)
      {
        $content = call_user_func($listFunc[$key], $content);
      }
    }
  }
  return $content;
}

function the_content()
{
  $content = apply_filter('the_content', $content);
  echo $content;
}

?>

....

<?php
require_once("core.php");
require_once("my_plugin.php");

the_content(); // hello world my name is Tasikmalaya
?>

выход

hello world my name is Tasikmalaya
uingtea
источник
0

в вашем первом примере вы используете имя функции, которое является строкой. он может исходить извне или определяться на лету. то есть вы не знаете, какую функцию нужно будет запустить в момент создания кода.

Тихий призрак
источник
-1

При использовании пространств имен call_user_func () - единственный способ запустить функцию, имя которой вы заранее не знаете, например:

$function = '\Utilities\SearchTools::getCurrency';
call_user_func($function,'USA');

Если бы все ваши функции находились в одном пространстве имен, это не было бы такой проблемой, поскольку вы могли бы использовать что-то вроде этого:

$function = 'getCurrency';
$function('USA');

Изменить: после того, как @Jannis сказал, что я ошибаюсь, я провел еще немного тестов, и мне не повезло:

<?php
namespace Foo {

    class Bar {
        public static function getBar() {
            return 'Bar';
        }
    }
    echo "<h1>Bar: ".\Foo\Bar::getBar()."</h1>";
    // outputs 'Bar: Bar'
    $function = '\Foo\Bar::getBar';
    echo "<h1>Bar: ".$function()."</h1>";
    // outputs 'Fatal error: Call to undefined function \Foo\Bar::getBar()'
    $function = '\Foo\Bar\getBar';
    echo "<h1>Bar: ".$function()."</h1>";
    // outputs 'Fatal error: Call to undefined function \foo\Bar\getBar()'
}

Вы можете увидеть выходные результаты здесь: https://3v4l.org/iBERh, похоже, второй метод работает для PHP 7 и новее, но не для PHP 5.6.

Томас Редстоун
источник
1
. за неправду. $ fn = '\ Foo \ Bar \ getCurrency'; $ fn ();
Ян Сверре
Привет, @Jannis, я не считаю, что это правда, может быть, вы видите, где я ошибаюсь, я добавил более подробный пример к своему ответу.
ThomasRedstone
@ThomasRedstone, вам были нужны эти функции заранее? php не загружает функции из других файлов автоматически. И что с этими маленькими и большими буквами в пространствах имен. Бар - это класс? тогда это еще один вариант использования.
przemo_li
привет @przemo_li, это один файл (все в пространстве имен), не уверен, что произошло с именем пространства имен, в свою защиту я написал ответ 4 года назад, я обновил пространство имен и добавил примечание о PHP 7 со ссылкой для просмотра фактического результата. Я до сих пор не знаю, как jansverre заставил это работать, PHP 7 не вошел в альфа-
версию