How to call PHP function from string stored in a Variable
Мне нужно иметь возможность вызывать функцию, но имя функции хранится в переменной, это возможно? например:
function foo () { // код здесь } function bar () { // код здесь } $functionName = "foo"; // i need to call the function based on what is $functionName
Anyhelp would be great.
Спасибо!
18 ответов
Моя любимая версия - встроенная версия:
${"variableName"} = 12;
$className->{"variableName"};
$className->{"methodName"}();
StaticClass::${"variableName"};
StaticClass::{"methodName"}();
Вы можете поместить переменные или выражения в скобки тоже!
В PHP7 есть несколько потрясающих возможностей. Изначально, как уже упоминалось, в PHP5 (и даже старше, чем PHP5) мы могли сделать:
function something() {
echo 256;
}
$foo = "something";
$foo(); // 256
Это хорошо, но в PHP7 стало лучше. Мы можем выполнить произвольные операции над (a) строкой (ами) в скобках и использовать ее в качестве имени функции всего за один раз (учтите, что мы объявили функцию что-то ()):
$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)()
Например, вы можете использовать комбинацию анонимных классов и функции выше:
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.
Да, это возможно:
function foo($msg) {
echo $msg."<br />";
}
$var1 = "foo";
$var1("testing 1,2,3");
Source: 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);
}
Несколько лет спустя, но это лучший способ сейчас imho:
$x = (new ReflectionFunction("foo"))->getClosure();
$x();
В случае, если 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-й аргумент (проценты).
Для полноты картины вы также можете использовать eval ():
$functionName = "foo()";
eval($functionName);
Тем не мение, call_user_func()
это правильный путь.
Динамические имена функций и пространства имен
Просто добавить пункт о динамических именах функций при использовании пространств имен.
Если вы используете пространства имен, следующее не будет работать, если только ваша функция не находится в глобальном пространстве имен:
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 пока!
Если вы были в контексте объекта, пытаясь вызвать функцию динамически, попробуйте что-то вроде этого кода ниже:
$this->{$variable}();
Самый простой способ безопасно вызвать функцию, используя имя, хранящееся в переменной, - это
//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);
}
Следующий код может помочь написать динамическую функцию в PHP. теперь имя функции можно динамически менять с помощью переменной '$current_page'.
$current_page = 'home_page';
$function = @${$current_page . '_page_versions'};
$function = function() {
echo 'current page';
};
$function();
Учитывая некоторые из приведенных здесь отличных ответов, иногда вам нужно быть точным. Например.
- если функция имеет возвращаемое значение, например (логическое, массив, строка, int, float и т. д.).
- если функция не имеет возвращаемого значения, проверьте
- если функция существует
Давайте посмотрим на его кредитоспособность на некоторые из полученных ответов.
Class Cars{
function carMake(){
return 'Toyota';
}
function carMakeYear(){
return 2020;
}
function estimatedPriceInDollar{
return 1500.89;
}
function colorList(){
return array("Black","Gold","Silver","Blue");
}
function carUsage(){
return array("Private","Commercial","Government");
}
function getCar(){
echo "Toyota Venza 2020 model private estimated price is 1500 USD";
}
}
Мы хотим проверить, существует ли метод, и вызвать его динамически.
$method = "color List";
$class = new Cars();
//If the function have return value;
$arrayColor = method_exists($class, str_replace(' ', "", $method)) ? call_user_func(array($this, $obj)) : [];
//If the function have no return value e.g echo,die,print e.t.c
$method = "get Car";
if(method_exists($class, str_replace(' ', "", $method))){
call_user_func(array($this, $obj))
}
Спасибо
Один из нетрадиционных подходов, который мне пришел в голову, заключается в том, что если вы не генерируете весь код с помощью какого-либо супер-ультра-автономного ИИ, который пишет сам, есть большие шансы, что функции, которые вы хотите "динамически" вызывать, уже определены в вашем коде. база. Так почему бы просто не проверить строку и сделать позорную ifelse
танцуй, чтобы вызвать... ты понял мою точку зрения.
например.
if($functionName == 'foo'){
foo();
} else if($functionName == 'bar'){
bar();
}
Четное switch-case
можно использовать, если вам не нравится мягкий вкус ifelse
лестница.
Я понимаю, что есть случаи, когда "динамический вызов функции" был бы абсолютной необходимостью (подобно некоторой рекурсивной логике, которая модифицирует себя). Но большинство повседневных тривиальных вариантов использования можно просто избежать.
Он отсеивает большую неопределенность в вашем приложении, давая вам возможность выполнить резервную функцию, если строка не соответствует определению какой-либо из доступных функций. ПО МОЕМУ МНЕНИЮ.
Я не знаю, почему вы должны это использовать, мне это не очень хорошо звучит, но если есть только небольшое количество функций, вы можете использовать конструкцию if/elseif. Я не знаю, возможно ли прямое решение.
что-то вроде $foo = "bar"; $test = "foo"; эхо-тест $$;
должен вернуть бар, вы можете попробовать, но я не думаю, что это будет работать для функций