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

function foo ()
{
    //code here
}

function bar ()
{
    //code here
}

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

当前回答

动态函数名和命名空间

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

如果你正在使用命名空间,下面的代码将不起作用,除非你的函数在全局命名空间中:

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

其他回答

$functionName()或call_user_func($functionName)

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

eg.

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

如果你不喜欢ifelse梯子的无味味道,甚至可以使用开关盒。

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

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

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

解决方案:使用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讲座。

使用call_user_func函数。