Respostas:
is_callable
função. Ele irá verificar se uma variável contém algo que pode ser chamado como uma função de (ser-lhe o nome de uma função, uma matriz que contém uma instância de objecto e um nome de função, ou uma função / fecho anónimo)
call_user_func(array('ClassName', 'method'), $args)
Minha versão favorita é a versão embutida:
${"variableName"} = 12;
$className->{"propertyName"};
$className->{"methodName"}();
StaticClass::${"propertyName"};
StaticClass::{"methodName"}();
Você também pode colocar variáveis ou expressões dentro dos colchetes!
{"functionName"}();
não é legal e gera um erro de sintaxe.
Sim, é possível:
function foo($msg) {
echo $msg."<br />";
}
$var1 = "foo";
$var1("testing 1,2,3");
Fonte: http://www.onlamp.com/pub/a/php/2001/05/17/php_foundations.html?page=2
Como já mencionado, existem algumas maneiras de conseguir isso, possivelmente com o método mais seguro call_user_func()
ou, se necessário, você também pode seguir o caminho $function_name()
. É possível passar argumentos usando esses dois métodos, assim
$function_name = 'foobar';
$function_name(arg1, arg2);
call_user_func_array($function_name, array(arg1, arg2));
Se a função que você está chamando pertencer a um objeto, você ainda poderá usar um destes
$object->$function_name(arg1, arg2);
call_user_func_array(array($object, $function_name), array(arg1, arg2));
No entanto, se você usar o $function_name()
método, pode ser uma boa ideia testar a existência da função se o nome for dinâmico de alguma forma
if(method_exists($object, $function_name))
{
$object->$function_name(arg1, arg2);
}
Caso alguém seja trazido aqui pelo google porque eles estavam tentando usar uma variável para um método dentro de uma classe, a seguir é um exemplo de código que realmente funcionará. Nenhuma das opções acima funcionou para a minha situação. A principal diferença está &
na declaração $c = & new...
e &$c
na transmissão call_user_func
.
Meu caso específico é ao implementar o código de alguém que tem a ver com cores e métodos de dois membros lighten()
e darken()
da classe csscolor.php. Por qualquer motivo, eu queria que o mesmo código pudesse chamar clarear ou escurecer, em vez de selecioná-lo com lógica. Esse pode ser o resultado da minha teimosia em não apenas usar if-else ou alterar o código que chama esse método.
$lightdark="lighten"; // or optionally can be darken
$color="fcc"; // a hex color
$percent=0.15;
include_once("csscolor.php");
$c = & new CSS_Color($color);
$rtn=call_user_func( array(&$c,$lightdark),$color,$percent);
Observe que tentar algo com $c->{...}
não funcionou. Ao ler atentamente o conteúdo fornecido pelo leitor na parte inferior da página do php.net, pude juntar os itens call_user_func
acima. Além disso, observe que, $params
como uma matriz não funcionou para mim:
// This doesn't work:
$params=Array($color,$percent);
$rtn=call_user_func( array(&$c,$lightdark),$params);
Essa tentativa acima daria um aviso sobre o método que espera um segundo argumento (por cento).
Alguns anos atrasado, mas esta é a melhor maneira agora imho:
$x = (new ReflectionFunction("foo"))->getClosure();
$x();
Por uma questão de integridade, você também pode usar eval () :
$functionName = "foo()";
eval($functionName);
No entanto, call_user_func()
é o caminho certo.
eval
não é uma solução para esta pergunta.
Nota: Para uma versão resumida, consulte TL; DR no final da resposta.
Atualização : um dos métodos antigos explicados aqui foi removido. Consulte outras respostas para obter explicação sobre outros métodos, que não são abordados aqui. A propósito, se esta resposta não ajudar, você deve retornar atualizando suas coisas. O suporte ao PHP 5.6 terminou em janeiro de 2019 (agora nem o PHP 7.0 e 7.1 estão sendo suportados). Veja as versões suportadas para mais informações.
Como já mencionado, no PHP5 (e também em versões mais recentes como o PHP7), poderíamos usar variáveis como nomes de funções, use call_user_func()
ecall_user_func_array()
(que, pessoalmente, odeio essas funções), etc.
A partir do PHP7, existem novas maneiras introduzidas:
Nota: Tudo <something>
entre parênteses significa uma ou mais expressões para formar algo, por exemplo<function_name>
significa formar um nome de função.
Podemos usar uma ou mais expressões entre parênteses como o nome da função de uma só vez, na forma de:
(<function_name>)(arguments);
Por exemplo:
function something(): string
{
return "something";
}
$bar = "some_thing";
(str_replace("_", "", $bar))(); // something
// Possible, too; but generally, not recommended, because makes your code more complicated
(str_replace("_", "", $bar))()();
Nota: Embora remover os parênteses str_replace()
não seja um erro, colocar parênteses torna o código mais legível. No entanto, você não pode fazer isso algumas vezes, por exemplo, enquanto estiver usando.
operador. Para ser consistente, recomendo que você coloque os parênteses sempre.
Assim como as chamadas de função dinâmica, podemos fazer o mesmo com as chamadas de método, cercadas por chaves em vez de parênteses (para formas extras, navegue até a seção TL; DR):
$object->{<method_name>}(arguments);
$object::{<method_name>}(arguments);
Veja em um exemplo:
class Foo
{
public function another(): string
{
return "something";
}
}
$bar = "another thing";
(new Something())->{explode(" ", $bar)[0]}(); // something
Uma maneira mais elegante adicionada no PHP7 é a seguinte:
[<object>, <method_name>](arguments);
[<class_name>, <method_name>](arguments); // Static calls only
Como um exemplo:
class Foo
{
public function nonStaticCall()
{
echo "Non-static call";
}
public static function staticCall()
{
echo "Static call";
}
}
$x = new X();
[$x, "non" . "StaticCall"](); // Non-static call
[$x, "static" . "Call"](); // Static call
Nota: O benefício de usar esse método em relação ao anterior é que você não se importa com o tipo de chamada (por exemplo, se é estático ou não).
Para tornar as coisas um pouco complicadas, você pode usar uma combinação de classes anônimas e os recursos acima:
$bar = "SomeThing";
echo (new class {
public function something()
{
return 512;
}
})->{strtolower($bar)}(); // 512
Geralmente, no PHP7, é possível usar os seguintes formulários:
// Everything inside `<something>` brackets means one or more expressions
// to form something
// Dynamic function call
(<function_name>)(arguments)
// Dynamic method call on an object
$object->{<method_name>}(arguments)
$object::{<method_name>}(arguments)
// Dynamic method call on a dynamically-generated object
(<object>)->{<method_name>}(arguments)
(<object>)::{<method_name>}(arguments)
// Dynamic method call, statically
ClassName::{<method_name>}(arguments)
(<class_name>)::{<method_name>}(arguments)
// Dynamic method call, array-like (no different between static and non-static calls
[<object>, <method_name>](arguments)
// Dynamic method call, array-like, statically
[<class_name>, <method_name>](arguments)
Baseado principalmente nesta conversa sobre PHP .
(expressions)->$bar()
Apenas para adicionar um ponto sobre nomes de funções dinâmicas ao usar espaços para nome.
Se você estiver usando espaços para nome, o seguinte não funcionará, exceto se sua função estiver no espaço para nome global:
namespace greetings;
function hello()
{
// do something
}
$myvar = "hello";
$myvar(); // interpreted as "\hello();"
Você precisa usar call_user_func()
:
// if hello() is in the current namespace
call_user_func(__NAMESPACE__.'\\'.$myvar);
// if hello() is in another namespace
call_user_func('mynamespace\\'.$myvar);
Complementando a resposta de @Chris K se você quiser chamar o método de um objeto, você pode chamá-lo usando uma única variável com a ajuda de um fechamento:
function get_method($object, $method){
return function() use($object, $method){
$args = func_get_args();
return call_user_func_array(array($object, $method), $args);
};
}
class test{
function echo_this($text){
echo $text;
}
}
$test = new test();
$echo = get_method($test, 'echo_this');
$echo('Hello'); //Output is "Hello"
Eu postei outro exemplo aqui
Digamos que eu tenho essas variáveis e funções:
$functionName1 = "sayHello";
$functionName2 = "sayHelloTo";
$functionName3 = "saySomethingTo";
$friend = "John";
$datas = array(
"something"=>"how are you?",
"to"=>"Sarah"
);
function sayHello()
{
echo "Hello!";
}
function sayHelloTo($to)
{
echo "Dear $to, hello!";
}
function saySomethingTo($something, $to)
{
echo "Dear $to, $something";
}
Para chamar função sem argumentos
// Calling sayHello()
call_user_func($functionName1);
Olá!
Para chamar função com 1 argumento
// Calling sayHelloTo("John")
call_user_func($functionName2, $friend);
Caro John, olá!
Para chamar a função com 1 ou mais argumentos
Isso será útil se você estiver chamando dinamicamente suas funções e cada função tiver um número diferente de argumentos. Este é o meu caso que eu tenho procurado (e resolvido). call_user_func_array
É a chave
// You can add your arguments
// 1. statically by hard-code,
$arguments[0] = "how are you?"; // my $something
$arguments[1] = "Sarah"; // my $to
// 2. OR dynamically using foreach
$arguments = NULL;
foreach($datas as $data)
{
$arguments[] = $data;
}
// Calling saySomethingTo("how are you?", "Sarah")
call_user_func_array($functionName3, $arguments);
Querida Sarah, como você está?
Yay tchau!
Use a função call_user_func.
O código a seguir pode ajudar a escrever a função dinâmica no PHP. agora o nome da função pode ser alterado dinamicamente pela variável '$ current_page'.
$current_page = 'home_page';
$function = @${$current_page . '_page_versions'};
$function = function() {
echo 'current page';
};
$function();
$function
variável sem nenhum motivo.
A maneira mais fácil de chamar uma função com segurança usando o nome armazenado em uma variável é,
//I want to call method deploy that is stored in functionname
$functionname = 'deploy';
$retVal = {$functionname}('parameters');
Eu usei como abaixo para criar tabelas de migração dinamicamente no Laravel,
foreach(App\Test::$columns as $name => $column){
$table->{$column[0]}($name);
}
Uma abordagem não convencional, que me veio à mente, é menos que você esteja gerando todo o código por meio de uma IA super ultra autônoma que se escreve , há grandes chances de que as funções que você deseja "dinamicamente" chamar já estejam definidas no seu código base. Então, por que não apenas verificar a corda e fazer o infameifelse
dança para convocar o ... você entendeu o meu ponto.
por exemplo.
if($functionName == 'foo'){
foo();
} else if($functionName == 'bar'){
bar();
}
Até switch-case
pode ser usado se você não gostar do sabor suave da ifelse
escada.
Entendo que há casos em que a " chamada dinâmica da função " seria uma necessidade absoluta ( como uma lógica recursiva que se modifica ). Mas a maioria dos casos de uso triviais do dia a dia pode ser esquivada.
Ele elimina muita incerteza do seu aplicativo, enquanto oferece a chance de executar uma função de fallback se a string não corresponder a nenhuma das definições de funções disponíveis. NA MINHA HUMILDE OPINIÃO.
if (method_exists($functionName)) $functionName(); else //exception or handle
Eu não sei por que você tem que usar isso, não parece tão bom para mim, mas se houver apenas uma pequena quantidade de funções, você pode usar uma construção if / elseif. Não sei se é possível uma solução direta.
algo como $ foo = "bar"; $ test = "foo"; teste de eco $$;
deve retornar bar, você pode tentar, mas eu não acho que isso funcionará para funções