PHP对象内匿名函数直接调用报错,如何实现正常调用?
PHP中stdClass对象直接调用匿名函数的解决方案
问题原因
给stdClass对象赋值匿名函数作为属性时,PHP只会把它当作普通对象属性(存储的是Closure实例),不会将其识别为类的方法。所以直接用$data->myfunc()这种方法调用语法时,PHP会认为你要调用stdClass类中未定义的myfunc方法,从而抛出致命错误。而call_user_func()可以直接传入Closure实例并执行,因此能正常运行。
解决方案
方案1:先取出匿名函数再调用
这是最直接的方式,先把存储在属性里的Closure实例取出,再执行:
<?php $data = (object) []; $data->foo = "whatever"; $data->myfunc = function () { echo "Yeah"; }; // 先取出函数再调用 $func = $data->myfunc; $func(); // 正常输出Yeah
方案2:自定义类通过魔术方法兼容直接调用
如果需要频繁实现“对象属性直接当方法调用”的需求,可以自定义类,利用__call魔术方法处理未定义的方法调用,自动匹配对应的匿名函数属性并执行:
<?php class DynamicCallableObject { private $props = []; // 处理属性赋值 public function __set($name, $value) { $this->props[$name] = $value; } // 处理属性读取 public function __get($name) { return $this->props[$name] ?? null; } // 处理未定义的方法调用 public function __call($name, $args) { if (isset($this->props[$name]) && $this->props[$name] instanceof Closure) { return call_user_func_array($this->props[$name], $args); } throw new BadMethodCallException("方法 {$name} 不存在"); } } // 使用自定义类 $data = new DynamicCallableObject(); $data->foo = "whatever"; $data->myfunc = function () { echo "Yeah"; }; $data->myfunc(); // 正常输出Yeah // 带参数的情况也支持 $data->add = function($a, $b) { return $a + $b; }; echo $data->add(2, 3); // 输出5
补充说明
如果匿名函数需要访问对象的其他属性(即需要$this指向当前对象),可以在赋值时用bindTo方法绑定上下文:
$data->myfunc = function () { echo $this->foo; }; // 绑定上下文到$data对象 $data->myfunc = $data->myfunc->bindTo($data); // 取出调用 $func = $data->myfunc; $func(); // 输出whatever
内容的提问来源于stack exchange,提问作者Martin Zvarík
相关产品推荐
相关产品推荐

