Мне нужно иметь возможность вызывать функцию, но имя функции хранится в переменной, возможно ли это? например:
function foo () { //code here } function bar () { //code here } $functionName = "foo"; // i need to call the function based on what is $functionName
Anyhelp будет здорово.
Спасибо!
Моя любимая версия - встроенная версия:
${"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. По какой-то причине я хотел, чтобы один и тот же код мог вызвать lighten или darken, а не выбирать его с логикой. Это может быть результатом моего упрямства не просто использовать 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);
Эта вышеприведенная попытка даст предупреждение о методе, ожидающем второй аргумент (в процентах).
Несколько лет спустя, но это лучший способ теперь imho:
$x = (new ReflectionFunction("foo"))->getClosure();
$x();
Для полноты вы также можете использовать eval():
$functionName = "foo()";
eval($functionName);
Однако call_user_func()
является правильным способом.
eval
не является решением этого вопроса.
Просто добавьте точку имен динамических функций при использовании пространств имен.
Если вы используете пространства имен, , то следующее не будет работать, если только ваша функция находится в глобальном пространстве имен:
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);
Есть несколько потрясающих возможностей с PHP7. Первоначально, как уже упоминалось, в PHP5 (и даже старше PHP5) мы могли бы сделать:
function something() {
echo 256;
}
$foo = "something";
$foo(); // 256
Это хорошо, но в PHP7 это стало лучше. Мы можем совершать произвольные операции над (a) строками в круглых скобках и использовать их как имя функции всего за один раз (рассмотрим, что мы объявили функцию something()):
$bar = "some_thing";
// We use in this form: (expressions)(arguments);
(str_replace("_", "", $bar))(); // 256
Кроме того, вы можете использовать следующую форму:
(expressions)['bar']
(expressions)->bar
(expressions)->bar()
(expressions)->$bar()
(expressions)::$bar
(expressions)::bar()
(expressions)()
Например, вы можете использовать комбинацию анонимных классов и вышеприведенную функцию:
echo (new class {
public $something = 512;
})->something; // 512
Кроме того, вы можете вызвать метод в экземпляре класса в виде:
[objectInstance, methodName]();
В качестве примера мы могли бы сделать:
class X {
public function object_call() {
echo "Object Call";
}
public static function static_call() {
echo "Static Call";
}
}
[new X(), "object_call"](); // Object Call
[new X(), "static_call"](); // Static Call
Взято из этого разговора PHP.
(expressions)->$bar()
Дополняя ответ @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"
Я разместил еще один пример здесь
Используйте функцию call_user_func.
Следующий код может помочь написать динамическую функцию в PHP. теперь имя функции может динамически меняться переменной '$ current_page'.
$current_page = 'home_page';
$function = @${$current_page . '_page_versions'};
$function = function() {
echo 'current page';
};
$function();
Один необычный подход, который пришел мне на ум, заключается в том, что, если вы не генерируете весь код через супер сверхавтономный ИИ, который сам пишет, есть большие шансы, что функции, которые вы хотите "динамически" вызвать, уже определены в вашем коде база. Так почему бы не просто проверить строку и сделать позорный 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"; echo $$ test;
должен возвращать бар, вы можете попробовать, но я не думаю, что это будет работать для функций