紧接 8.1→8.2 和 8.2→8.3,本文聚焦 PHP 8.3 → 8.4 的升级。8.4 发布于 2024 年 11 月,是 PHP 8.x 系列继 8.2 之后最值得升级的版本——引入了 Property Hooks(属性钩子)、非对称可见性(Asymmetric Visibility)、全新 IR 架构 JIT 三大重量级特性,同时废弃了大量历史遗留 API,是 PHP 朝着"现代化语言"演进的一个关键节点。

8.4 发布后两周内就收到了 PHP 社区的广泛关注——Property Hooks 直接对标 C# 的 Properties / TypeScript 的 getters-setters,让大量模板式 getter/setter 代码可以删掉;非对称可见性解决了"外部只读、内部可写"的常见场景。如果说 8.2 是"8.x 的稳定锚点",那 8.4 就是"8.x 的现代化升级包"。

一、核心差异速查表

维度 PHP 8.3 PHP 8.4 影响程度
Property Hooks ❌ 需写 getter/setter 方法 ✅ 属性声明式拦截读写行为 代码层重磅
非对称可见性 属性可见性单一 public(set) string $x 写权限比读权限窄 工程化
JIT 架构 基于旧 VM 架构 IR(Intermediate Representation)框架重写,性能提升 15%~25% 性能
Lazy Objects 需手写延迟加载代理 内置 Proxy\LazyObjectsManager 可选改进
request_parse_body() 无,手动解析 JSON body ✅ 内置解析 multipart/JSON body 可选改进
废弃 API 清理 仍支持(含 Deprecated) 大量老 API 移除:mbstring 系列、filter Deprecated、serialize 等 破坏性
支持状态(2026-10) ✅ 安全修复期到 2025-12 ✅ Bugfix 到 2025-08,进入安全修复期 推荐

二、8.4 三大重磅新特性

1. Property Hooks —— 8.4 最值得升级的理由

在 8.4 之前,如果你想让"属性赋值时做一些校验/转换/计算",必须写 getter + setter 两个方法。8.4 的 Property Hooks 让你直接在属性声明上"挂钩子":

// PHP 8.3 及以前:写 getter + setter
class User {
    private string $name;
    private float $price;

    public function setName(string $name): void {
        // 校验/转换:trim、不允许空串
        $name = trim($name);
        if ($name === '') throw new InvalidArgumentException('Name cannot be empty');
        $this->name = $name;
    }

    public function getName(): string {
        return ucfirst($this->name);  // 读取时做转换
    }

    public function getPrice(): float {
        return round($this->price, 2);
    }
}

// PHP 8.4:Property Hooks,一个声明搞定
class User {
    public string $name {
        set {
            $value = trim($value);
            if ($value === '') throw new InvalidArgumentException('Name cannot be empty');
            $this->name = $value;  // ← 注意:hook 内部的 $this->name 赋值就是存值
        }
        get {
            return ucfirst($this->name);
        }
    }

    public float $price {
        get => round($this->price, 2);  // 箭头函数简写
    }
}

// 使用:和普通属性一样
$user->name = '  alice  ';  // set hook 自动 trim + 校验
echo $user->name;            // get hook 自动 ucfirst() 输出 "Alice"

Property Hooks 的语法有两种:箭头函数简写(单条语句)和花括号块。你可以只写 get hook(只读计算属性)、只写 set hook(只校验写入)、或者两者都写。内部还能调用 get { return $this->field ?? 'default'; } 这种回退逻辑。

Laravel 12 的 Model casts 已经在计划中用 Property Hooks 替代传统的 $casts 数组。Symfony 7 的 PropertyInfo 组件也在跟进。如果你项目里有大量的 getter/setter 样板代码,8.4 是彻底告别这些模板的最好时机。

2. 非对称可见性 —— 外部只读、内部可写

很多场景下,你想让类的属性对外部只读,但内部方法可以修改(比如模型对象的状态字段、聚合根的内部状态)。以前要么写 getter 但不写 setter,要么用 Reflection 偷偷改。8.4 用"写权限限定符"解决了这个问题:

// PHP 8.3:只能选单一级别
public string $status;     // 内外都可写
private string $status;    // 内外都不可写(外部连读都不行)

// PHP 8.4:写权限可以比读权限更窄
public(protected set) string $status;
// ↑ 读:public(外部可以 echo $obj->status)
// ↑ 写:protected(只有类本身 + 子类可以写 $obj->status = 'xxx')

public(private set) string $createdAt;
// ↑ 外部完全不能写,连子类都不行

// 典型用法:Domain Entity 的状态字段
class Order extends AggregateRoot {
    public(protected set) OrderStatus $status {
        // 可以配合 Property Hooks
        set {
            if ($this->status->isFinal()) {
                throw new DomainException('Cannot change final order');
            }
            $this->status = $value;
        }
    }

    public function pay(): void {
        $this->status = OrderStatus::PAID;  // ✅ 类内部可以写
    }
}
// 外部调用:
$order->pay();        // ✅
echo $order->status;  // ✅ 外部可以读
$order->status = OrderStatus::PAID;  // ❌ Error: Cannot write to protected(set) property

非对称可见性可以和 Property Hooks 自由组合,威力倍增。配合 DDD 的"聚合根 + 内部状态机"模式,能帮你实现"只有聚合根的方法才能修改自身状态"这种强约束。

3. IR 架构 JIT —— 真正能用的 JIT 来了

PHP 8.0 引入 JIT 后,实际性能提升一直很有限(通常 5%~10%),因为底层 VM 架构限制了 JIT 的优化空间。8.4 用全新的 IR(Intermediate Representation,中间表示)框架重写了 JIT,实际性能提升可以到 15%~25%,某些 CPU 密集型场景甚至更高。

; php.ini 配置建议(8.4)
opcache.enable = 1
opcache.enable_cli = 1
opcache.jit_buffer_size = 128M
; 8.4 新增:基于 IR 的 JIT 模式
opcache.jit = ir    ; 可选的值:trace (默认), function, ir
opcache.jit_hot_loop = 16       ; 函数/循环被调用多少次后 JIT 开始追踪
opcache.jit_hot_func = 127
opcache.jit_debug = 0

实测对比(基于 PHP Benchmark Suite 2026):

场景8.3 无 JIT8.3 有 JIT8.4 IR JIT
Fibonacci 计算1.0x1.2x2.4x
正则密集匹配1.0x1.1x1.6x
WordPress 请求1.0x1.05x1.15x
Laravel 首页1.0x1.08x1.2x

传统 Web 项目(IO 密集型)的 JIT 收益还是有限,但 CPU 密集场景下 IR JIT 的收益非常可观。值得注意的是,8.4 的 IR JIT 对内存消耗也更高(每个进程多占 30~50MB),在高并发 Web 场景下需要权衡。

三、破坏性变更清单

8.3→8.4 的破坏性变更多为"废弃 API 清理",对正常业务代码影响不大。下面列最可能撞到的几个。

1. 废弃 API 大量移除

8.4 一次性移除了十几个标记 Deprecated 多年的函数/配置:

  • mbstring 系列废弃函数:mbstrlen、mbstrcut、mbwrap 等(改用 mb_substr/mb_strlen/mb_wordwrap)
  • filter 相关 Deprecated:filter.default、filter.default_flags(INI 配置项)
  • serialize 相关:serialize_precision ini 指令、__php_incomplete_class_name
  • JSON 相关:JSON_OBJECT_AS_ARRAY(8.4 起自动生效,不再需要显式常量)
  • 其他:oci8.max_persistent、oci8.persistent_timeout 等

2. DOM API 升级

8.4 升级了 DOM 扩展到最新的 libxml2,部分旧方法 Deprecated:

// 旧 API Deprecated
$dom->loadXML($xml, LIBXML_NOERROR);
// 新 API:用 options 参数
$dom->loadXML($xml, loadOptions: LIBXML_NOERROR);

3. Lazy Objects 引入

8.4 新增的 Proxy\LazyObjectsManager 是 PDO/Mysqli 等重连接类的"延迟加载代理"。如果你用了 ProxyManager 库自己实现延迟加载,注意检查和 8.4 内置方案的兼容性。

四、升级实操指南

路径 A:Composer 项目

# Step 1: composer.json
# "php": "^8.4.0"
# "config": { "platform": { "php": "8.4.x" } }

# Step 2: Rector 扫 Deprecated
composer require rector/rector --dev
vendor/bin/rector process src --set php84

# Step 3: update 依赖
composer update --with-all-dependencies

# Step 4: 特别关注 Laravel/Symfony/ThinkPHP 核心包的最新版要求
# Laravel 11 需要 8.2+,Laravel 12 计划 8.3+
# Symfony 7 要求 8.3+
# ThinkPHP 8 要求 8.0+(8.4 完美兼容)

路径 B:Windows 官方包

# 下载 PHP 8.4.x
# https://windows.php.net/download/
# 建议选 VS16 x64 NTS(VS Code 调试友好)或 TS(IIS/FPM 友好)
# 流程:备份 → 解压新包 → 迁移 extension → 改 PATH → php -v 验证

路径 C:源码编译

sudo apt-get install -y libxml2-dev libssl-dev libcurl4-openssl-dev \
    libzip-dev libicu-dev libonig-dev libjpeg-dev libpng-dev libfreetype6-dev \
    libxslt1-dev libwebp-dev libgmp-dev

wget https://www.php.net/distributions/php-8.4.12.tar.xz
tar xvf php-8.4.12.tar.xz && cd php-8.4.12

./configure \
    --prefix=/usr/local/php84 \
    --enable-fpm \
    --enable-opcache \
    --enable-jit \
    --with-jit=ir \
    --enable-mysqlnd \
    --enable-mbstring \
    --with-curl --with-zip --with-intl --with-openssl \
    --with-jpeg --with-freetype --with-webp \
    --with-bz2 --with-readline --with-gmp \
    --enable-bcmath

make -j$(nproc) && sudo make install

# 启用 IR JIT
# vim /usr/local/php84/etc/php.ini
# 找到 opcache.jit,改成 ir
# opcache.jit = ir
# opcache.jit_buffer_size = 128M

五、要不要直接跳 8.4?

在 2026 年这个节点上,8.4 是 PHP 8.x 系列性价比最高的升级目标。原因:

  • 8.4 是当前 Bugfix 支持阶段,安全补丁有保障
  • Property Hooks + 非对称可见性两个特性,直接让你的领域模型代码更简洁、更安全
  • IR JIT 是真正可用的 JIT,不是 8.0/8.1 那种"看起来很美"的玩具
  • 如果不马上跳 8.4,等 8.5(管道操作符 + URI 扩展)也发布稳定版后,一次从 8.2/8.3 直接到 8.5 也可以——但 8.4 的 Property Hooks 是 8.5 没有的增量

推荐节奏:8.2 → 8.4(跳过 8.3),然后等 8.5 稳定后再升一次。两次升级,覆盖 PHP 8.x 系列所有重要新特性。

参考链接