搜索全站
报错排查 8 分钟阅读

PHP 8.2 与 8.3 下 WordPress 常见不兼容写法与改写方法

PHP 8.x 收紧了语法与类型检查,很多老插件主题会报错。本文列出 WordPress 生态中最常遇到的六类不兼容写法:create_function、each()、动态属性、null 传参、字符串数字比较、隐式浮点转换,每类给出报错示例与可直接套用的改写代码。

U
UFO_PF 2024-07-03 · 阅读 8 分钟
PH 报错排查
阅读提示
本文约 3,087 字,预计阅读 8 分钟。文中命令与配置均经过实测,可直接参考执行。

引言:报错看不懂,改起来就靠猜

升级 PHP 8 后,站点日志里会出现一堆陌生提示:Deprecated、TypeError、Fatal error。这些不是 WordPress 的问题,而是 PHP 语言本身收紧了规则。

本文不讨论抽象的语言变更,只列在 WordPress 插件主题里真实高频出现的写法,以及怎么改。

原理分析:PHP 8 的三个变化方向

  1. 移除:7.x 标记废弃的函数在 8.0 被彻底删除(create_function、each、money_format 等);
  2. 收紧类型:内建函数对参数类型不再”宽容”,传 null 会报错;
  3. 错误升级: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 全面得多。

常见踩坑与失败案例

  1. 只改报错的那一行 —— 同一个插件里可能有一百处同类写法。改一两处只是延缓,建议整体扫描或换插件。
  2. 案例:某站升级后后台出现几千条 Dynamic property 提示,debug.log 三天涨到 2GB。最后用 #[AllowDynamicProperties] 临时压制 + 联系插件作者更新,双管齐下。
  3. 直接改第三方插件文件 —— 插件更新后你的改动会被覆盖。正确做法是 fork 或提交补丁给作者,短期可通过 mu-plugins 里的兼容垫片处理。
  4. error_reporting 设置不当 —— 生产环境应关掉 display_errors,否则 deprecated 会刷满页面。
  5. 以为 deprecated 无所谓 —— 8.2 的 deprecated 在 9.0 会变成 fatal error,现在不改,两年后还得改。

总结

PHP 8 的不兼容问题集中在被移除的老函数、收紧的类型检查、动态属性三类。处理方式优先级是:先换插件/主题 > 提交补丁给作者 > 本地打补丁(要记录,更新后重打)> 临时属性抑制。工具上,phpcs + PHPCompatibility 能在升级前把问题全部暴露出来,比升级后救火划算得多。建议在每次大版本升级前跑一次扫描,把结果写进升级文档。

U
UFO_PF作者

专注 WordPress 生态的实战作者,内容以「可复制、可验证」为第一原则。

留下你的想法

邮箱地址不会被公开。带 * 的为必填项。