PHP 8.2.17面向对象子类方法签名兼容问题咨询
PHP函数与类方法的类型兼容差异分析
PHP版本:8.2.17
可正常运行的代码
class Request {} class FormRequest extends Request {} function test(Request $request) { print_r('buuu!' . get_class($request)); } test(new FormRequest());
运行结果:
buuu!FormRequest
无法运行的代码
class Request {} class FormRequest extends Request {} class Animal { public function test(Request $request) {} } class Giraffe extends Animal { public function test(FormRequest $request) { print_r('buuu!' . get_class($request)); } } (new Giraffe())->test(new FormRequest());
运行结果:
Fatal error: Declaration of Giraffe::test(FormRequest $request) must be compatible with Animal::test(Request $request) in /home/user/scripts/code.php on line 14
问题
除了面向对象编程(OOP)规则之外,这两种情况的差异是什么?
解答
- 第一个场景是独立全局函数的调用:函数的参数类型声明只是对传入值的基础类型校验,只要传入的实例是声明类型的子类(或实现类),就符合PHP的类型兼容规则。这里没有继承体系下的方法替换需求,只是单纯接收一个符合类型要求的参数,所以
FormRequest作为Request的子类,自然可以被函数正常接收。 - 第二个场景是类继承中的方法重写:子类
Giraffe重写父类Animal的test方法时,必须满足代码的可替换性——也就是任何使用父类Animal的场景,替换成子类Giraffe后必须能正常运行。如果父类方法能接受所有Request类型的实例,而子类方法只接受更具体的FormRequest,那么当用Animal类型的变量指向Giraffe实例并传入普通Request时,子类方法就无法处理,这会破坏继承的兼容性。PHP为了避免这种潜在的运行时错误,直接在语法层面禁止了这种参数类型变严格的方法重写。
内容的提问来源于stack exchange,提问作者José Victor
相关产品推荐
相关产品推荐

