简介

PHP 8.4 引入了许多新特性,如属性钩子(Property Hooks)、非对称可见性(Asymmetric Visibility)以及更新的 DOM API 等。本文将介绍主要变化和如何进行迁移。

参考资源

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 属性可以公开读取但只能私有写入。

可空类型解包

PHP 8.4 引入了可空类型解包操作符 ??=,可以在一行代码中解包可空值:

// 旧方式
function getUsername(?User $user): string {
    if ($user === null) {
        return 'Guest';
    }
    return $user->username;
}

// PHP 8.4 新方式
function getUsername(?User $user): string {
    return $user??->username ?? 'Guest';
}

增强的 DOM API

PHP 8.4 更新了 DOM API,提供了更现代、更易用的接口:

// 新的 DOM API 示例
$doc = new DOM\Document();
$doc->loadHTML('<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

PHP 8.4 为 BCMath 引入了对象 API,使用起来更加直观和面向对象。

PHP 8.4 新增函数

新的数组操作函数

// array_find(array $array, callable $callback): mixed - 查找第一个满足条件的元素
$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(array $array, callable $callback): mixed - 查找第一个满足条件的元素的键

// array_any(array $array, callable $callback): bool - 检查是否至少有一个元素满足回调函数条件
$result = array_any([1, 2, 3, 4], fn($n) => $n > 3); // 结果: true

// array_all(array $array, callable $callback): bool - 检查是否所有元素都满足回调函数条件
$result = array_all([1, 2, 3, 4], fn($n) => $n > 0); // 结果: true

这些新函数简化了常见的数组操作,提高了代码的可读性和简洁性。

性能优化

PHP 8.4 包含多项性能优化:

  1. 改进的 JIT 编译器:进一步优化了 Just-In-Time 编译性能
  2. 更高效的内存管理:减少了内存使用和垃圾收集开销
  3. 优化的字符串处理:提升了字符串操作的性能

在基准测试中,PHP 8.4 比 PHP 8.3 平均快 5-10%,特别是在处理复杂计算和大型数组时。

兼容性与迁移

弃用特性

隐式可空类型

// ❌ PHP 8.4 已弃用
function save(Book $book = null) {}

// ✅ 修复方法:显式声明可空类型
function save(?Book $book = null) {}

在 PHP 8.4 中,隐式可空类型已被弃用,需要使用问号(?)显式声明可空类型。

不安全的哈希函数

// ❌ PHP 8.4 中 md5() 和 sha1() 被标记为不安全

// ✅ 推荐使用更安全的哈希算法
echo hash('xxh128', 'ABC123');

在 PHP 8.4 中,md5()sha1() 函数被标记为不安全,推荐使用更安全的哈希算法。

已移除的功能

以下功能在 PHP 8.4 中被完全移除:

// ❌ 在 PHP 8.4 中不再可用
$str = create_function('$a', 'return $a + 1;'); // 已在 PHP 7.2 弃用并在 PHP 8.4 移除
$size = each($array); // 已在 PHP 7.2 弃用并在 PHP 8.4 移除

行为变化

一些函数和特性的行为发生了变化:

// PHP 8.3 及以前版本 - 隐式将数组转换为对象
$array = ['a' => 1, 'b' => 2];
$obj = (object) $array;
echo $obj->a; // 输出: 1

// PHP 8.4 - 更严格的类型检查,某些隐式转换可能失败

总结

PHP 8.4 带来了许多实用的新特性和改进,包括属性钩子、非对称可见性、BCMath 对象 API 和新的数组函数等。同时,一些旧特性也被弃用或移除,如隐式可空类型和不安全的哈希函数。通过了解这些变化和遵循迁移建议,我们可以顺利地从 PHP 8.3 迁移到 PHP 8.4,并充分利用新版本带来的性能提升和功能改进。