PHP call_user_func vs. samo wywołanie funkcji

92

Jestem pewien, że istnieje na to bardzo proste wytłumaczenie. Jaka jest różnica między tym:

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

... i to (i jakie są korzyści?):

function barber($type){
    echo "You wanted a $type haircut, no problem\n";
}
barber('mushroom');
barber('shave');
sójka
źródło

Odpowiedzi:

88

Zawsze używaj rzeczywistej nazwy funkcji, gdy ją znasz.

call_user_func służy do wywoływania funkcji, których nazwy nie znasz z wyprzedzeniem, ale jest znacznie mniej wydajne, ponieważ program musi wyszukiwać funkcję w czasie wykonywania.

Kai
źródło
44
call_user_funcniekoniecznie jest potrzebne. Zawsze można wywołać funkcję za pomocą funkcji zmiennych: $some_func(). call_user_func_arrayjest tym, który jest naprawdę przydatny.
Ionuț G. Stan
23
php zawsze musi „wyszukiwać funkcję w czasie wykonywania”
VolkerK
2
@Pacerier Incorrect. Funkcje anonimowe są nadal w zmiennych, tj $func = function(){};. Ewentualne parametrem call_user_func musi być wymagalne, co oznacza, że zawiera wystarczającą ilość danych, aby uzyskać dostęp to bezpośrednio, czy to $func(), czy $obj->{$func}(), czy cokolwiek.
Benubird,
2
„Mniej wydajne” to właściwie bardzo mało, zwłaszcza że php7 to około kilku ms / milion połączeń: github.com/fab2s/call_user_func
fab2s
1
Według jednego ze źródeł „wywołanie nieistniejącej funkcji poprzez zmienną powoduje błąd krytyczny, podczas gdy call_user_func () zwraca ostrzeżenie”. Więc to jest jedna różnica.
mbomb007
32

Chociaż nazwy funkcji zmiennych można wywoływać w ten sposób:

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

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

są przypadki, w których nie wiesz, ile argumentów przekazujesz. Rozważ następujące:

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

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

Jest również przydatny do wywoływania odpowiednio metod statycznych i obiektowych:

call_user_func(array('someClass','someFunc'),$arg);
call_user_func(array($myObj,'someFunc'),$arg);
Lucas Oman
źródło
8
Wiem, że to jest stare, ale nie mogę znaleźć artykułów gdzie indziej. Czy korzystniejsze jest użycie call_user_func ('customFunction') jako dołączonego do $ variableFunction ()? Jakie są różnice? Dzięki!
David Hobs
14

call_user_funcopcja jest tam tak można robić takie rzeczy jak:

$dynamicFunctionName = "barber";

call_user_func($dynamicFunctionName, 'mushroom');

gdzie dynamicFunctionNameciąg mógłby być bardziej ekscytujący i generowany w czasie wykonywania. Nie powinieneś używać call_user_func, chyba że musisz, ponieważ jest wolniejszy.

Brian Schroth
źródło
2
Wygląda na to, że w tym scenariuszu możesz użyć funkcji zmiennej.
Anthony Rutledge,
5

Wyobrażam sobie, że jest to przydatne do wywoływania funkcji, której nazwy z góry nie znasz ... Coś takiego:

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

call_user_func($func, 'stuff');
kluczowy
źródło
6
Nie. Nadal możemy to zrobić$func('stuff');
ankush981
1
Tak, ale różnica polega na tym, że użycie zmiennej spowoduje błąd krytyczny PHP w porównaniu z ostrzeżeniem PHP, jeśli używane jest call_user_func.
Robert Brisita
Nie zanegowało to wartości funkcji zmiennych call_user_func()w tym scenariuszu.
Anthony Rutledge
5

W PHP 7 możesz wszędzie używać ładniejszej składni zmiennej i funkcji. Działa z funkcjami statycznymi / instancjami i może przyjmować tablicę parametrów. Więcej informacji na https://trowski.com/2015/06/20/php-callable-paradox

$ret = $callable(...$params);
mils
źródło
ODPOWIEDŹ, to jedyna odpowiedź, która naprawdę odpowiada na pytanie.
Mormegil
3

Nie ma żadnych korzyści z wywoływania tej funkcji w ten sposób, ponieważ myślę, że była używana głównie do wywoływania funkcji użytkownika (takiej jak wtyczka), ponieważ edycja pliku podstawowego nie jest dobrą opcją. oto brudny przykład używany przez 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
?>

wynik

hello world my name is Tasikmalaya
uingtea
źródło
0

w pierwszym przykładzie używasz nazwy funkcji, która jest łańcuchem. może pochodzić z zewnątrz lub zostać ustalone w locie. to znaczy nie wiesz, jaka funkcja będzie musiała zostać uruchomiona w momencie tworzenia kodu.

SilentGhost
źródło
-1

Podczas korzystania z przestrzeni nazw call_user_func () jest jedynym sposobem na uruchomienie funkcji, której nazwy nie znasz, na przykład:

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

Gdyby wszystkie twoje funkcje znajdowały się w tej samej przestrzeni nazw, nie byłby to taki problem, ponieważ możesz użyć czegoś takiego:

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

Edycja: Śledząc @Jannis mówiąc, że się mylę, przeprowadziłem trochę więcej testów i nie miałem dużo szczęścia:

<?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()'
}

Możesz zobaczyć wyniki wyjściowe tutaj: https://3v4l.org/iBERh wydaje się, że druga metoda działa od PHP 7, ale nie PHP 5.6.

ThomasRedstone
źródło
1
. za nieprawdę. $ fn = '\ Foo \ Bar \ getCurrency'; $ fn ();
Jan Sverre
Cześć @Jannis, nie uważam, że to prawda, może widzisz, gdzie idę źle, dodałem bardziej szczegółowy przykład do mojej odpowiedzi.
ThomasRedstone
@ThomasRedstone Czy wcześniej wymagałeś tych funkcji? php nie ładuje automatycznie funkcji z innych plików. A co z tymi małymi i dużymi literami w przestrzeniach nazw. Czy Bar to klasa? to jest kolejny przypadek użycia.
przemo_li
cześć @przemo_li, to jest pojedynczy plik (wszystko w przestrzeni nazw), nie jestem pewien, co się stało z nazwą przestrzeni nazw, na swoją obronę napisałem odpowiedź 4 lata temu, zaktualizowałem przestrzeń nazw i dodałem w notatce o PHP 7, z linkiem do rzeczywistego wyniku. I nadal nie wiem, jak to działa jansverre wykonane, PHP 7 nie wchodzi alfa aż 11 cze 2015
ThomasRedstone