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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1005857/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 00:36:39  来源:igfitidea点击:

How to call a function from a string stored in a variable?

phpdynamic-function

提问by Lizard

I need to be able to call a function, but the function name is stored in a variable, is this possible? e.g:

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

function foo ()
{
  //code here
}

function bar ()
{
  //code here
}

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

回答by Lajos Meszaros

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!

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

回答by Sev

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

回答by olliefinn

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(). It is possible to pass arguments using both of these methods as so

如前所述,有几种方法可以实现这一点,可能是最安全的方法,call_user_func()或者如果必须,您也可以沿着$function_name(). 可以使用这两种方法传递参数

$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

如果您正在调用的函数属于一个对象,您仍然可以使用其中任何一个

$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()方法,如果名称以任何方式动态,则测试该函数是否存在可能是个好主意

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

回答by Chris K

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. None of the above worked for my situation. The key difference is the &in the declaration of $c = & new...and &$cbeing passed in call_user_func.

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

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. This may be the result of my stubbornness to not just use if-else or to change the code calling this method.

我的具体情况是在实现某人的代码时与颜色和两个成员方法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);

Note that trying anything with $c->{...}didn't work. 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. Also, note that $paramsas an array didn't workfor me:

请注意,尝试任何东西都$c->{...}不起作用。在阅读 php.net 页面底部的读者贡献内容后call_user_func,我能够将上述内容拼凑起来。另外,请注意,$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).

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

回答by Internal Server Error

A few years late, but this is the best manner now imho:

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

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

回答by karim79

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()才是正道。

回答by MAChitgarha

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 is not 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.0 and 7.1 are not being supported). See supported versionsfor more information.

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

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()(which, personally, I hate those functions), etc.

正如其他人提到的,在 PHP5(以及像 PHP7 这样的较新版本中)我们可以使用变量作为函数名、使用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, e.g. <function_name>means expressions forming a function name.

注意:<something>括号内的所有内容表示由一个或多个表达式组成的东西,例如,<function_name>表示形成函数名称的表达式。

Dynamic Function Call: Function Name On-the-fly

动态函数调用:动态函数名称

We can use one or more expressions inside parentheses as the function name in just one go, in the form of:

我们可以一次性使用一个或多个括号内的表达式作为函数名,形式如下:

(<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. However, you cannot do that sometimes, e.g. while using .operator. To be consistent, I recommend you to put the parentheses always.

注意:虽然去掉括号str_replace()不是错误,但是加上括号会使代码更具可读性。但是,有时您不能这样做,例如在使用.运算符时。为了保持一致,我建议您始终使用括号。

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

就像动态函数调用一样,我们可以对方法调用做同样的事情,用大括号而不是圆括号括起来(对于额外的形式,导航到 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 (i.e. whether it's static or not).

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

Extra Example: Using Anonymous Classes

额外示例:使用匿名类

Making things a bit complicated, you could use a combination of anonymous classesand 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中,使用以下形式都是可以的:

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

Based mostly on this PHP talk.

主要基于这个 PHP 谈话

回答by Jivan

Dynamic function names and namespaces

动态函数名称和命名空间

Just to add a point about dynamic function names when using namespaces.

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

If you're using namespaces, the following won't workexcept if your function is in the global namespace:

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

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

回答by David

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

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