PHP 5.3.0之前版本中使用call_user_func()调用parent::与self::的问题
parent/self与call_user_func()的行为细节 Great question—let's break down exactly what was going on with these OOP keywords and callback functions back in PHP 5.2 and earlier versions.
核心问题:parent/self无上下文解析能力
在PHP 5.3.0之前,call_user_func()这类基于回调的函数完全无法识别parent::method或self::method字符串中的面向对象上下文。它不会把parent解析为当前类的父类,也不会把self解析为当前类本身,而是将这些关键字当作字面意义上的类名来处理。
示例与警告表现
看这段示例代码:
class Base { public static function greet() { echo "Hello from Base!\n"; } } class Derived extends Base { public static function greet() { // 在PHP 5.2中会触发E_STRICT警告 call_user_func('parent::greet'); } } Derived::greet();
在PHP 5.2环境下运行这段代码,会抛出一条E_STRICT级别警告,内容大致是:
Non-static method Base::greet() should not be called statically
哪怕greet()是明确声明为静态的方法,PHP依然会触发警告——因为它没有识别出parent::是合法的OOP上下文,而是把这个调用当成你试图调用一个名为parent的类的静态方法(而这个类根本不存在)。
更糟的情况:非静态方法
如果目标方法不是静态的,你会遇到更严重的错误(比如致命错误),因为PHP试图在静态上下文调用非静态方法,却没有对应的对象实例可以绑定。
5.2版本下的解决方案
要避开这些问题,你必须硬编码实际的类名,而不能使用parent或self:
// 替代parent::greet的写法 call_user_func('Base::greet'); // 替代self::greet的写法 call_user_func('Derived::greet');
这种写法虽然能运行,但非常脆弱——如果后续重命名父类,你必须手动更新所有硬编码的类名引用。
PHP 5.3的修复
PHP 5.3.0开始为回调中的这些关键字引入了正确的上下文解析。现在,子类中调用call_user_func('parent::greet')会正确解析为父类的方法,完全尊重OOP继承层级,不会再触发警告或错误。
内容的提问来源于stack exchange,提问作者user9582261

