[英]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"}();
您也可以将变量或表达式放在方括号内!
注意:有关摘要版本,请参阅答案末尾的 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 名称的表达式。
我们可以在一个 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()
周围的括号不是错误,但放置括号可使代码更具可读性。 但是,有时您不能这样做,例如在使用.
操作员。 为了保持一致,我建议您始终使用括号。
一个有用的例子是在对象的上下文中:如果你在属性中存储了一个可调用对象,你必须这样调用它:
($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
一般在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);
上面的尝试会给出关于期望第二个参数(百分比)的方法的警告。
只是在使用名称空间时添加关于动态 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";
}
在没有 arguments 的情况下拨打 function
// Calling sayHello() call_user_func($functionName1);
你好!
使用 1 个参数调用 function
// Calling sayHelloTo("John") call_user_func($functionName2, $friend);
亲爱的约翰,你好!
使用 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);
}
考虑到此处给出的一些出色答案,有时您需要做到精确。 例如。
让我们看看它对给出的一些答案的功劳。
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.