PHP call_user_func vs. função apenas de chamada

90

Tenho certeza de que há uma explicação muito fácil para isso. Qual é a diferença entre isso:

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

... e isto (e quais são os benefícios?):

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

Respostas:

87

Sempre use o nome real da função quando souber.

call_user_func é para chamar funções cujo nome você não sabe com antecedência, mas é muito menos eficiente, pois o programa precisa pesquisar a função em tempo de execução.

Kai
fonte
Obrigado Kai. call_user_func acabou sendo exatamente o que eu precisava.
Jay,
44
call_user_funcnão é necessariamente necessário. Você sempre pode chamar uma função usando funções variáveis: $some_func(). call_user_func_arrayé aquele que é realmente útil.
Ionuț G. Stan,
23
php sempre precisa "procurar a função em tempo de execução"
VolkerK de
2
@Pacerier Incorrect. As funções anônimas ainda estão em variáveis, ou seja $func = function(){};. Qualquer parâmetro possível para call_user_func deve ser chamável, o que significa que contém dados suficientes para acessá-lo diretamente, seja isso $func(), ou $obj->{$func}(), ou o que quer.
Benubird de
2
O "menos eficiente" é na verdade muito pouco, especialmente desde php7, é sobre algumas chamadas ms / milhões: github.com/fab2s/call_user_func
fab2s
32

Embora você possa chamar nomes de funções variáveis ​​desta maneira:

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

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

há casos em que você não sabe quantos argumentos está passando. Considere o seguinte:

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

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

Também é útil para chamar métodos estáticos e de objeto, respectivamente:

call_user_func(array('someClass','someFunc'),$arg);
call_user_func(array($myObj,'someFunc'),$arg);
Lucas omã
fonte
8
Eu sei que isso é muito antigo, mas não consegui encontrar artigos em outro lugar. É mais vantajoso usar call_user_func ('customFunction') em vez de $ variableFunction ()? Quais são as diferenças? Obrigado!
David Hobs
15

a call_user_funcopção está lá para que você possa fazer coisas como:

$dynamicFunctionName = "barber";

call_user_func($dynamicFunctionName, 'mushroom');

onde a dynamicFunctionNamestring poderia ser mais excitante e gerada em tempo de execução. Você não deve usar call_user_func a menos que seja necessário, porque é mais lento.

Brian Schroth
fonte
1
Parece que você poderia usar uma função variável neste cenário.
Anthony Rutledge
6

Eu imagino que seja útil para chamar uma função cujo nome você não sabe com antecedência ... Algo como:

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

call_user_func($func, 'stuff');
fundamental
fonte
5
Não. Ainda podemos fazer$func('stuff');
ankush981
1
Sim, mas a diferença é que usar uma variável produzirá um erro fatal do PHP em relação a um aviso do PHP se call_user_func for usado.
Robert Brisita
Isso não anulou o valor das funções variáveis call_user_func()neste cenário.
Anthony Rutledge
4

Com o PHP 7 você pode usar a sintaxe de função variável mais agradável em qualquer lugar. Ele funciona com funções estáticas / de instância e pode receber uma série de parâmetros. Mais informações em https://trowski.com/2015/06/20/php-callable-paradox

$ret = $callable(...$params);
mils
fonte
3

Não há vantagens em chamar a função assim porque acho que costumava chamar a função "usuário" (como o plugin) porque editar o arquivo principal não é uma boa opção. aqui estão os exemplos sujos usados ​​pelo 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
?>

resultado

hello world my name is Tasikmalaya
uingtea
fonte
0

em seu primeiro exemplo, você está usando o nome da função, que é uma string. pode vir de fora ou ser determinado imediatamente. ou seja, você não sabe qual função precisará ser executada no momento da criação do código.

SilentGhost
fonte
-1

Ao usar namespaces, call_user_func () é a única maneira de executar uma função cujo nome você não sabe de antemão, por exemplo:

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

Se todas as suas funções estivessem no mesmo namespace, então não seria um problema, pois você poderia usar algo assim:

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

Edit: Após @Jannis dizendo que estou errado, fiz mais alguns testes e não tive muita sorte:

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

Você pode ver os resultados de saída aqui: https://3v4l.org/iBERh parece que o segundo método funciona para o PHP 7 em diante, mas não para o PHP 5.6.

ThomasRedstone
fonte
. por não ser verdade. $ fn = '\ Foo \ Bar \ getCurrency'; $ fn ();
Jan Sverre
Olá @Jannis, não estou achando isso verdade, talvez você possa ver onde estou errado. Adicionei um exemplo mais detalhado à minha resposta.
ThomasRedstone
@ThomasRedstone você solicitou essas funções antes? php não carrega automaticamente funções de outros arquivos. Além disso, o que há com aquelas letras pequenas vs grandes em namespaces. Bar é uma aula? então esse é outro caso de uso.
przemo_li
oi @przemo_li, este é um único arquivo (tudo dentro do namespace), não tenho certeza do que aconteceu com o nome do namespace, em minha defesa, escrevi a resposta 4 anos atrás, atualizei o namespace e adicionei uma nota sobre PHP 7, com um link para ver a saída real. Eu ainda não sei como o jansverre fez funcionar, o PHP 7 não entrou no alpha até 11 de junho de 2015
ThomasRedstone