PHP中如何调用存储在类属性中的函数
PHP语法解析存在优先级:当你写出$obj->method()格式的代码时,解析器会优先查找类中定义的method成员方法,不会把method当做类属性解析。你存到$this->handler里的是属性值,不是类的原生方法,所以直接写$this->handler()会触发「方法不存在」的报错。
另外你示例里写的$route->$handler()是可变属性语法,PHP会读取当前作用域下$handler变量的值作为属性名查找,和你要访问的handler属性完全不是一个逻辑,属于语法书写错误。
按推荐优先级从高到低排列:
方案1:封装统一调用入口(工程化首选)
不要直接暴露存储回调的属性,在类中定义专门的执行方法,内部处理回调调用逻辑,同时给构造函数加callable类型校验,从源头拦截非法传入值:
class Route { protected $handler; public function __construct(callable $handler) { $this->handler = $handler; } // 支持透传参数 public function run(...$args) { return ($this->handler)(...$args); } }
调用示例:
function foo() { echo "success"; } $route = new Route('foo'); $route->run(); // 输出success
这种写法逻辑清晰、可读性强,也能避免外部随意修改存储的回调,是实际项目中最常用的实现方式。
方案2:括号包裹明确解析优先级(轻量场景适用)
如果不想额外封装方法,调用时给属性访问部分加括号,明确告诉PHP先取属性值、再执行回调,就不会触发类方法查找逻辑,兼容PHP7.0及以上版本:
class Route { public $handler; public function __construct(callable $handler) { $this->handler = $handler; } }
调用示例(类内类外逻辑一致):
function foo() { echo "success"; } $route = new Route('foo'); ($route->handler)(); // 输出success // 类内部调用同理 // ($this->handler)();
如果是PHP7以下的老版本,可以用call_user_func/call_user_func_array实现同样效果:
// 无参调用 call_user_func($this->handler); // 带参调用 call_user_func_array($this->handler, [$arg1, $arg2]);
方案3:__call魔术方法拦截(不推荐)
如果非要实现$route->handler()这种和调用类方法完全一致的写法,可以通过__call魔术方法拦截不存在的方法调用,判断对应属性是否为可调用结构后执行:
class Route { public $handler; public function __construct(callable $handler) { $this->handler = $handler; } public function __call($name, $args) { if (property_exists($this, $name) && is_callable($this->$name)) { return ($this->$name)(...$args); } throw new \BadMethodCallException("方法{$name}不存在"); } }
这种写法会隐式拦截所有未定义的方法调用,提升调试成本,除非有特殊语法需求,否则不建议使用。
你注释里写的$this->handler = fn () => $handler();是用箭头函数包装回调的写法,本质还是把闭包存在属性里,调用时同样需要遵守上面的语法规则,不能直接写$this->handler()触发调用。
内容的提问来源于stack exchange,提问作者PiwiTheKiwi

