Ответы:
is_callable
функцию. Он проверит, содержит ли переменная что-то, что может быть вызвано как функция (будь то имя функции, массив, содержащий экземпляр объекта и имя функции, или анонимная функция / замыкание)
call_user_func(array('ClassName', 'method'), $args)
Моя любимая версия - встроенная версия:
${"variableName"} = 12;
$className->{"propertyName"};
$className->{"methodName"}();
StaticClass::${"propertyName"};
StaticClass::{"methodName"}();
Вы можете поместить переменные или выражения в скобки тоже!
{"functionName"}();
недопустима и выдаст синтаксическую ошибку.
Да, это возможно:
function foo($msg) {
echo $msg."<br />";
}
$var1 = "foo";
$var1("testing 1,2,3");
Источник: http://www.onlamp.com/pub/a/php/2001/05/17/php_foundations.html?page=2
Как уже упоминалось, есть несколько способов достичь этого, возможно, самым безопасным способом, call_user_func()
или, если необходимо, вы также можете пойти по пути $function_name()
. Можно передать аргументы, используя оба этих метода, так
$function_name = 'foobar';
$function_name(arg1, arg2);
call_user_func_array($function_name, array(arg1, arg2));
Если вызываемая вами функция принадлежит объекту, вы все равно можете использовать любой из этих
$object->$function_name(arg1, arg2);
call_user_func_array(array($object, $function_name), array(arg1, arg2));
Однако, если вы собираетесь использовать $function_name()
метод, может быть хорошей идеей проверить наличие функции, если имя каким-либо образом является динамическим
if(method_exists($object, $function_name))
{
$object->$function_name(arg1, arg2);
}
В случае, если Google привел сюда кого-то еще, потому что он пытался использовать переменную для метода в классе, ниже приведен пример кода, который действительно будет работать. Ничто из вышеперечисленного не сработало для моей ситуации. Основное различие заключается &
в объявлении $c = & new...
и &$c
передаче call_user_func
.
Мой конкретный случай - при реализации чьего-либо кода, связанного с цветами и двумя методами-членами, lighten()
и darken()
из класса csscolor.php. По какой-то причине я хотел, чтобы один и тот же код мог вызывать светлее или темнее, а не выделять его с помощью логики. Это может быть результатом моего упрямства не просто использовать if-else или изменить код, вызывающий этот метод.
$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);
Обратите внимание, что попытка чего-либо с $c->{...}
не работает. Прочитав материалы, предоставленные читателями внизу страницы php.net call_user_func
, я смог собрать все вышеперечисленное. Также обратите внимание, что $params
как массив не работал для меня:
// This doesn't work:
$params=Array($color,$percent);
$rtn=call_user_func( array(&$c,$lightdark),$params);
Приведенная выше попытка выдаст предупреждение о методе, ожидающем 2-й аргумент (проценты).
Несколько лет спустя, но сейчас это лучший способ imho:
$x = (new ReflectionFunction("foo"))->getClosure();
$x();
Для полноты картины вы также можете использовать eval () :
$functionName = "foo()";
eval($functionName);
Тем не менее, call_user_func()
это правильный путь.
eval
не является решением этого вопроса.
Примечание: для краткой версии см. TL; DR в конце ответа.
Обновление : один из старых методов, описанных здесь, был удален. Обратитесь к другим ответам для объяснения других методов, здесь это не рассматривается. Кстати, если этот ответ вам не поможет, вам следует вернуться к обновлению вашего материала. Поддержка PHP 5.6 прекратилась в январе 2019 года (теперь даже PHP 7.0 и 7.1 не поддерживаются). Смотрите поддерживаемые версии для получения дополнительной информации.
Как уже упоминалось, в PHP5 (а также в более новых версиях, таких как PHP7) мы могли использовать переменные в качестве имен функций, использовать call_user_func()
и call_user_func_array()
(которые, лично я ненавижу эти функции) и т. Д.
Начиная с PHP7, появились новые способы:
Примечание. Все, что в <something>
скобках, означает одно или несколько выражений для формирования чего-либо, например, <function_name>
означает выражения, образующие имя функции.
Мы можем использовать одно или несколько выражений в скобках в качестве имени функции всего за один раз, в виде:
(<function_name>)(arguments);
Например:
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))()();
Примечание. Хотя удаление скобок str_replace()
не является ошибкой, добавление скобок делает код более читабельным. Тем не менее, вы не можете сделать это иногда, например, при использовании .
оператора. Чтобы быть последовательным, я рекомендую ставить круглые скобки всегда.
Так же, как динамические вызовы функций, мы можем сделать то же самое с вызовами методов, заключенными в фигурные скобки вместо скобок (для дополнительных форм перейдите к разделу TL; DR):
$object->{<method_name>}(arguments);
$object::{<method_name>}(arguments);
Смотрите это в примере:
class Foo
{
public function another(): string
{
return "something";
}
}
$bar = "another thing";
(new Something())->{explode(" ", $bar)[0]}(); // something
В PHP7 добавлен более элегантный способ:
[<object>, <method_name>](arguments);
[<class_name>, <method_name>](arguments); // Static calls only
Например:
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
Примечание . Преимущество использования этого метода перед предыдущим заключается в том, что вам не важен тип вызова (т. Е. Статический он или нет).
Делая вещи немного сложнее, вы можете использовать комбинацию анонимных классов и описанных выше функций:
$bar = "SomeThing";
echo (new class {
public function something()
{
return 512;
}
})->{strtolower($bar)}(); // 512
Как правило, в PHP7 возможно использование следующих форм:
// 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)
Основано в основном на этом разговоре PHP .
(expressions)->$bar()
Просто добавить пункт о динамических именах функций при использовании пространств имен.
Если вы используете пространства имен, следующее не будет работать, если только ваша функция не находится в глобальном пространстве имен:
namespace greetings;
function hello()
{
// do something
}
$myvar = "hello";
$myvar(); // interpreted as "\hello();"
Вы должны использовать 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);
В дополнение к ответу @Chris K, если вы хотите вызвать метод объекта, вы можете вызвать его с помощью одной переменной с помощью замыкания:
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"
Я разместил еще один пример здесь
Допустим, у меня есть эти переменные и функции:
$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";
}
Для вызова функции без аргументов
// Calling sayHello()
call_user_func($functionName1);
Здравствуйте!
Для вызова функции с 1 аргументом
// Calling sayHelloTo("John")
call_user_func($functionName2, $friend);
Дорогой Джон, привет!
Вызов функции с 1 или более аргументами.
Это будет полезно, если вы динамически вызываете свои функции и каждая функция имеет разное количество аргументов. Это мой случай, который я искал (и раскрыл). call_user_func_array
это ключ
// 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);
Дорогая Сара, как ты?
Yay пока!
Используйте функцию call_user_func.
Следующий код может помочь написать динамическую функцию в PHP. теперь имя функции можно динамически изменять с помощью переменной '$ current_page'.
$current_page = 'home_page';
$function = @${$current_page . '_page_versions'};
$function = function() {
echo 'current page';
};
$function();
$function
переменную без каких-либо причин.
Самый простой способ безопасного вызова функции с использованием имени, хранящегося в переменной:
//I want to call method deploy that is stored in functionname
$functionname = 'deploy';
$retVal = {$functionname}('parameters');
Я использовал, как показано ниже, для динамического создания таблиц миграции в Laravel,
foreach(App\Test::$columns as $name => $column){
$table->{$column[0]}($name);
}
Один необычный подход, который мне пришёл в голову, заключается в том, что, если вы не генерируете весь код с помощью какого-либо супер-ультра-автономного ИИ, который пишет сам , есть большие шансы, что функции, которые вы хотите «динамически» вызывать, уже определены в вашем коде. основание. Так почему бы просто не проверить строку и не позорить незнакомый ifelse
танец, чтобы вызвать ... вы поняли мою точку зрения.
например.
if($functionName == 'foo'){
foo();
} else if($functionName == 'bar'){
bar();
}
Даже switch-case
можно использовать, если вам не нравится мягкий вкус ifelse
лестницы.
Я понимаю, что есть случаи, когда « динамический вызов функции » был бы абсолютной необходимостью ( подобно некоторой рекурсивной логике, которая модифицирует себя ). Но большинство повседневных тривиальных сценариев использования можно просто избежать.
Он отсеивает большую неопределенность в вашем приложении, давая вам возможность выполнить резервную функцию, если строка не соответствует определению какой-либо из доступных функций. ПО МОЕМУ МНЕНИЮ.
if (method_exists($functionName)) $functionName(); else //exception or handle
Я не знаю, почему вы должны это использовать, мне это не очень хорошо звучит, но если есть только небольшое количество функций, вы можете использовать конструкцию if / elseif. Я не знаю, возможно ли прямое решение.
что-то вроде $ foo = "bar"; $ test = "foo"; эхо-тест $$;
должен вернуть бар, вы можете попробовать, но я не думаю, что это будет работать для функций