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

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

function foo ()
{
  //code here
}

function bar ()
{
  //code here
}

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

Anyhelp было бы здорово.

спасибо!

14 ответов



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

${"variableName"} = 12;

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

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

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


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

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(). Можно передать аргументы, используя оба этих метода, как so

$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() метод может быть хорошей идеей проверить наличие функции если имя каким-либо образом dynamic

if(method_exists($object, $function_name))
{
    $object->$function_name(arg1, arg2);
}

в случае, если кто-то еще привлечен сюда google, потому что они пытались использовать переменную для метода в классе, ниже приведен пример кода, который действительно будет работать. Ничего из вышеперечисленного не сработало в моей ситуации. Ключевым отличием является & в заявлении $c = & new... и &$c был принят в call_user_func.

мой конкретный случай-это реализация чьего-то кода, связанного с цветами и двумя методами-членами lighten() и darken() от csscolor.РНР класс. По какой-то причине я хотел, чтобы один и тот же код мог вызывать 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 ' s страница на call_user_func, я смог собрать воедино все вышеперечисленное. Кроме того, обратите внимание, что $params как массив не работает для меня:

// This doesn't work:
$params=Array($color,$percent);
$rtn=call_user_func( array(&$c,$lightdark),$params);

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


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

$x = (new ReflectionFunction("foo"))->getClosure();
$x();

для полноты вы также можете использовать 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"

я опубликовал еще один пример здесь


используйте функцию 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 лестница.

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

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


есть некоторые удивительные возможности, как PHP7. Первоначально, как упоминали другие, в PHP5 (и даже старше PHP5) мы могли бы сделать:

function something() {
    echo 256;
}

$foo = "something";
$foo(); // 256

это хорошо, но в PHP7 стало лучше. Мы можем сделать произвольные операции над строкой(а) в круглых скобках и использовать ее как имя функции всего за один раз (рассмотрим, что мы объявили функцию 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)()

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

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 talk.


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

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

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