繁体   English   中英

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

[英]How to call a function from a string stored in a variable?

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

function foo ()
{
    //code here
}

function bar ()
{
    //code here
}

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

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

${"variableName"} = 12;

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

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

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

解决方案:使用PHP7

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

旧方法

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

正如其他人提到的,在 PHP5(以及较新的版本,如 PHP7)中,我们可以使用变量作为 function 名称,使用call_user_func()call_user_func_array()等。

新方法

从 PHP7 开始,引入了新的方法:

注意: <something>括号内的所有内容都表示一个或多个表达式来构成某物,例如<function_name>表示构成 function 名称的表达式。

动态 Function 呼叫:Function 即时姓名

我们可以在一个 go 中形成一个括号内的 function 名称:

(<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()周围的括号不是错误,但放置括号可使代码更具可读性。 但是,有时您不能这样做,例如在使用. 操作员。 为了保持一致,我建议您始终使用括号。

动态 Function 调用:Callable Property

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

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

举个简单的例子:

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

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

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

就像动态 function 调用一样,我们可以对方法调用执行相同的方式,用大括号而不是圆括号括起来(对于额外的 forms,请导航至 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

注意:与前一种方法相比,使用此方法的好处是,您无需关心呼叫类型(即是否为 static)。

注意:如果您关心性能(和微优化),请不要使用此方法。 正如我测试的那样,这种方法确实比其他方法慢(超过 10 倍)。

附加示例:使用匿名类

让事情变得有点复杂,您可以结合使用匿名类和上述功能:

$bar = "SomeThing";

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

TL;DR(结论)

一般在PHP7中,使用下面的forms都是可以的:

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

是的,有可能:

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()的路线 go 。 可以使用这两种方法传递 arguments

$function_name = 'foobar';

$function_name(arg1, arg2);

call_user_func_array($function_name, array(arg1, arg2));

如果您呼叫的 function 属于 object,您仍然可以使用其中任何一个

$object->$function_name(arg1, arg2);

call_user_func_array(array($object, $function_name), array(arg1, arg2));

但是,如果您打算使用$function_name()方法,那么测试 function 是否存在是个好主意,如果名称是动态的

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

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

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

如果其他人被谷歌带到这里,因为他们试图在 class 中使用变量作为方法,下面是一个实际工作的代码示例。 以上都不适合我的情况。 主要区别在于$c = & new...声明中的&和在call_user_func中传递的&$c

我的具体情况是在实现某人的代码时必须使用 colors 和来自 csscolor.php class 的两个成员方法 lighten lighten()和 darken darken() 。无论出于何种原因,我希望相同的代码能够调用 lighten() 和 darken() 而不是比 select 更符合逻辑。 这可能是我顽固地不使用 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);

上面的尝试会给出关于期望第二个参数(百分比)的方法的警告。

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

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

但是, call_user_func()是正确的方法。

动态 function 名称和命名空间

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

如果您使用的是命名空间,则以下内容将不起作用,除非您的 function 在全局命名空间中:

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 function。

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

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

$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. 在没有 arguments 的情况下拨打 function

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

    你好!

  2. 使用 1 个参数调用 function

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

    亲爱的约翰,你好!

  3. 使用 1 个或多个 arguments调用 function 如果您正在动态调用函数并且每个 function 具有不同数量的 arguments,这将很有用。这是我一直在寻找(并解决)的案例。 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);

    亲爱的莎拉,你好吗?

再见!

如果您在 object 上下文中尝试动态调用 function,请尝试如下代码:

$this->{$variable}();

以下代码可以帮助在 PHP 中写入动态 function。现在 function 名称可以通过变量“$current_page”动态更改。

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

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

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

考虑到此处给出的一些出色答案,有时您需要做到精确。 例如。

  1. 如果 function 有返回值,例如(布尔值、数组、字符串、整数、浮点数等)。
  2. 如果function没有返回值检查
  3. 如果 function 存在

让我们看看它对给出的一些答案的功劳。

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

谢谢

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

例如。

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

如果你不喜欢ifelse梯子的乏味,甚至可以使用switch-case

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

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

我不知道为什么你必须使用它,对我来说听起来不太好,但如果只有少量功能,你可以使用 if/elseif 结构。 我不知道是否可以直接解决。

像 $foo = "bar"; $测试=“富”; 回声$$测试;

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM