PHP 5.6.x中父类闭包实例化子类protected构造函数的行为是Bug吗?
结论:这是PHP 5.6.x的预期行为,PHP 7.x做了针对性行为修正
这是一个典型的PHP版本间闭包访问控制逻辑差异问题,具体细节拆解如下:
PHP 5.6.x的行为逻辑
在PHP 5.6及更早版本中,闭包的访问权限完全绑定到它被定义时的类上下文:
- 当你在父类方法里定义一个闭包,这个闭包的"权限身份"就固定属于父类本身;
- 当子类调用该父类方法时,闭包尝试实例化另一个拥有
protected构造函数的子类——此时父类并没有权限访问这个子类的protected构造函数(protected成员仅允许类自身、它的直接/间接子类,以及通过该类实例访问,父类不属于目标子类的子类范畴); - 因此PHP 5.6会抛出权限错误,这是符合当时版本访问控制规则的预期结果。
PHP 7.x的行为调整
PHP 7.x对闭包的上下文绑定逻辑做了优化,让行为更符合开发者直觉:
- 当闭包在类方法内部被调用时,它会继承调用时的类上下文权限;
- 当子类调用父类方法触发闭包执行时,闭包的权限会切换到当前子类的上下文;
- 由于子类和目标子类同属父类的派生类,在子类上下文下有权访问另一个子类的
protected构造函数,因此实例化操作可以正常执行。
示例代码验证
class ParentClass { public function getCreatorClosure() { return function() { return new AnotherChild(); }; } } class CurrentChild extends ParentClass { public function createInstance() { $closure = $this->getCreatorClosure(); return $closure(); } } class AnotherChild extends ParentClass { protected function __construct() {} } // PHP 5.6执行报错:Call to protected AnotherChild::__construct() from context '' // PHP 7.x及以上正常返回AnotherChild实例 $child = new CurrentChild(); $result = $child->createInstance();
这个调整是PHP官方为了解决PHP 5.x中闭包权限绑定过于僵化的问题,让闭包的权限逻辑更贴合实际开发场景而做出的改进。
内容的提问来源于stack exchange,提问作者dgaspar
相关产品推荐
相关产品推荐

