Как вызвать функцию PHP из строки, хранящейся в переменной

269

Мне нужно иметь возможность вызывать функцию, но имя функции хранится в переменной, возможно ли это? например:

function foo ()
{
  //code here
}

function bar ()
{
  //code here
}

$functionName = "foo";
// i need to call the function based on what is $functionName

Anyhelp будет здорово.

Спасибо!

Теги:

14 ответов

442
Лучший ответ

$functionName() или call_user_func($functionName) p >

  • 4
    Мне нужно сделать это самому, но я немного обеспокоен, что это так легко (надругаться): D
  • 11
    +1, даже если я лично не рекомендую $ functionName (), труднее читать и обнаруживать.
Показать ещё 6 комментариев
95

Моя любимая версия - встроенная версия:

${"variableName"} = 12;

$className->{"propertyName"};
$className->{"methodName"}();

StaticClass::${"propertyName"};
StaticClass::{"methodName"}();

Вы можете поместить переменные или выражения в скобки тоже!

  • 1
    @marcioAlmada: публиковать комментарии, а не редактировать ответы других таким образом; это добавляет путаницу - не ясно, кто что сказал [для любопытных: см. ревизии для объяснений]
  • 4
    Хорошо, @kryger. Строка 2 {"functionName"}(); не является законным и выдаст синтаксическую ошибку.
Показать ещё 3 комментария
17

Да, это возможно:

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

16

Как уже упоминалось, есть несколько способов достичь этого, возможно, самым безопасным способом является 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);
}
  • 0
    Это должен быть принятый ответ.
12

В случае, если кто-то еще привезет сюда 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);

Эта вышеприведенная попытка даст предупреждение о методе, ожидающем второй аргумент (в процентах).

  • 0
    что делает "$ c = & new CSS_Color"? Я говорю об усилителе (&). Что это и меняет?
  • 0
    @danon & является оператором "address of" или "reference". Я вызываю новый объект класса CSS_Color, а затем присваиваю его ссылку (он же адрес) на $ c. Я ненавижу повторять код, поэтому часто использую имена переменных переменных.
Показать ещё 3 комментария
11

Несколько лет спустя, но это лучший способ теперь imho:

$x = (new ReflectionFunction("foo"))->getClosure();
$x();
  • 3
    Путь к ООП для меня, но я дал ему +1, так как никто еще не упомянул классы Reflection.
9

Для полноты вы также можете использовать eval():

$functionName = "foo()";
eval($functionName);

Однако call_user_func() является правильным способом.

  • 6
    Следует отметить, что eval () допускает такое же поведение, но также позволяет выполнять любой код PHP. Таким образом, переменная может быть использована для взлома системы. Call_user_func () не приносит таких проблем безопасности.
  • 4
    eval не является решением этого вопроса.
Показать ещё 1 комментарий
6

Динамические имена функций и пространства имен

Просто добавьте точку имен динамических функций при использовании пространств имен.

Если вы используете пространства имен, , то следующее не будет работать, если только ваша функция находится в глобальном пространстве имен:

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);
5

Есть несколько потрясающих возможностей с 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.

  • 1
    Хороший список выражений, также включает в себя: (expressions)->$bar()
  • 1
    @Necro Спасибо, я добавил это!
3

Дополняя ответ @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"

Я разместил еще один пример здесь

2

Используйте функцию call_user_func.

1

Следующий код может помочь написать динамическую функцию в PHP. теперь имя функции может динамически меняться переменной '$ current_page'.

$current_page = 'home_page';
$function = @${$current_page . '_page_versions'};
$function = function() {
    echo 'current page';
};
$function();
-3

Один необычный подход, который пришел мне на ум, заключается в том, что, если вы не генерируете весь код через супер сверхавтономный ИИ, который сам пишет, есть большие шансы, что функции, которые вы хотите "динамически" вызвать, уже определены в вашем коде база. Так почему бы не просто проверить строку и сделать позорный ifelse танец, чтобы вызвать... вы получите мою точку зрения.

например.

if($functionName == 'foo'){
  foo();
} else if($functionName == 'bar'){
  bar();
}

Даже switch-case можно использовать, если вам не нравится мягкий вкус лестницы ifelse.

Я понимаю, что бывают случаи, когда "динамическое вызов функции" будет абсолютной необходимостью (как и какая-то рекурсивная логика, которая модифицирует себя). Но большинство повседневных тривиальных случаев использования можно просто уклониться.

Это избавляет от неопределенности от вашего приложения, давая вам возможность выполнить функцию возврата, если строка не соответствует определению определения доступных функций. ПО МОЕМУ МНЕНИЮ.

  • 0
    Если значение переменной уже является именем функции, зачем делать дополнительную работу? также было бы хорошо получить твердую обратную связь, чтобы увидеть, существует ли функция по php, прежде чем запускать ее: if (method_exists($functionName)) $functionName(); else //exception or handle
  • 1
    Да, ваша точка зрения верна, но поскольку имя функции является динамическим, в вашей логике любая строка, которая приходит, должна выполняться, если функция с таким именем существует, независимо от того, актуальна ли эта функция в текущей ситуации или нет. Мой подход гарантирует, что может быть выполнен только определенный набор функций, в противном случае может быть выдана ошибка. Это может быть упрощено массивами и как таковыми.
-9

Я не знаю, почему у вас это использовать, не так хорошо звучит для меня вообще, но если есть только небольшое количество функций, вы можете использовать конструкцию if/elseif. Я не знаю, возможно ли прямое решение.

что-то вроде $ foo = "bar"; $ test = "foo"; echo $$ test;

должен возвращать бар, вы можете попробовать, но я не думаю, что это будет работать для функций

Ещё вопросы

Сообщество Overcoder
Наверх
Меню