紧接 8.1→8.2、8.2→8.3、8.3→8.4,本文聚焦 PHP 8.4 → 8.5 的升级。8.5 发布于 2025 年 11 月 20 日,标题是"Smarter, Faster, Built for Tomorrow"——这是 PHP 8.x 系列的最后一个大版本。PHP 官方已经公布 8.5 之后将进入 PHP 9 开发周期,8.6 预计 2026 年底发布,8.x 系列将在 2027 年 11 月完全 EOL。

8.5 有三个值得关注的新特性:管道操作符 |>(期待多年的特性终于落地)、URI 扩展(原生 URL 解析)、clone with(一行克隆并修改属性)。前两个是真正会改变代码写法的特性,第三个是 DDD Value Object 场景下的完美语法糖。另外还有 #[\NoDiscard] Attribute 和 cURL 持久化共享句柄两个"运维安全"类改进。

一、核心差异速查表

维度 PHP 8.4 PHP 8.5 影响程度
管道操作符 ❌ 靠函数嵌套或 array_reduce 实现 ✅ |> 原生,从左到右传递 语法层重磅
URI 扩展 ❌ 需用 parse_url + 手动拼接 ✅ 原生 Uri\Uri 对象,RFC 3986/WHATWG 标准 代码层
clone with ❌ 需写 with 方法 ✅ clone $obj with (x: newVal, y: 'val') 可选改进
#[\NoDiscard] ❌ 无 ✅ 标记函数返回值不可丢弃,遗漏时告警 安全/质量
cURL 持久化句柄 ❌ 每次 curl_init 都是新连接 ✅ CurlShareHandle 跨请求共享连接池 性能
支持状态(2026-10) ✅ Bugfix 到 2025-08 ✅ 刚发布,Bugfix 到 2026-11 推荐升级
💡 PHP 版本演进里程碑:从 2020 年 11 月 PHP 8.0 发布到 2025 年 11 月 PHP 8.5 发布,PHP 8.x 系列走完了整整 5 年。下一轮 PHP 9 预计 2026 年 Q4 发布,将带来命名空间自动导入、新类型系统等重大变革。8.5 是这一轮"现代化 PHP"的收关之作,值得认真升级。

二、8.5 三大新特性详解

1. 管道操作符 |> —— PHP 开发者期待了整整十年

管道操作符在 Elixir、F#、Rust、TypeScript 等语言里都有,PHP 社区从 2016 年就开始讨论,2025 年终于正式进入 8.5。它的作用是把"函数嵌套"改成"从左到右顺读":

// PHP 8.4 及以前:函数嵌套,读起来反人类
$result = json_encode(
    array_map(fn($user) => ['name' => ucfirst($user['name']), 'email' => $user['email']],
        array_filter($users, fn($u) => $u['status'] === 'active')
    ),
    JSON_PRETTY_PRINT
);

// PHP 8.5:管道操作符,从左到右顺读
$result = $users
    |> array_filter(fn($u) => $u['status'] === 'active')
    |> array_map(fn($user) => ['name' => ucfirst($user['name']), 'email' => $user['email']])
    |> json_encode(..., JSON_PRETTY_PRINT);

// 更简洁的写法
$result = $users
    |> array_filter(..., ...)
    |> array_map(fn($u) => ['name' => ucfirst($u['name']), 'email' => $u['email']], ...)
    |> json_encode(..., JSON_PRETTY_PRINT);

管道操作符的规则很简单:$value |> callable 等价于 callable($value)——上一步的输出自动作为下一步 callable 的第一个参数。如果你的 callable 第一个参数就是要处理的值,直接套就行;如果不是,用占位符或者闭包调整:

// 直接套:strlen 的第一个参数就是值
$len = 'hello' |> strlen;    // 5

// 不是第一个参数的情况:用闭包或 8.5 引入的 partial application
$result = 'a/b/c' |> str_replace('/', '-', ...);
// 这里 str_replace('/','-',$value),管道注入 $value 为第三个参数

// 也可以这样写(更明确)
$result = 'a/b/c' |> str_replace(...);  // ❌ 不对,管道注入的是第一个参数
// 要用命名参数或闭包
$result = 'a/b/c' |> fn($s) => str_replace('/', '-', $s);  // ✅
// 或者用 partial application
$result = 'a/b/c' |> str_replace('/', '-', ...);

管道操作符还能配合类方法调用:

$report = $db->query('SELECT * FROM orders')
    |> ResultSet::from(...)
    |> ->groupBy('customer_id')
    |> ->total('amount')
    |> ->formatAsCurrency()
    |> report_make(..., ...);

管道操作符不是"必须用"——它是一个让代码更易读的工具。喜欢函数式风格的人会大量用;习惯 OOP 的人可以按需用在数据转换链路上。

2. URI 扩展 —— PHP 终于有原生 URL 解析了

在 8.5 之前,PHP 开发者要处理 URL,只能靠 parse_url()(简单够用但粗糙)或者自己实现 RFC 3986 兼容的解析器(复杂易错)。8.5 终于加了一个原生的 Uri 扩展,提供完整的 URI 对象模型:

// PHP 8.5 原生 URI
use Uri\Uri;

$uri = Uri::from('https://api.example.com:8443/v2/users?id=123#profile');

echo $uri->scheme;   // "https"
echo $uri->host;     // "api.example.com"
echo $uri->port;     // 8443
echo $uri->path;     // "/v2/users"
echo $uri->query;    // "id=123"
echo $uri->fragment; // "profile"
echo $uri->userinfo; // ""

// 可以修改并生成新 URI(不可变)
$newUri = $uri->withPath('/v3/users')->withQueryString(['id' => '456', 'sort' => 'desc']);

// WHATWG URL 标准兼容(对 web 开发重要)
$whatwg = Uri::from('http://example.com/ foo bar ');
// WHATWG 模式下空格自动转成 %20,这和浏览器 JS 的 URL 解析一致

URI 扩展的底层用的是 liburiparser(RFC 3986/3987 标准实现),也支持 WHATWG URL API 模式。对 PHP 开发者来说,这意味着终于不用自己写或依赖第三方包来做 URL 拼接/规范化/解析了。

3. clone with —— DDD Value Object 的完美语法糖

结合 readonly class,clone with 让"不可变对象修改属性返回新对象"这种 DDD 常见模式变得极简:

// PHP 8.4:手写 with 方法
readonly class Money {
    public function __construct(
        public float $amount,
        public string $currency,
    ) {}

    public function withAmount(float $newAmount): self {
        return new self($newAmount, $this->currency);  // ← 每次都要写这个
    }
}

// PHP 8.5:clone with 语法
readonly class Money {
    public function __construct(
        public float $amount,
        public string $currency,
    ) {}
    // 不需要写 with 方法了!
}

$money = new Money(100, 'CNY');
$newMoney = clone $money with (amount: 200);
// $money 还是 100 元(不可变)
// $newMoney 是 200 元的新实例

clone with 可以一次改多个属性:clone $user with (name: 'Alice', email: 'a@b.com')。和 readonly class + Property Hooks 配合,就是完整的 DDD Value Type 语言级支持。

三、其他值得关注的改进

#[\NoDiscard] Attribute —— 安全网一样的 Attribute

#[NoDiscard]
function generateToken(): string {
    return bin2hex(random_bytes(32));
}

// 调用方忘记用返回值:
generateToken();  // ⚠️ Deprecated 警告:Discarded return value of function generateToken()

// 这个 Attribute 专门标记那些返回值"必须被使用"的函数
// 比如 generateToken 返回的 token 不用就丢了(严重 bug)
// 或者 throw_if 这种返回值有语义的 helper 函数

cURL 持久化共享句柄

// PHP 8.4:每次 curl_init 都建立新连接
$ch1 = curl_init('https://api.example.com/a');
$ch2 = curl_init('https://api.example.com/b');
// → 两次完整的 SSL/TLS 握手

// PHP 8.5:共享句柄,连接池复用
$share = curl_share_init();
curl_share_setopt($share, CURLSHOPT_SHARE, CURL_LOCK_DATA_CONNECT);
curl_share_setopt($share, CURLSHOPT_SHARE, CURL_LOCK_DATA_SSL_SESSION);

$ch1 = curl_init('https://api.example.com/a');
curl_setopt($ch1, CURLOPT_SHARE, $share);

$ch2 = curl_init('https://api.example.com/b');
curl_setopt($ch2, CURLOPT_SHARE, $share);
// → 第二次请求直接复用 SSL session + 连接池,延迟减半

curl_close($ch1); curl_close($ch2);
curl_share_close($share);

在批量请求或高频 API 调用场景下,持久化句柄可以把 SSL 握手开销减半。但注意多线程/多进程场景下要加锁,否则会有竞态。

四、破坏性变更清单

8.4→8.5 的破坏性变更同样不多(PHP 官方对 minor 版本升级的定性就是"大部分项目应该可以不做修改就能运行")。主要集中在:

  • 某些 hash_* 系列函数在 8.5 移除了对已经不再安全的算法的支持(如 salsa20)
  • date_create_from_format 在某些 edge case 下行为调整
  • libxml 扩展默认启用 stricter 的错误报告

建议还是跑一次 Rector php85 规则集,自动扫一遍 Deprecated。

五、升级实操指南

路径 A:Composer 项目

# composer.json:
# "php": "^8.5.0"
# "config": { "platform": { "php": "8.5.x" } }

# Rector 扫 Deprecated
composer require rector/rector --dev
vendor/bin/rector process src --set php85

# update
composer update --with-all-dependencies
# 注意:8.5 刚发布,部分包可能还没声明支持 ^8.5
# 如果遇到 composer constraint 冲突,用 composer update --ignore-platform-reqs 先装起来测
# 然后在 issue 里催包作者更新

路径 B:Windows 官方包

# PHP 8.5 官方包已在 2025-11-20 发布
# https://windows.php.net/download/
# 选 VS16 x64 NTS 或 TS

# 流程不变:
# 备份旧 php 目录 → 解压新包 → php.ini 同步配置 → 迁移 extension → 改 PATH → php -v 验证
# 注意 8.5 的 extension 版本和 8.4 不同,旧的 .dll 可能不兼容,需要下载 8.5 对应版本

路径 C:源码编译

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

# 8.5 新增了 liburiparser 依赖(URI 扩展)
sudo apt-get install -y liburiparser-dev 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

./configure \
    --prefix=/usr/local/php85 \
    --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 \
    --enable-uri   # ← 8.5 新增!启用 URI 扩展

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

六、PHP 8.x 系列总结

到此为止,PHP 8.0→8.5 六个版本的升级指南全部完成。这里做一张对照表,方便你规划自己的升级路线:

版本发布重磅特性破坏性变更数量生态状态(2026-10)
8.02020-11属性提升/union/nullsafe/match/JIT★★★★★❌ 完全 EOL
8.12021-11枚举/readonly/Fiber★❌ 完全 EOL
8.22022-12readonly class/first-class callable/动态属性 Error★★★❌ 完全 EOL
8.32023-11类型化常量/Override/Trait 可见性★⚠️ 仅剩安全修复
8.42024-11Property Hooks/非对称可见性/IR JIT★★⚠️ 刚进安全修复期
8.52025-11管道操作符/URI 扩展/clone with★✅ Bugfix 支持中

推荐升级路线(2026 年版):

  • 当前还在 7.4/8.0/8.1:先升到 8.2(解决动态属性 Error),再直接升 8.5
  • 当前在 8.2/8.3:直接跳到 8.5(8.4 的 Property Hooks 值得单独看,但可以跳过)
  • 当前在 8.4:升到 8.5,拿到管道操作符 + URI 扩展

PHP 8.x 系列还有大概一年半的安全支持窗口(到 2027 中后),之后就进入 PHP 9 时代。但对于大多数项目来说,8.5 已经是一个稳定、现代、功能完整的版本,可以长期跑下去。

参考链接