PHP 8 重大变更:is_callable() 不再支持类名+非静态方法检查,强制返回 false!
最近在 PHP 8 环境下,发现 WPJAM Basic 的一个严重问题:就是后台文章和分类列表的一些操作无效了,点击保存按钮没有任何反应。经过深入调试,发现问题根源在于 PHP 8 对is_callable()
函数的行为进行了重大调整。
技术细节
在 PHP 8 之前,is_callable()
函数在检查类名与非静态方法的组合时会返回 true
,即使这种调用方式在实际执行时可能会导致问题。PHP 8 对此进行了更严格的检查,以提前发现潜在的错误调用方式,因此 is_callable()
在检查一个类名与非静态方法时将返回失败(应当检查一个类的实例)。
具体看下面这个例子就大概能够明白了:
class Test{
public function method1() { }
public static function method2() { }
}
// PHP 8 之前
var_dump(is_callable(['Test', 'method1'])); // bool(true)
var_dump(is_callable(['Test', 'method2'])); // bool(true)
// PHP 8 之后
var_dump(is_callable(['Test', 'method1'])); // bool(false)
var_dump(is_callable(['Test', 'method2'])); // bool(true)
var_dump(is_callable([new Test, 'method1'])); // bool(true)
变更原因
PHP 8 的这一变更是为了更严格地执行面向对象编程规范:
- 静态与非静态方法调用的区分:非静态方法需要类的实例才能调用,而静态方法可以直接通过类名调用。
- 提前错误检测:在 PHP 7 及以下版本,虽然
is_callable()
会返回true
,但实际以静态方式调用非静态方法时会产生警告。PHP 8 通过is_callable()
提前返回false
来更早发现问题。 - 代码质量提升:强制开发者明确方法调用的上下文,避免模糊的调用方式。
解决方案
既然知道这个原因,那就是代码要根据上下文来写了。所以如果要检查某个对象的非静态方法是否可调用,应该使用一个对象实例而不是类名。
此外,其实很多时候我们只需要检查类的方法是否存在,而不关心其可调用性(例如访问控制),那么可以简单使用 method_exists()
进行判断就好了:
if (method_exists('Test', 'method1')) {
// Do something
}