前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >PHP 8.4 新功能

PHP 8.4 新功能

作者头像
Tinywan
发布2024-11-21 18:46:47
发布2024-11-21 18:46:47
39800
代码可运行
举报
文章被收录于专栏:开源技术小栈
运行总次数:0
代码可运行

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 的用途以及如何使用它们:

代码语言:javascript
代码运行次数:0
复制
<?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,可以通过以下方式进行简化:

代码语言:javascript
代码运行次数:0
复制
<?php

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

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

代码语言:javascript
代码运行次数:0
复制
<?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,我们可以编写以下定义:

代码语言:javascript
代码运行次数:0
复制
<?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) {}
}

一个完整的案例

代码语言:javascript
代码运行次数:0
复制
<?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');

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

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

代码语言:javascript
代码运行次数:0
复制
<?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 以发现代码示例和两种不同实现的详细功能。

不带括号的类实例化

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

代码语言:javascript
代码运行次数:0
复制
<?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 将返回传递给它的回调函数的第一个匹配项

代码语言:javascript
代码运行次数:0
复制
<?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:

代码语言:javascript
代码运行次数:0
复制
<?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

代码语言:javascript
代码运行次数:0
复制
<?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

代码语言:javascript
代码运行次数:0
复制
<?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

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-11-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 开源技术小栈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Property Hooks
  • 设置具有非对称可见性的类属性的可见性
  • 对惰性对象的原生支持
  • 不带括号的类实例化
  • 解析 HTML5
  • 新的函数
    • array_find
    • array_find_key
    • array_any
    • array_all
  • 改进和错误修复
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档