Announcement

👇Official Account👇

图片

Welcome to join the group & private message

Article first/tail QR code

Skip to content

PHP 8.4 新特性详解:属性钩子、非对称可见性与更多

PHP 8.4 于 2024 年 11 月正式发布,带来了期待已久的「属性钩子」特性,以及多项语法糖和性能改进。如果你还在用 PHP 8.2 或更早版本,本文帮你快速掌握升级的理由。

一、属性钩子(Property Hooks)⭐ 重磅特性

这是 PHP 8.4 最受期待的特性,允许在属性的 get/set 上直接定义逻辑,无需编写 getter/setter 方法。

之前的写法

php
class User
{
    private string $_email = '';

    public function getEmail(): string
    {
        return strtolower($this->_email);
    }

    public function setEmail(string $value): void
    {
        if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
            throw new InvalidArgumentException("邮箱格式不正确");
        }
        $this->_email = $value;
    }
}

PHP 8.4 写法

php
class User
{
    public string $email {
        get => strtolower($this->email);
        set {
            if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
                throw new InvalidArgumentException("邮箱格式不正确");
            }
            $this->email = $value;
        }
    }
}

$user = new User();
$user->email = "Zhang@Example.COM";
echo $user->email; // zhang@example.com

只读虚拟属性

php
class Circle
{
    public function __construct(public float $radius) {}

    // 只有 get,没有 set(只读虚拟属性)
    public float $area {
        get => M_PI * $this->radius ** 2;
    }

    public float $diameter {
        get => $this->radius * 2;
        set => $this->radius = $value / 2;
    }
}

$c = new Circle(5.0);
echo $c->area;      // 78.53981...
echo $c->diameter;  // 10

$c->diameter = 20;
echo $c->radius;    // 10

二、非对称可见性(Asymmetric Visibility)

可以为属性的读和写分别设置不同的访问级别。

php
class User
{
    // public 读,private 写(只有类内部才能修改)
    public private(set) int $id;

    // public 读,protected 写
    public protected(set) string $name;

    // 构造器提升也支持
    public function __construct(
        public private(set) string $email,
        public readonly string $createdAt = ''
    ) {}
}

$user = new User('zhang@example.com');
echo $user->id;     // ✅ 可读
$user->id = 1;      // ❌ 报错:不能在类外部写入

三、new 表达式不加括号直接调用方法

php
// PHP 8.3 及之前:必须加括号
$result = (new MyClass())->method();

// PHP 8.4:可以直接调用
$result = new MyClass()->method();

// 可以链式调用
$value = new QueryBuilder()
    ->select('id', 'name')
    ->from('users')
    ->where('active', 1)
    ->limit(10)
    ->get();

四、新增数组函数

array_find() / array_find_key()

php
$users = [
    ['id' => 1, 'name' => '张三', 'role' => 'admin'],
    ['id' => 2, 'name' => '李四', 'role' => 'user'],
    ['id' => 3, 'name' => '王五', 'role' => 'admin'],
];

// 找到第一个满足条件的元素
$admin = array_find($users, fn($u) => $u['role'] === 'admin');
// ['id' => 1, 'name' => '张三', 'role' => 'admin']

// 找到第一个满足条件的 key
$key = array_find_key($users, fn($u) => $u['name'] === '李四');
// 1

// 检查是否有元素满足条件
$hasAdmin = array_any($users, fn($u) => $u['role'] === 'admin');  // true

// 检查是否所有元素都满足条件
$allActive = array_all($users, fn($u) => isset($u['id']));  // true

五、HTML5 解析支持

php
// 新增 Dom\HTMLDocument(支持 HTML5 解析)
$doc = Dom\HTMLDocument::createFromString('
    <html>
        <body>
            <h1>Hello PHP 8.4</h1>
            <p class="intro">新特性介绍</p>
        </body>
    </html>
');

$h1 = $doc->querySelector('h1');
echo $h1->textContent; // Hello PHP 8.4

$paras = $doc->querySelectorAll('p.intro');
foreach ($paras as $p) {
    echo $p->textContent;
}

六、#[\Deprecated] 弃用属性

php
class LegacyAPI
{
    #[\Deprecated(
        message: "请使用 newMethod() 代替",
        since: "2.0"
    )]
    public function oldMethod(): void
    {
        // ...
    }

    public function newMethod(): void
    {
        // ...
    }
}

$api = new LegacyAPI();
$api->oldMethod();
// Deprecated: LegacyAPI::oldMethod() is deprecated since 2.0, 请使用 newMethod() 代替

七、JIT 编译器改进

PHP 8.4 对 JIT(即时编译器)进行了重大重构,简化了配置:

ini
; PHP 8.3 及之前的复杂配置
opcache.enable=1
opcache.jit_buffer_size=64M
opcache.jit=1255

; PHP 8.4 简化配置
opcache.enable=1
opcache.jit_buffer_size=64M
opcache.jit=on  ; 直接用 on/off 即可

八、其他改进

懒对象(Lazy Objects)

php
// 懒初始化:只在首次访问时才真正创建对象
$reflector = new ReflectionClass(MyHeavyService::class);
$service = $reflector->newLazyGhost(function(MyHeavyService $obj): void {
    $obj->__construct(/* 昂贵的初始化 */);
});

// 此时 $service 还未真正初始化
// 首次访问属性时才触发初始化
echo $service->someProperty; // 触发初始化

BCMath 对象 API

php
use BcMath\Number;

$a = new Number('10.5');
$b = new Number('3.2');

$result = $a + $b;  // 使用运算符直接计算
echo $result;       // 13.7

$result = ($a * $b)->round(2);
echo $result;       // 33.6

九、升级注意事项

PHP 8.4 的破坏性变更:

php
// 1. implode() 参数顺序弃用
implode($array, $separator);   // ❌ 弃用(旧顺序)
implode($separator, $array);   // ✅ 正确

// 2. 某些 HTML 实体编码函数的默认编码改为 UTF-8
htmlspecialchars($str);  // 默认编码变为 ENT_QUOTES | ENT_SUBSTITUTE

// 3. GMP 对象不再可序列化
$n = gmp_init('12345');
serialize($n);  // ❌ 报错

总结

特性重要程度说明
属性钩子⭐⭐⭐彻底改变属性封装方式
非对称可见性⭐⭐⭐精细控制读写权限
new 不加括号⭐⭐语法糖,链式调用更流畅
array_find 等⭐⭐减少手写循环
HTML5 解析⭐⭐告别 DOMDocument 的痛苦
JIT 简化配置对普通开发者透明

PHP 8.4 的属性钩子是该版本最大的亮点,它让 PHP 的 OOP 更现代,代码更简洁。建议生产环境在 PHP 8.4.1+ 后升级。


作者:PFinal南丞 | 更新时间:2026-04-21

上次更新于: