简体   繁体   English

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

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

I need to be able to call a function, but the function name is stored in a variable, is this possible?我需要能够调用 function,但是 function 名称存储在一个变量中,这可能吗? eg:例如:

function foo ()
{
    //code here
}

function bar ()
{
    //code here
}

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

My favorite version is the inline version:我最喜欢的版本是内联版本:

${"variableName"} = 12;

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

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

You can place variables or expressions inside the brackets too!您也可以将变量或表达式放在方括号内!

Solution: Use PHP7解决方案:使用PHP7

Note: For a summarized version, see TL;DR at the end of the answer.注意:有关摘要版本,请参阅答案末尾的 TL;DR。

Old Methods旧方法

Update : One of the old methods explained here has been removed.更新:此处解释的旧方法之一已被删除。 Refer to other answers for explanation on other methods, it isn't covered here.其他方法的解释请参考其他答案,这里不做赘述。 By the way, if this answer doesn't help you, you should return upgrading your stuff.顺便说一下,如果这个答案对你没有帮助,你应该回来升级你的东西。 PHP 5.6 support has ended in January 2019 (now even PHP 7.2 and 7.3 are not being supported). PHP 5.6 支持已于 2019 年 1 月结束(现在甚至不支持 PHP 7.2 和 7.3)。 See supported versions for more information.有关详细信息,请参阅支持的版本

As others mentioned, in PHP5 (and also in newer versions like PHP7) we could use variables as function names, use call_user_func() and call_user_func_array() , etc.正如其他人提到的,在 PHP5(以及较新的版本,如 PHP7)中,我们可以使用变量作为 function 名称,使用call_user_func()call_user_func_array()等。

New Methods新方法

As of PHP7, there are new ways introduced:从 PHP7 开始,引入了新的方法:

Note: Everything inside <something> brackets means one or more expressions to form something, eg <function_name> means expressions forming a function name.注意: <something>括号内的所有内容都表示一个或多个表达式来构成某物,例如<function_name>表示构成 function 名称的表达式。

Dynamic Function Call: Function Name On-the-fly动态 Function 呼叫:Function 即时姓名

We can form a function name inside parentheses in just one go:我们可以在一个 go 中形成一个括号内的 function 名称:

(<function_name>)(arguments);

For example:例如:

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

Note: Although removing the parentheses around str_replace() is not an error, putting parentheses makes code more readable.注意:虽然删除str_replace()周围的括号不是错误,但放置括号可使代码更具可读性。 However, you cannot do that sometimes, eg while using .但是,有时您不能这样做,例如在使用. operator.操作员。 To be consistent, I recommend you to put the parentheses always.为了保持一致,我建议您始终使用括号。

Dynamic Function Call: Callable Property动态 Function 调用:Callable Property

A useful example would be in the context of objects: If you have stored a callable in a property, you have to call it this way:一个有用的例子是在对象的上下文中:如果你在属性中存储了一个可调用对象,你必须这样调用它:

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

As a simple example:举个简单的例子:

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

Obviously, calling it as $this->eventHandler() is plain wrong: By that you mean calling a method named eventHandler .显然,将其称为$this->eventHandler()是完全错误的:您的意思是调用名为eventHandler的方法。

Dynamic Method Call: Method Name On-the-fly动态方法调用:动态方法名称

Just like dynamic function calls, we can do the same way with method calls, surrounded by curly braces instead of parentheses (for extra forms, navigate to TL;DR section):就像动态 function 调用一样,我们可以对方法调用执行相同的方式,用大括号而不是圆括号括起来(对于额外的 forms,请导航至 TL;DR 部分):

$object->{<method_name>}(arguments);
$object::{<method_name>}(arguments);

See it in an example:在一个例子中看到它:

class Foo
{
    public function another(): string
    {
        return "something";
    }
}

$bar = "another thing";

(new Something())->{explode(" ", $bar)[0]}(); // something

Dynamic Method Call: The Array Syntax动态方法调用:数组语法

A more elegant way added in PHP7 is the following: PHP7中添加的更优雅的方式如下:

[<object>, <method_name>](arguments);
[<class_name>, <method_name>](arguments); // Static calls only

As an example:举个例子:

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

Note: The benefit of using this method over the previous one is that, you don't care about the call type (ie whether it's static or not).注意:与前一种方法相比,使用此方法的好处是,您无需关心呼叫类型(即是否为 static)。

Note: If you care about performance (and micro-optimizations), don't use this method.注意:如果您关心性能(和微优化),请不要使用此方法。 As I tested, this method is really slower than other methods (more than 10 times).正如我测试的那样,这种方法确实比其他方法慢(超过 10 倍)。

Extra Example: Using Anonymous Classes附加示例:使用匿名类

Making things a bit complicated, you could use a combination of anonymous classes and the features above:让事情变得有点复杂,您可以结合使用匿名类和上述功能:

$bar = "SomeThing";

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

TL;DR (Conclusion) TL;DR(结论)

Generally, in PHP7, using the following forms are all possible:一般在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);

Special thanks to this PHP talk .特别感谢这个 PHP talk

Yes, it is possible:是的,有可能:

function foo($msg) {
    echo $msg."<br />";
}
$var1 = "foo";
$var1("testing 1,2,3");

Source: http://www.onlamp.com/pub/a/php/2001/05/17/php_foundations.html?page=2资料来源: http://www.onlamp.com/pub/a/php/2001/05/17/php_foundations.html?page=2

As already mentioned, there are a few ways to achieve this with possibly the safest method being call_user_func() or if you must you can also go down the route of $function_name() .如前所述,有几种方法可以实现这一点,最安全的方法可能是call_user_func()或者如果必须的话,你也可以沿着$function_name()的路线 go 。 It is possible to pass arguments using both of these methods as so可以使用这两种方法传递 arguments

$function_name = 'foobar';

$function_name(arg1, arg2);

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

If the function you are calling belongs to an object you can still use either of these如果您呼叫的 function 属于 object,您仍然可以使用其中任何一个

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

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

However if you are going to use the $function_name() method it may be a good idea to test for the existence of the function if the name is in any way dynamic但是,如果您打算使用$function_name()方法,那么测试 function 是否存在是个好主意,如果名称是动态的

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

A few years late, but this is the best manner now imho:晚了几年,但这是现在最好的方式恕我直言:

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

In case someone else is brought here by google because they were trying to use a variable for a method within a class, the below is a code sample which will actually work.如果其他人被谷歌带到这里,因为他们试图在 class 中使用变量作为方法,下面是一个实际工作的代码示例。 None of the above worked for my situation.以上都不适合我的情况。 The key difference is the & in the declaration of $c = & new... and &$c being passed in call_user_func .主要区别在于$c = & new...声明中的&和在call_user_func中传递的&$c

My specific case is when implementing someone's code having to do with colors and two member methods lighten() and darken() from the csscolor.php class. For whatever reason, I wanted to have the same code be able to call lighten or darken rather than select it out with logic.我的具体情况是在实现某人的代码时必须使用 colors 和来自 csscolor.php class 的两个成员方法 lighten lighten()和 darken darken() 。无论出于何种原因,我希望相同的代码能够调用 lighten() 和 darken() 而不是比 select 更符合逻辑。 This may be the result of my stubbornness to not just use if-else or to change the code calling this method.这可能是我顽固地不使用 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);

Note that trying anything with $c->{...} didn't work.请注意,使用$c->{...}尝试任何操作均无效。 Upon perusing the reader-contributed content at the bottom of php.net's page on call_user_func , I was able to piece together the above.在仔细阅读 php.net 上call_user_func页面底部的读者贡献内容后,我能够拼凑出以上内容。 Also, note that $params as an array didn't work for me:另外,请注意$params作为数组对我不起作用

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

This above attempt would give a warning about the method expecting a 2nd argument (percent).上面的尝试会给出关于期望第二个参数(百分比)的方法的警告。

For the sake of completeness, you can also use eval() :为了完整起见,您还可以使用eval()

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

However, call_user_func() is the proper way.但是, call_user_func()是正确的方法。

Dynamic function names and namespaces动态 function 名称和命名空间

Just to add a point about dynamic function names when using namespaces.只是在使用名称空间时添加关于动态 function 名称的一点。

If you're using namespaces, the following won't work except if your function is in the global namespace:如果您使用的是命名空间,则以下内容将不起作用,除非您的 function 在全局命名空间中:

namespace greetings;

function hello()
{
    // do something
}

$myvar = "hello";
$myvar(); // interpreted as "\hello();"

What to do?该怎么办?

You have to use call_user_func() instead:您必须改用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);

Complementing the answer of @Chris K if you want to call an object's method, you can call it using a single variable with the help of a closure:如果你想调用一个对象的方法,补充@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"

I posted another example here我在这里发布了另一个例子

Use the call_user_func function.使用 call_user_func function。

What I learnt from this question and the answers.我从这个问题和答案中学到了什么。 Thanks all!谢谢大家!

Let say I have these variables and functions:假设我有这些变量和函数:

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

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

    Hello!你好!

  2. To call function with 1 argument使用 1 个参数调用 function

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

    Dear John, hello!亲爱的约翰,你好!

  3. To call function with 1 or more arguments This will be useful if you are dynamically calling your functions and each function have different number of arguments. This is my case that I have been looking for (and solved).使用 1 个或多个 arguments调用 function 如果您正在动态调用函数并且每个 function 具有不同数量的 arguments,这将很有用。这是我一直在寻找(并解决)的案例。 call_user_func_array is the key 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);

    Dear Sarah, how are you?亲爱的莎拉,你好吗?

Yay bye!再见!

If you were in a object context trying to call a function dynamically please try something like this code bellow:如果您在 object 上下文中尝试动态调用 function,请尝试如下代码:

$this->{$variable}();

Following code can help to write dynamic function in PHP. now the function name can be dynamically change by variable '$current_page'.以下代码可以帮助在 PHP 中写入动态 function。现在 function 名称可以通过变量“$current_page”动态更改。

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

The easiest way to call a function safely using the name stored in a variable is,使用存储在变量中的名称安全调用 function 的最简单方法是,

//I want to call method deploy that is stored in functionname 
$functionname = 'deploy';

$retVal = {$functionname}('parameters');

I have used like below to create migration tables in Laravel dynamically,我已经像下面那样在 Laravel 中动态创建迁移表,

foreach(App\Test::$columns as $name => $column){
        $table->{$column[0]}($name);
}

Considering some of the excellent answers given here, sometimes you need to be precise.考虑到此处给出的一些出色答案,有时您需要做到精确。 For example.例如。

  1. if a function has a return value eg (boolean,array,string,int,float etc).如果 function 有返回值,例如(布尔值、数组、字符串、整数、浮点数等)。
  2. if the function has no return value check如果function没有返回值检查
  3. if the function exists如果 function 存在

Let's look at its credit to some of the answers given.让我们看看它对给出的一些答案的功劳。

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";
    }
 }

We want to check if method exists and call it dynamically.我们想检查方法是否存在并动态调用它。

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

Thanks谢谢

One unconventional approach, that came to my mind is, unless you are generating the whole code through some super ultra autonomous AI which writes itself , there are high chances that the functions which you want to "dynamically" call, are already defined in your code base.我想到的一种非常规方法是,除非您通过一些自行编写的超超自治 AI 生成整个代码,否则您想要“动态”调用的函数很可能已经在您的代码中定义根据。 So why not just check for the string and do the infamous ifelse dance to summon the...you get my point.那么,为什么不只检查字符串并执行臭名昭著的ifelse舞蹈来召唤……你明白我的意思了。

eg.例如。

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

Even switch-case can be used if you don't like the bland taste of ifelse ladder.如果你不喜欢ifelse梯子的乏味,甚至可以使用switch-case

I understand that there are cases where the " dynamically calling the function " would be an absolute necessity ( Like some recursive logic which modifies itself ).我知道在某些情况下“动态调用 function ”是绝对必要的(就像一些修改自身的递归逻辑)。 But most of the everyday trivial use-cases can just be dodged.但是大多数日常琐碎的用例都可以避免。

It weeds out a lot of uncertainty from your application, while giving you a chance to execute a fallback function if the string doesn't match any of the available functions' definition.它消除了应用程序中的很多不确定性,同时让您有机会在字符串与任何可用函数的定义不匹配时执行回退 function。 IMHO.恕我直言。

I dont know why u have to use that, doesnt sound so good to me at all, but if there are only a small amount of functions, you could use a if/elseif construct.我不知道为什么你必须使用它,对我来说听起来不太好,但如果只有少量功能,你可以使用 if/elseif 结构。 I dont know if a direct solution is possible.我不知道是否可以直接解决。

something like $foo = "bar";像 $foo = "bar"; $test = "foo"; $测试=“富”; echo $$test;回声$$测试;

should return bar, you can try around but i dont think this will work for functions应该返回栏,你可以尝试一下,但我认为这不适用于函数

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

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