PHP7升级PHP8.2:静态父方法解析调用子类的语法问题
问题
我需要将代码从PHP 7重构至PHP 8.2,核心需求是在子类的静态方法中调用父类同名静态方法,同时让父类方法里的get_called_class()能识别出当前调用的子类。但PHP 8.2的可调用语法发生了变更,原来的写法已被弃用,我尝试了多种方式都无法达到预期效果:
- 非静态方法可以通过Reflection结合关联对象参数实现类似逻辑,但静态方法的实现思路一直没理清
- 尝试过的写法要么返回父类名称,要么触发无限循环,要么带有弃用警告
以下是PHP 7的可用代码,以及我在PHP 8.2中的尝试:
######### # PHP 7 ######### if (preg_match('#^7#', phpversion())) { class A { public static function getClassName() { return get_called_class() . ' '. implode(' ', func_get_args()); } } class B extends A { public static function getClassName() { # 其他业务逻辑 return call_user_func_array([ 'parent', 'getClassName' ], func_get_args()); } } echo B::getClassName('-', 'Hello!') . "\n"; // 预期输出: 'B - Hello!' } ######### # PHP 8 ######### if (preg_match('#^8#', phpversion())) { class A { public static function getClassName() { return get_called_class() . ' ' . implode(' ', func_get_args()); } } class B extends A { public static function getClassName() { # 其他业务逻辑 return call_user_func_array([ static::class, 'parent::getClassName' ], func_get_args()); // 已弃用,输出正确但有警告 return (new \ReflectionMethod(parent::class, 'getClassName'))->invokeArgs(null, func_get_args()); // 返回'A - Hello!',不符合预期 return (new \ReflectionMethod(static::class, 'getClassName'))->invokeArgs(null, func_get_args()); // 无限循环,触发段错误 return call_user_func_array([ parent::class, 'getClassName' ], func_get_args()); // 返回'A - Hello!',不符合预期 return call_user_func_array([ 'parent', 'getClassName' ], func_get_args()); // 已弃用,输出正确但有警告 } } echo B::getClassName('-', 'Hello!') . "\n"; // 预期输出: 'B - Hello!' }
请问PHP 8.2中的正确语法应该是什么?
解决方案
使用forward_static_call_array()函数即可完美解决这个问题,该函数专门设计用于静态上下文的方法转发,会保留当前的调用上下文(即get_called_class()会返回实际发起调用的子类名称),且不存在弃用警告。
修改后的PHP 8.2代码如下:
if (preg_match('#^8#', phpversion())) { class A { public static function getClassName() { return get_called_class() . ' ' . implode(' ', func_get_args()); } } class B extends A { public static function getClassName() { # 其他业务逻辑 return forward_static_call_array([parent::class, 'getClassName'], func_get_args()); } } echo B::getClassName('-', 'Hello!') . "\n"; // 输出: 'B - Hello!' }
原理说明
forward_static_call_array()会沿着静态调用链传递上下文,父类方法中的get_called_class()会识别到实际调用的子类B,而不是父类A- 该函数的参数格式为
[父类类名, 方法名],第二个参数是要传递的参数数组,完全符合需求 - 相比
call_user_func_array()的旧写法,它没有弃用风险,是PHP 8+中处理静态方法转发的标准方式
内容的提问来源于stack exchange,提问作者Jomiquel
相关产品推荐
相关产品推荐

