PHP8致命错误修复:非静态方法无法静态调用的回调问题
我正在使用一款已停止维护的WordPress插件livecom,近期将网站升级至PHP8后,该插件激活时会触发WordPress致命错误,希望手动修复以继续使用。
错误信息
PHP Fatal error: Uncaught TypeError: call_user_func_array(): Argument #1 ($callback) must be a valid callback, non-static method
完整错误栈
AH01071: Got error 'PHP message: PHP Fatal error: Uncaught TypeError: call_user_func_array(): Argument #1 ($callback) must be a valid callback, non-static method OmAlb_LiveCom::plugins_loaded() cannot be called statically in /var/www/vhosts/<>/httpdocs/wp-includes/class-wp-hook.php:308
Stack trace:
#0 /var/www/vhosts/<>/httpdocs/wp-includes/class-wp-hook.php(332): WP_Hook->apply_filters()
#1 /var/www/vhosts/<>/httpdocs/wp-includes/plugin.php(517): WP_Hook->do_action()
#2 /var/www/vhosts/<>/httpdocs/wp-settings.php(480): do_action()
#3 /var/www/vhosts/<>/httpdocs/wp-config.php(101): require_once('...')
#4 /var/www/vhosts/<>/httpdocs/wp-load.php(50): require_once('...')
#5 /var/www/vhosts/<>/httpdocs/wp-blog-header.php(13): require_once('...')
#6 /var/www/vhosts/<>/httpdocs/index.php(17): require('...')
#7 {main}
thrown in /var/www/vhosts/<>/httpdocs/wp-includes/class-wp-hook.php on line 308', referer: https://<>/<>
插件中存在这类调用:
function init() { OmAlb_LiveCom_HookHandlers::add_shortcode(); }
问题根源分析
是的,这类静态调用非静态方法的代码正是错误的根源。
PHP8对类型检查和回调有效性的校验比旧版本严格得多:在PHP7及以前,静态调用非静态方法只会触发警告,但PHP8直接升级为致命错误。错误栈里明确指出OmAlb_LiveCom::plugins_loaded()这个非静态方法被静态调用,和你贴出的OmAlb_LiveCom_HookHandlers::add_shortcode()属于同一类问题——都是用::调用了没有声明为static的类方法。
修复方案
针对这类问题,有两种可靠的重构方式:
方式1:将被调用的方法声明为静态方法
找到插件中对应的OmAlb_LiveCom_HookHandlers类里的add_shortcode()方法,以及错误栈里提到的OmAlb_LiveCom类的plugins_loaded()方法,在方法前加上static关键字:
class OmAlb_LiveCom_HookHandlers { public static function add_shortcode() { // 原方法内容保持不变 } } class OmAlb_LiveCom { public static function plugins_loaded() { // 原方法内容保持不变 } }
这种方式改动最小,适合方法内部没有使用$this(即不依赖类实例属性)的情况。如果方法里有$this调用,这种方式会引发新的错误,此时需要用第二种方式。
方式2:实例化类后调用非静态方法
如果被调用的方法依赖类的实例属性(用到了$this),需要先创建类的实例,再调用方法:
function init() { $hook_handler = new OmAlb_LiveCom_HookHandlers(); $hook_handler->add_shortcode(); } // 对应错误栈里的plugins_loaded方法,找到注册钩子的地方,改成实例调用 // 比如原代码可能是: // add_action('plugins_loaded', 'OmAlb_LiveCom::plugins_loaded'); // 改成: $livecom_instance = new OmAlb_LiveCom(); add_action('plugins_loaded', [$livecom_instance, 'plugins_loaded']);
额外检查
修复完这两处后,建议全局搜索插件代码里所有::调用的方法,检查对应的方法是否被声明为static,避免遗漏其他类似问题。
内容的提问来源于stack exchange,提问作者Andrew Abbott

