325

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

function foo ()
{
    //code here
}

function bar ()
{
    //code here
}

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

18 回答 18

509

$functionName()或者call_user_func($functionName)

于 2009-06-17T08:50:33.297 回答
144

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

${"variableName"} = 12;

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

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

您也可以将变量或表达式放在括号内!

于 2013-09-20T08:42:12.217 回答
30

解决方案:使用PHP7

注意:有关摘要版本,请参阅答案末尾的 TL;DR。

旧方法

更新:这里解释的旧方法之一已被删除。有关其他方法的说明,请参阅其他答案,此处不再赘述。顺便说一句,如果这个答案对您没有帮助,您应该返回升级您的东西。PHP 5.6 支持已于 2019 年 1 月结束(现在甚至不支持 PHP 7.1 和 7.2)。有关详细信息,请参阅支持的版本

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

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

就像动态函数调用一样,我们可以对方法调用做同样的事情,用花括号而不是括号括起来(对于额外的形式,导航到 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;DR(结论)

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

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

// Dynamic function call
(<function_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 演讲

于 2018-09-14T18:47:55.487 回答
23

是的,有可能:

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

于 2009-06-17T08:46:35.893 回答
20

如前所述,有几种方法可以实现这一点,可能是最安全的方法,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);
}
于 2013-01-31T14:05:11.340 回答
15

晚了几年,但这是现在最好的方式恕我直言:

$x = (new ReflectionFunction("foo"))->getClosure();
$x();
于 2016-02-27T22:50:47.510 回答
13

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

上述尝试将警告该方法需要第二个参数(百分比)。

于 2012-05-30T11:29:35.300 回答
10

为了完整起见,您还可以使用eval()

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

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

于 2009-06-17T09:00:39.063 回答
8

动态函数名称和命名空间

只是在使用命名空间时添加关于动态函数名称的一点。

如果您正在使用命名空间,则以下内容将不起作用,除非您的函数位于全局命名空间中:

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);
于 2014-02-02T16:19:30.420 回答
5

如果要调用对象的方法,可以补充@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"

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

于 2014-11-26T12:17:38.830 回答
4

我从这个问题和答案中学到了什么。谢谢大家!

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

$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. 使用 1 个参数调用函数

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

    亲爱的约翰,你好!

  3. 使用 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);
    

    亲爱的莎拉,你好吗?

再见!

于 2019-03-29T07:46:47.137 回答
3

使用 call_user_func 函数。

于 2009-06-17T08:47:45.360 回答
3

如果您在对象上下文中尝试动态调用函数,请尝试以下代码:

$this->{$variable}();
于 2021-04-07T00:44:27.973 回答
2

以下代码有助于在 PHP 中编写动态函数。现在函数名可以通过变量'$current_page'动态改变。

$current_page = 'home_page';
$function = @${$current_page . '_page_versions'};
$function = function() {
    echo 'current page';
};
$function();
于 2015-02-24T09:35:02.777 回答
2

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

//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);
}
于 2019-11-25T09:19:07.873 回答
0

考虑到这里给出的一些优秀答案,有时您需要精确。例如。

  1. 如果一个函数有一个返回值,例如(布尔值、数组、字符串、整数、浮点数等)。
  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($this, $obj))
        }

谢谢

于 2021-10-19T07:20:32.860 回答
-5

我想到的一种非常规方法是,除非您通过一些超自主的 AI 自己编写来生成整个代码,否则您想要“动态”调用的函数很有可能已经在您的代码中定义根据。那么,为什么不检查绳子并跳起臭名昭著的ifelse舞蹈来召唤……你明白我的意思。

例如。

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

如果您不喜欢梯子的平淡味道,甚至switch-case可以使用。ifelse

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

它消除了您的应用程序中的许多不确定性,同时让您有机会在字符串与任何可用函数的定义不匹配时执行回退函数。恕我直言。

于 2018-06-10T23:53:58.097 回答
-10

我不知道你为什么要使用它,对我来说听起来一点也不好,但如果只有少量函数,你可以使用 if/elseif 构造。我不知道是否可以直接解决。

类似 $foo = "bar"; $test = "foo"; 回声$$测试;

应该返回吧,您可以尝试一下,但我认为这不适用于函数

于 2009-06-17T08:50:51.750 回答