简介
PHP 8.4 引入了许多新特性,如属性钩子(Property Hooks)、非对称可见性(Asymmetric Visibility)、#[Deprecated] 属性以及更新的 DOM API 等。本文将介绍主要变化和如何进行迁移。
参考资源
- 在线测试环境:https://onlinephp.io/
- 官方发布说明:https://www.php.net/releases/8.4/en.php
- 迁移指南:https://www.php.net/manual/en/migration84.php
- 更新详情:https://php.watch/versions/8.4
PHP 8.4 新特性
属性钩子与非对称可见性
// 属性钩子(Property Hooks)与非对称可见性(Asymmetric Visibility)
class User {
private bool $isModified = false;
public function __construct(public private(set) string $first, private string $last)
{
}
public string $fullName {
get => $this->first . " " . $this->last;
set {
[$this->first, $this->last] = explode(' ', $value, 2);
$this->isModified = true;
}
}
}
$user = new User("Ming", "Li");
echo $user->fullName; // 输出: Ming Li
$user->fullName = "Hong Xiao";
echo $user->fullName; // 输出: Hong Xiao
// 非对称可见性示例
echo $user->first; // 输出: Hong
$user->first = "Hua";
// 错误: Fatal error: Uncaught Error: Cannot modify private(set) property User::$first
属性钩子允许我们定义属性的获取和设置行为,而非对称可见性允许我们为属性设置不同的读写权限。在上例中,$first 属性可以公开读取但只能私有写入。
#[Deprecated] 属性
PHP 8.4 引入了 #[Deprecated] 属性,可以用来标记已弃用的代码:
#[Deprecated("Use newFunction() instead", since: "2.0")]
function oldFunction(): void {
// ...
}
oldFunction();
// Warning: Function oldFunction() is deprecated, Use newFunction() instead
这使得开发者可以在自己的代码库中使用与 PHP 内部相同的弃用机制。
增强的 DOM API
PHP 8.4 更新了 DOM API,提供了更现代、更易用的接口:
// 新的 DOM API 示例
$doc = \Dom\HTMLDocument::createFromString('<div><span>Hello</span></div>');
// 使用 querySelector 和 querySelectorAll
$span = $doc->querySelector('span');
echo $span->textContent; // 输出: Hello
// 使用 innerHTML/outerHTML
$div = $doc->querySelector('div');
echo $div->innerHTML; // 输出: <span>Hello</span>
$div->innerHTML = '<p>World</p>';
echo $div->outerHTML; // 输出: <div><p>World</p></div>
BCMath 的对象 API
// BCMath 的对象 API
use BcMath\Number;
$num1 = new Number('0.12345');
$num2 = new Number('2');
$result = $num1 + $num2;
echo $result; // 输出: '2.12345'
var_dump($num1 > $num2); // 输出: false
// PHP 8.4 之前的写法
$num1 = '0.12345';
$num2 = 2;
$result = bcadd($num1, $num2, 5);
echo $result; // 输出: '2.12345'
var_dump(bccomp($num1, $num2) > 0); // 输出: false
// 新增 bcdivmod() 函数 - 同时返回商和余数
[$quotient, $remainder] = bcdivmod('10', '3', 2);
echo $quotient; // 输出: 3
echo $remainder; // 输出: 1.00
PHP 8.4 为 BCMath 引入了对象 API,使用起来更加直观和面向对象。
HTTP/3 支持
PHP 8.4 的 cURL 扩展新增了 HTTP/3 支持:
$ch = curl_init('https://example.com');
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_3);
// 或强制使用 HTTP/3
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_3ONLY);
$response = curl_exec($ch);
其他新增的 cURL 选项包括:CURLOPT_PREREQFUNCTION、CURLOPT_DEBUGFUNCTION、CURLOPT_SERVER_RESPONSE_TIMEOUT、CURLOPT_TCP_KEEPCNT。
PHP 8.4 新增函数
新的数组操作函数
// array_find() - 查找第一个满足条件的元素
$animal = array_find(
['dog', 'cat', 'cow', 'duck', 'goose'],
static fn (string $value): bool => str_starts_with($value, 'c'),
);
var_dump($animal); // 输出: string(3) "cat"
// array_find_key() - 查找第一个满足条件的元素的键
$key = array_find_key(
['a' => 1, 'b' => 2, 'c' => 3],
fn($v) => $v > 1
);
var_dump($key); // 输出: string(1) "b"
// array_any() - 检查是否至少有一个元素满足条件
$result = array_any([1, 2, 3, 4], fn($n) => $n > 3); // true
// array_all() - 检查是否所有元素都满足条件
$result = array_all([1, 2, 3, 4], fn($n) => $n > 0); // true
新的字符串处理函数
// 多字节字符串修剪函数
$str = " こんにちは "; // 包含全角空格
echo mb_trim($str); // "こんにちは"
echo mb_ltrim($str); // "こんにちは "
echo mb_rtrim($str); // " こんにちは"
// 多字节首字母大小写转换
echo mb_ucfirst('ñoño'); // "Ñoño"
echo mb_lcfirst('ÑoÑo'); // "ñoÑo"
// 按字形簇拆分字符串
$chars = grapheme_str_split('👨👩👧👦');
var_dump($chars); // ['👨👩👧👦']
日期时间新方法
// 从时间戳创建 DateTime 对象
$dt = DateTime::createFromTimestamp(1704067200);
$dti = DateTimeImmutable::createFromTimestamp(1704067200.123456);
// 微秒处理
$dt = new DateTime();
echo $dt->getMicrosecond(); // 获取微秒
$dt->setMicrosecond(500000); // 设置微秒
round() 函数新舍入模式
// PHP 8.4 新增舍入模式
echo round(1.5, 0, PHP_ROUND_HALF_UP); // 2 (四舍五入)
echo round(1.5, 0, PHP_ROUND_HALF_DOWN); // 1 (五舍六入)
echo round(1.5, 0, PHP_ROUND_HALF_EVEN); // 2 (银行家舍入)
echo round(1.5, 0, PHP_ROUND_HALF_ODD); // 1 (舍入到奇数)
echo round(1.2, 0, PHP_ROUND_CEILING); // 2 (向上取整)
echo round(1.8, 0, PHP_ROUND_FLOOR); // 1 (向下取整)
echo round(-1.5, 0, PHP_ROUND_TOWARD_ZERO); // -1 (向零取整)
echo round(-1.5, 0, PHP_ROUND_AWAY_FROM_ZERO); // -2 (远离零取整)
// 注意:无效的舍入模式现在会抛出 ValueError
其他新函数
// request_parse_body() - 解析请求体
[$_POST, $_FILES] = request_parse_body();
// HTTP 响应头处理
$headers = http_get_last_response_headers(); // 获取最后一次响应头
http_clear_last_response_headers(); // 清除响应头缓存
// IANA 时区 ID
echo intltz_get_iana_id('Asia/Shanghai'); // 获取规范时区 ID
兼容性与迁移
弃用特性
隐式可空类型
// ❌ PHP 8.4 已弃用
function save(Book $book = null) {}
// ✅ 修复方法:显式声明可空类型
function save(?Book $book = null) {}
在 PHP 8.4 中,隐式可空类型已被弃用,需要使用问号(?)显式声明可空类型。
其他弃用
// ❌ E_STRICT 常量已弃用
error_reporting(E_ALL & ~E_STRICT);
// ❌ session_set_save_handler() 超过 2 个参数已弃用
session_set_save_handler($open, $close, $read, $write, $destroy, $gc);
// ✅ 使用 SessionHandlerInterface
session_set_save_handler(new MySessionHandler(), true);
// ❌ CSV 函数的 $escape 参数默认值已弃用,需显式传递
fgetcsv($handle, 0, ',', '"'); // 需要传递第四个参数
// ❌ CURLOPT_BINARYTRANSFER 已弃用(实际上从未有任何效果)
行为变化
exit/die 变为函数
exit 和 die 从语言结构变为函数,这意味着:
// 现在可以作为 callable 使用
$callback = exit(...);
// 参数类型更严格
exit(new stdClass()); // TypeError: exit(): Argument #1 ($status) must be of type string|int
常量类型变化
// PHP_ZTS 和 PHP_DEBUG 从 int 变为 bool
var_dump(PHP_ZTS); // bool(true) 或 bool(false)
var_dump(PHP_DEBUG); // bool(true) 或 bool(false)
已移除的扩展
以下扩展从 PHP 核心移至 PECL:
- Pspell - 拼写检查扩展
- IMAP - 邮件协议扩展
- OCI8 - Oracle 数据库扩展
- PDO-OCI - Oracle PDO 驱动
如需继续使用,需从 PECL 安装。
最低版本要求
- OpenSSL:最低版本 1.1.1
- libcurl:最低版本 7.61.0
- Bcrypt:密码哈希默认 cost 从 10 提升到 12
总结
PHP 8.4 带来了许多实用的新特性和改进:
主要新特性:
- 属性钩子和非对称可见性
#[Deprecated]属性- 现代化的 DOM API
- BCMath 对象 API
- HTTP/3 支持
- 新的数组和字符串函数
需要注意的变化:
- 隐式可空类型已弃用
exit/die变为函数- 部分扩展移至 PECL
- 依赖库最低版本要求提升
通过了解这些变化并遵循迁移建议,可以顺利地从 PHP 8.3 迁移到 PHP 8.4。