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

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

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');

8 ответов

Решение

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

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

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

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);

call_user_func опция есть, чтобы вы могли делать такие вещи, как:

$dynamicFunctionName = "barber";

call_user_func($dynamicFunctionName, 'mushroom');

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

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

$ret = $callable(...$params);

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

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

call_user_func($func, 'stuff');

Вызывать такую ​​функцию не имеет смысла, потому что я думаю, что она в основном используется для вызова "пользовательской" функции (например, плагина), потому что редактирование файла ядра не является хорошим вариантом. Вот грязный пример, используемый 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

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

При использовании пространств имен 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.

Другие вопросы по тегам