REC

PHP 8.4 新功能

易航
1年前发布 /正在检测是否收录...

图片[1] - PHP 8.4 新功能 - 易航博客

PHP 8.4 的正式发布计划于下周,即 2024 年 11 月 21 日发布。

在此次发布之前,一系列预发布版本(Alpha、Beta 和候选版本)允许社区测试新功能并进行最后一刻的调整。PHP 8.4 引入了多项改进,包括用于操作数组的新功能、受其他语言启发的属性钩子以及简化的语法。让我们一起回顾一下此版本中要记住的新功能。

Property Hooks

Property Hooks 是 8.4 版中引入的主要功能之一。PHP 实现的灵感来自其他语言(如 Kotlin、C#、Swift、Javascript 或 Python)中的现有实现。让我们举几个例子来说明 Property Hooks 的用途以及如何使用它们:

<?php

declare(strict_types=1);

class Foo
{
    private string $id;

    public function getId(): string
    {
        return $this->id;
    }

    public function setId(string $id): void
    {
        $this->id = $id;
    }
}

从 PHP 8 开始,由于 Constructor Property Promotion,可以通过以下方式进行简化:

<?php
class Foo
{
    function __construct(public string $id) {}
}

在我们必须保留访问器 (getter/setter) 的情况下,我们会考虑包含业务逻辑的丰富模型,我们失去了更轻量级语法的优势。PHP 版本 8.4 和引入的 Property Hooks 修复了这个问题:

<?php
class Foo {
    public function __construct(
        public string $id {
               get {
                return '#' . $this->id;
               }
               set(string $id){
                $this->id = mb_strtoupper($id);
               }
          },
    ){}
}

乍一看,语法似乎令人困惑,但就像任何语法演变一样,随着时间的推移,您会习惯它。

Property Hooks 引入的另一种可能性是能够在 property 上定义接口。

使用这个新版本的 PHP,我们可以编写以下定义:

<?php

interface HasId {
    public string $id { get; set; }
}
    
// Les fonction fléchées peuvent être aussi utilisées pour raccourcir la syntaxe
class Foo implements HasId {
    function __construct(
        public string $id {
            get => '#' . $this->id;
            set (string $id) => $this->id = mb_strtoupper($id);
        },
    ) {}
}
    
// Le contrat d’interface est également respecté sans l’utilisation des Property Hooks en déclarant publiquement la propriété
class Bar implements HasId {
    function __construct(public string $id) {}
}

一个完整的案例

<?php

declare(strict_types=1);

interface HasId {
    public string $id { get; set; }
}

class Foo implements HasId {
    function __construct(
        public string $id {
            get => '#' . $this->id;
            set (string $id) => $this->id = mb_strtoupper($id);
        },
    ) {}
}

class Bar implements HasId {
    function __construct(public string $id) {}
}

class Baz {
    public function display(HasId $object): void
    {
        echo $object->id . PHP_EOL;
    }
    
    public function update(HasId $object, string $id): void{
        $object->id = $id;
        $this->display($object);
    }
}

$foo = new Foo(id: 'FOO');
$bar = new Bar(id: 'BAR');
$baz = new Baz();

$baz->display($foo);
$baz->update($foo, 'foo');

$baz->display($bar);
$baz->update($bar, 'bar');

设置具有非对称可见性的类属性的可见性

非对称可见性 允许您根据相关操作是读取还是写入属性,对同一属性设置不同的可见性。然后,可以定义读取访问的公共可见性和写入访问的更受限的可见性(受保护或私有)。接下来的两个类是等效的,随着非对称可见性的引入,语法更加简洁。

<?php

class Foo {
    function __construct(private string $id,) {
        //
    }
    
    public function getId(): string {
        return $this->id;
    }
}

class Bar {
 function __construct(
  public private(set) string $id,
 ) {}
}

不对称可见性附带一些规则,这些规则很容易理解:

  • 属性必须被类型化(来自 PHP 实现的约束)
  • 只关注对象属性,静态属性不能从中受益(这也是 PHP 实现产生的约束)。
  • 对于对象属性,如果该属性设置为 private(set),则不能在与当前类不同的范围内修改链接对象。但是,如果链接对象的属性被定义为 Properties,则可以对其进行修改。
  • 对于数组类型属性,如果该属性已设置为 private(set),则无法在当前类的范围之外操作数组(添加元素、删除元素等)。
  • set 的可见性不能比 get 的可见性更宽。
  • 对于类继承或接口协定,可见性不能更严格,也可以更广泛。

readonly中定义的属性(在 PHP 8.1 中引入)和 public private(set) 中定义的属性之间的差异非常小,但值得一提。上面定义的不对称可见性将具有相同的效果,只是它允许内部更改。换句话说, readonly 限制了 mutation,并且在实例化期间还具有唯一写入的效果。

管独立于 Property Hook 运行,但这两种机制可以结合使用。此处提供了这两种功能的示例。

对惰性对象的原生支持

惰性对象 是其实际实例化将被推迟到实际需要的时间(因为它们的实例化通常很昂贵)的对象。出于性能原因,它们在 Doctrine 和 Symfony 中被大量使用。

Martin Fowler 在他的理论定义中建立了四种可能的实现。其中两个是不需要修改现有对象的实现:Ghost 和 Proxy。这些是通过在 PHP Reflection API 中添加方法保留和访问的。

在这两种情况下,都会创建一个初始化函数。对于 Ghosts,该函数将直接作用于对象。对于 Proxy,它是实例化惰性对象的函数,然后将交互反馈给真实实例。

在这两种情况下,实例化机制都是通过访问真实对象的 state 来触发的:读取或写入属性、测试属性是否具有值、克隆等。可以通过特定函数对特定属性禁用此行为,在某些情况下,可以定义或参数化,例如用于调试或序列化。

由于它是为非常有限且根据定义相当抽象的用例保留的,因此我们邀请您阅读 RFC 以发现代码示例和两种不同实现的详细功能。

不带括号的类实例化

更有趣的是,这种演变通过在实例化新对象时使括号变得多余,从而减轻了语法的负担。

<?php

// Avant et toujours valide
$o = (new Operation(0))->add(10)->multiply(2);

// Depuis PHP 8.4
$o = new Operation(0)->add(10)->multiply(2);

解析 HTML5

创建了一个新的 DOM\HTMLDocument 类来允许 HTML5 解析,为了确保与 HTML4 的向后兼容性,当前类将保持不变。这两个类保持相同的 API,因此可以以相同的方式使用。只有构造逻辑已更改,并且需要使用其中一个可用的工厂。用 C 语言编写的底层库是 Lexbor

新的函数

添加了四个作用于数组的新函数,它们补充了现有函数。

array_find

array_find 将返回传递给它的回调函数的第一个匹配项

<?php

$array = ['A', 'AA', 'AAA'];
$arrayWithKeys = ['A' => 1, 'AA' => 2, 'AAA' => 3];

array_find($array, static fn(string $value): bool => strlen($value) > 2);// returns AAA

array_find($array, static fn(string $value): bool => strlen($value) > 3);// returns null

array_find($arrayWithKeys, static fn(int $value, string $key): bool => $value === strlen($key)); // returns 1

array_find_key

array_find_key 的工作方式与上一个函数相同,但返回 key 而不是 value:

<?php
$array = ['A', 'AA', 'AAA'];

$arrayWithKeys = ['A' => 1, 'AA' => 2, 'AAA' => 3];

array_find_key($array, static fn(string $value): bool => strlen($value) > 2); // returns 2

array_find_key($array, static fn(string $value): bool => strlen($value) > 3); // returns null

array_find_key($arrayWithKeys, static fn(int $value, string $key): bool => $value === strlen($key)); // returns A

array_any

如果数组中至少有一个元素与回调函数匹配,array_any 将返回布尔值 true

<?php

$array = ['A', 'AA', 'AAA'];
$arrayWithKeys = ['A' => 1, 'AA' => 2, 'AAA' => 3];

array_any($array, static fn(string $value): bool => strlen($value) > 2)); // returns true

array_any($arrayWithKeys, static fn(int $value, string $key): bool => $value === strlen($key)); // returns true

array_all

如果数组中的所有元素都与回调函数匹配,array_all 将返回布尔值为 true

<?php

$array = ['A', 'AA', 'AAA'];
$arrayWithKeys = ['A' => 1, 'AA' => 2, 'AAA' => 3];

array_all($array, static fn(string $value): bool => strlen($value) < 4)); // returns true

array_all($arrayWithKeys, static fn(int $value, string $key): bool => $value === strlen($key)); // returns true

改进和错误修复

除其他事项外,我们保留了以下更改:

  • 添加了新的多字节函数来操作字符串 mb_trim、mb_ltrim、mb_rtrim、mb_ucfirst mb_lcfirst
  • 添加了用于从时间戳创建 DateTime 对象的新函数。
  • exitdie 的元素失去了它们的地位,取而代之的是特殊功能。在不破坏向后兼容性的情况下,这允许对函数进行类似的操作,例如,更精确地键入输入参数。
  • 以下扩展正在从核心中移出以加入 PECL:Pspel、IMAP、OCI8PDO-OCI
  • 为舍入功能添加了四种新的舍入模式
  • 在 Sodium 中添加了两种新的加密算法,并升级了 OpenSSL
  • 添加了 cURL 的新选项。

完整的更新日志:https://www.php.net/ChangeLog-8.php

© 版权声明
本站用户发帖仅代表本站用户个人观点,并不代表本站赞同其观点和对其真实性负责。
转载本网站任何内容,请按照转载方式正确书写本站原文地址。
THE END
喜欢就支持一下吧
点赞 0 分享 赞赏
评论 抢沙发
取消 登录评论