如何从存储在变量中的字符串调用函数?

我需要能够调用一个函数,但函数名存储在一个变量,这是可能的吗?例句:

function foo ()
{
//code here
}


function bar ()
{
//code here
}


$functionName = "foo";
// I need to call the function based on what is $functionName
335377 次浏览

是的,这是可能的:

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函数。

我不知道你为什么要用这个,听起来对我来说一点都不好,但如果只有少量的函数,你可以使用if/elseif结构。

.我不知道是否有直接的解决办法 < p >之类的 $foo = "bar"; $test = "foo"; echo $ $测试;< / p >

应该返回酒吧,你可以尝试,但我不认为这将工作的功能

为了完整起见,你也可以使用eval ():

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

然而,call_user_func()才是正确的方法。

如果有人被谷歌带到这里,因为他们试图在一个类中使用一个方法的变量,下面是一个实际工作的代码示例。以上这些方法都不适用于我的情况。关键的区别是$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);

上述尝试将给出关于该方法期望第二个参数(percent)的警告。

如前所述,有几种方法可以实现这一点,最安全的方法可能是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);
}

我最喜欢的版本是内联版本:

${"variableName"} = 12;


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


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

你也可以把变量或表达式放在括号里!

动态函数名和命名空间

只是在使用名称空间时补充一点关于动态函数名的内容。

如果你正在使用命名空间,下面的方法行不通除非你的函数在全局命名空间中:

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"

我发布了另一个例子在这里

下面的代码有助于在PHP中编写动态函数。 现在函数名可以通过变量'$current_page'动态更改
$current_page = 'home_page';
$function = @${$current_page . '_page_versions'};
$function = function() {
echo 'current page';
};
$function();

虽然晚了几年,但我认为这是现在最好的方式:

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

我想到的一种非常规方法是除非你是通过一些超级超级自主的人工智能来生成整个代码,你想“动态”调用的函数很有可能已经在你的代码库中定义了。所以为什么不检查字符串并执行臭名昭著的ifelse舞蹈来召唤…你明白我的意思了。

如。

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

即使switch-case也可以使用,如果你不喜欢ifelse梯子的平淡味道。

我理解在某些情况下,“动态调用函数”是绝对必要的(就像一些自我修正的递归逻辑)。但是大多数日常琐碎的用例都可以被避开。

它从应用程序中清除了许多不确定性,同时如果字符串不匹配任何可用函数的定义,则为您提供了执行回退函数的机会。恕我直言。

解决方案:使用PHP7

注意:一个总结的版本,见TL;DR在答案的末尾。

老方法

更新:这里解释的一个旧方法已被删除。关于其他方法的解释,请参考其他答案,这里不涉及。顺便说一下,如果这个答案对你没有帮助,你应该回来升级你的东西。对PHP 5.6的支持已于2019年1月结束(现在甚至不支持PHP 7.2和7.3)。更多信息请参见支持版本

正如其他人所提到的,在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()周围的括号并不是错误,但添加括号会使代码更具可读性。然而,有时你不能这样做,例如在使用.操作符时。为了保持一致,我建议您始终使用括号。

动态函数调用:可调用属性

一个有用的例子是在对象的上下文中:如果你在属性中存储了一个可调用对象,你必须这样调用它:

($object->{<property_name>})();

举个简单的例子:

// Suppose we're in a class method context
($this->eventHandler)();

显然,将其调用为$this->eventHandler()是完全错误的:你的意思是调用名为eventHandler的方法。

动态方法调用:动态方法名

就像动态函数调用一样,我们也可以用同样的方法调用方法,用花括号括起来,而不是圆括号(对于额外的表单,请导航到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

与前一个方法相比,使用这个方法的好处是,你不关心调用类型(即它是否是静态的)。

注意:如果你关心性能(和微优化),不要使用这个方法。在我的测试中,这个方法确实比其他方法慢(超过10倍)。

额外示例:使用匿名类

让事情变得有点复杂,你可以结合使用匿名类和上面的特性:

$bar = "SomeThing";


echo (new class {
public function something()
{
return 512;
}
})->{strtolower($bar)}(); // 512

TL;博士(结论)

一般来说,在PHP7中,使用下列形式都是可能的:

// Everything inside `<something>` brackets means one or more expressions
// to form something


// Dynamic function call via function name
(<function_name>)(arguments);


// Dynamic function call on a callable property
($object->{<property_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讲座

我从这个问题和答案中学到了什么。感谢所有!

假设我有这些变量和函数:

$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";
}
  1. 调用函数不带参数

    // Calling sayHello()
    call_user_func($functionName1);
    

    你好!

    李< /引用> < / >
  2. 调用函数只有一个参数

    // Calling sayHelloTo("John")
    call_user_func($functionName2, $friend);
    

    亲爱的约翰,你好!

    李< /引用> < / >
  3. 使用一个或多个实参调用函数 如果动态调用函数,并且每个函数有不同数量的参数,这将非常有用。这是我一直在寻找(并解决)的案子。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);
    

    亲爱的莎拉,你好吗?

    李< /引用> < / >

耶再见!

使用存储在变量中的名称安全地调用函数的最简单方法是,

//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);
}

如果你在一个对象上下文中试图动态调用一个函数,请尝试如下代码:

$this->{$variable}();
考虑到这里给出的一些很好的答案,有时你需要精确。 例如,< / p >
  1. 如果函数有返回值,例如(布尔值,数组,字符串,int,浮点数 李e.t.c)。< / >
  2. 如果函数没有返回值,则检查
  3. 如果函数存在

让我们来看看这些答案的可信度。

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($class, $method))
}

谢谢