本文约 3,087 字,预计阅读 8 分钟。文中命令与配置均经过实测,可直接参考执行。
引言:报错看不懂,改起来就靠猜
升级 PHP 8 后,站点日志里会出现一堆陌生提示:Deprecated、TypeError、Fatal error。这些不是 WordPress 的问题,而是 PHP 语言本身收紧了规则。
本文不讨论抽象的语言变更,只列在 WordPress 插件主题里真实高频出现的写法,以及怎么改。
原理分析:PHP 8 的三个变化方向
- 移除:7.x 标记废弃的函数在 8.0 被彻底删除(
create_function、each、money_format等); - 收紧类型:内建函数对参数类型不再”宽容”,传 null 会报错;
- 错误升级:notice/warning 的级别提高,8.2 起动态属性会 deprecation。
理解这三点,看到报错就能大致判断属于哪一类。
保姆级实操:六类高频问题
一、create_function()(PHP 8.0 移除)
老插件里非常常见:
// 旧写法
$callback = create_function('$a', 'return $a * 2;');
add_filter('my_filter', $callback);
报错:
Fatal error: Uncaught Error: Call to undefined function create_function()
改写为匿名函数:
add_filter('my_filter', function ($a) {
return $a * 2;
});
二、each()(PHP 8.0 移除)
// 旧写法
while (list($key, $val) = each($arr)) { ... }
改写:
foreach ($arr as $key => $val) { ... }
三、动态属性(PHP 8.2 弃用,9.0 将报错)
// 旧写法
class My_Widget extends WP_Widget {
public function __construct() {
$this->some_var = 'x'; // 未在类中声明
}
}
提示:
Deprecated: Creation of dynamic property My_Widget::$some_var is deprecated
改写(在类中声明属性):
class My_Widget extends WP_Widget {
private $some_var;
public function __construct() {
$this->some_var = 'x';
}
}
如果改不动第三方代码,可临时在类上加 #[AllowDynamicProperties](PHP 8.2+),但这是权宜之计。
四、null 传给非 nullable 参数(PHP 8.1 弃用)
// 旧写法
echo trim(get_option('my_key')); // option 不存在时返回 false/null
提示:
Deprecated: Passing null to parameter #1 ($string) of type string is deprecated
改写:
echo trim((string) get_option('my_key', ''));
或先判空:
$val = get_option('my_key');
echo $val ? trim($val) : '';
五、字符串与数字比较行为变化(PHP 8.0)
// PHP 7:0 == "foo" 为 true
// PHP 8:0 == "foo" 为 false
if ($id == 'abc') { ... }
改写为显式比较:
if ((string) $id === 'abc') { ... }
在 WordPress 里常见于比较 get_post_meta() 返回值与字符串。
六、隐式浮点转换与精度(PHP 8.1 弃用)
$price = "12.5abc";
echo (int) $price; // Deprecated: Implicit conversion from float-string
改写:
$price = filter_var($price, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION);
七、WordPress 特有的常见点
wp_die()之前的mysql_*系列函数早已移除,遇到直接说明插件太老;$wpdb->escape()已废弃,用$wpdb->prepare();WP_Widget的构造函数风格:老插件用 PHP4 风格构造(类名同名方法),PHP 8 下可能告警,改为__construct()。
八、用工具批量扫描
# 安装 PHPCompatibility 标准
composer global require phpcompatibility/php-compatibility
phpcs --config-set installed_paths ~/.composer/vendor/phpcompatibility/php-compatibility
# 扫描插件目录
phpcs -p wp-content/plugins/old-plugin \
--standard=PHPCompatibility \
--runtime-set testVersion 8.2- \
--report=summary
输出会列出每个文件的每个不兼容点及行号,比手工 grep 全面得多。
常见踩坑与失败案例
- 只改报错的那一行 —— 同一个插件里可能有一百处同类写法。改一两处只是延缓,建议整体扫描或换插件。
- 案例:某站升级后后台出现几千条
Dynamic property提示,debug.log三天涨到 2GB。最后用#[AllowDynamicProperties]临时压制 + 联系插件作者更新,双管齐下。 - 直接改第三方插件文件 —— 插件更新后你的改动会被覆盖。正确做法是 fork 或提交补丁给作者,短期可通过 mu-plugins 里的兼容垫片处理。
error_reporting设置不当 —— 生产环境应关掉display_errors,否则 deprecated 会刷满页面。- 以为 deprecated 无所谓 —— 8.2 的 deprecated 在 9.0 会变成 fatal error,现在不改,两年后还得改。
总结
PHP 8 的不兼容问题集中在被移除的老函数、收紧的类型检查、动态属性三类。处理方式优先级是:先换插件/主题 > 提交补丁给作者 > 本地打补丁(要记录,更新后重打)> 临时属性抑制。工具上,phpcs + PHPCompatibility 能在升级前把问题全部暴露出来,比升级后救火划算得多。建议在每次大版本升级前跑一次扫描,把结果写进升级文档。
