PHP 8 的发布带来了 JIT 编译、命名参数、联合类型等令人兴奋的新特性,但同时也对旧代码的兼容性提出了挑战。Typecho 1.3 在保持向后兼容的同时,全面适配了 PHP 8.1/8.2/8.3,本文将梳理从 PHP 7.x 迁移到 PHP 8.x 时需要注意的关键点。

一、PHP 版本要求变更

Typecho 版本最低 PHP 要求推荐 PHP 版本
1.1 及以前PHP 5.1+PHP 5.6
1.2.xPHP 5.4+ / PHP 7.0+PHP 7.4
1.3PHP 7.4+PHP 8.1+

二、常见兼容性问题与修复

2.1 count() 不再接受不可数类型

PHP 8.0 起,count(null) 会抛出 TypeError

// 错误(在 PHP 8 下崩溃)
function processItems($items) {
    if (count($items) > 0) {  // $items 可能为 null
        // ...
    }
}

// 正确
function processItems($items) {
    if (is_array($items) && count($items) > 0) {
        // ...
    }
    // 或者使用空合并
    $items = $items ?? [];
    if (count($items) > 0) {
        // ...
    }
}

2.2 htmlspecialchars() 不再接受 null

// 错误
$safe = htmlspecialchars($maybeNull);

// 正确
$safe = htmlspecialchars($maybeNull ?? '');
// 或
$safe = !empty($maybeNull) ? htmlspecialchars($maybeNull) : '';

Typecho 1.3 核心已修复此问题,但主题和插件中如果直接调用 htmlspecialchars() 仍需自查。

2.3 strtolower() 等字符串函数不接受 null

// 错误
$lower = strtolower($maybeNull);

// 正确
$lower = strtolower($maybeNull ?? '');

2.4 静态属性类型声明

PHP 8.x 对类属性类型检查更加严格:

// 错误:会被解析为浮点数,且现代 PHP 不推荐
public static $VERSION = 1.2.1;

// 正确
public static string $VERSION = '1.2.1';

2.5 命名参数与保留关键字

PHP 8.0 引入了命名参数,同时一些原本可用的标识符变为保留字。检查你的类名、方法名是否使用了 MatchEnumReadonly 等 PHP 8 关键字。

2.6 PDO 弃用警告

// PHP 8.x 中以下写法会产生弃用警告
$pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true);

// Typecho 1.3 已修复此问题

2.7 curl_close() 弃用

PHP 8.5 起 curl_close() 被标记为弃用(curl 句柄会在对象销毁时自动关闭)。Typecho 1.3 已做相应调整。

三、PHP 8 新特性的利用

3.1 联合类型(Union Types)

在自定义插件类中可以使用更精确的类型声明:

namespace TypechoPlugin\Example;

class Helper
{
    /**
     * 获取配置值
     * 
     * @param string $key
     * @param string|int|bool|null $default
     * @return string|int|bool|null
     */
    public function getConfig(string $key, string|int|bool|null $default = null): string|int|bool|null
    {
        // ...
    }
}

3.2 Nullsafe 运算符

// 旧写法
$author = null;
if ($widget && $widget->author && $widget->author->name) {
    $author = $widget->author->name;
}

// PHP 8 新写法
$author = $widget?->author?->name;

3.3 命名参数

// 更清晰的参数传递
$db->select()
    ->from('table.contents')
    ->where('type = ?', 'post')
    ->order('created', \Typecho\Db::SORT_DESC)
    ->limit(10);

3.4 属性(Attributes)

虽然 Typecho 核心暂未大量使用 Attributes,但插件开发者可以利用它们做路由标记:

#[\Attribute(\Attribute::TARGET_METHOD)]
class Route {
    public function __construct(public string $path) {}
}

四、JIT 编译与性能

PHP 8.0 引入的 JIT(Just-In-Time)编译在 CPU 密集型任务中有显著收益。对于 Typecho 这类 I/O 密集型应用,提升有限,但仍建议开启:

; php.ini
opcache.jit_buffer_size=100M
opcache.jit=tracing

五、升级检查清单

  • [ ] 服务器 PHP 版本 >= 7.4(推荐 8.1+)
  • [ ] 所有主题/插件代码已检查 count()htmlspecialchars()strtolower() 的 null 传参
  • [ ] 数据库扩展已安装(pdo_mysql / mysqli / pdo_pgsql / pdo_sqlite)
  • [ ] mbstring 或 iconv 扩展已启用
  • [ ] curl 扩展已启用
  • [ ] opcache 已配置并启用 JIT(PHP 8+)
  • [ ] 已在测试环境完成全量功能验证
  • [ ] 数据库已备份

六、总结

PHP 8 不是对 PHP 7 的破坏性革命,而是一次稳健的进化。Typecho 1.3 已经为你处理了大部分兼容细节,站长和开发者只需要关注自己编写的主题与插件中的少数几个惯用法调整,就能享受到 PHP 8 带来的性能与安全提升。


官方建议:生产环境升级前,务必在 staging 环境完成完整回归测试。