PHP call_user_func порівняно з простою функцією виклику


90

Я впевнений, що цьому є дуже просте пояснення. Яка різниця між цим:

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

Відповіді:


87

Завжди використовуйте фактичне ім’я функції, коли вам це відомо.

call_user_func призначений для виклику функцій, ім’я яких ви не знаєте заздалегідь, але це набагато менш ефективно, оскільки програма повинна шукати функцію під час виконання.


Дякую Кай. 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

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 ()? Які відмінності? Дякую!
Девід Хобс,

15

call_user_funcваріант є , так що ви можете зробити такі речі , як:

$dynamicFunctionName = "barber";

call_user_func($dynamicFunctionName, 'mushroom');

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


1
Здається, ви могли б використовувати функцію змінної в цьому сценарії.
Ентоні Ратледж,

6

Думаю, це корисно для виклику функції, якій ви не знаєте назви заздалегідь ... Щось на зразок:

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

call_user_func($func, 'stuff');

5
Ні. Ми все ще можемо це зробити$func('stuff');
ankush981

1
Так, але різниця у використанні змінної призведе до фатальної помилки PHP порівняно з попередженням PHP, якщо використовується call_user_func.
Роберт Брісіта,

Це не заперечувало значення змінних функцій call_user_func()у цьому сценарії.
Ентоні Ратледж,

4

З PHP 7 ви можете використовувати приємніший синтаксис змінних функцій скрізь. Він працює зі статичними / екземпляром функцій, і він може приймати масив параметрів. Більше інформації на https://trowski.com/2015/06/20/php-callable-paradox

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

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

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.


. за неправду. $ fn = '\ Foo \ Bar \ getCurrency'; $ fn ();
Ян Сверре

Привіт @Jannis, я не вважаю, що це правда, можливо, ти бачиш, де я помиляюся, я додав більш детальний приклад до своєї відповіді.
ThomasRedstone

@ThomasRedstone ти вимагав цих функцій заздалегідь? php не завантажує функції з інших файлів. Також що з цими малими проти великих літер у просторах імен. Бар - це клас? то це ще одна справа використання.
przemo_li

привіт @przemo_li, це єдиний файл (все в межах простору імен), не впевнений, що сталося з ім'ям простору імен, на мій захист, я написав відповідь 4 роки тому, оновив простір імен і додав у примітці про PHP 7, з посиланням, щоб побачити фактичний результат. Я досі не знаю, як Janverver змусив це працювати, PHP 7 не увійшов до альфа-версії до 11 червня 2015 р.
ThomasRedstone
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.