PHP 8.1的新特性

By | 2022-02-07

枚举rfc

枚举将在 PHP 8.1 中添加!如果您不确定它们的用途,可以在此处了解它们。

添加枚举将是 PHP 的重大改进,因此我非常期待看到枚举在 PHP 8.1 中出现。为了让您快速预览它们的外观,这里有一个代码示例:

enum Status {
  case Pending;
  case Active;
  case Archived;
}

这就是它们的使用方式:

class Post
{
    public function __construct(
        private Status $status = Status::Pending;
    ) {}

    public function setStatus(Status $status): void
    {
        // …
    }
}

$post->setStatus(Status::Active);

您可以在这篇文章中找到有关如何使用枚举的深入分析。

纤维rfc

纤维——又名“绿色线程” ——是一种管理并行性的低级机制。您可能不会直接在应用程序中使用它们,但 Amphp 和 ReactPHP 等框架会大量使用它们。

这是一个使用纤维的简单示例:

$fiber = new Fiber(function (): void {
    $valueAfterResuming = Fiber::suspend('after suspending');

    // … 
});

$valueAfterSuspending = $fiber->start();

$fiber->resume('after resuming');

性能改进公关

Dmitry Stogov 对 opcache 进行了一些改进,他称之为“继承缓存”。此功能允许缓存类之间的链接,就像从 PHP 7.4 开始可以预加载链接的类一样。

Dmitry 报告说,由于这一变化,性能提高了 5% 到 8%,这是 PHP 8.1 中需要注意的一个很好的小细节。

使用字符串键解包数组 rfc

PHP 7.4已经允许数组解包,但它只适用于数字键。以前不支持字符串键的原因是因为对于如何合并数组重复项没有任何共识。RFC 通过遵循以下语义干净地解决了这个问题array_merge:

$array1 = ["a" => 1];

$array2 = ["b" => 2];

$array = ["a" => 0, ...$array1, ...$array2];

var_dump($array); // ["a" => 1, "b" => 2]

new 在初始化器中 rfc

该 RFC 允许您new在函数定义中以及在属性参数和其他地方使用关键字作为默认参数。

class MyController {
    public function __construct(
        private Logger $logger = new NullLogger(),
    ) {}
}

您可以在这篇专门的帖子中阅读有关此功能的所有信息。

只读属性rfc

类属性可以标记为只读,这意味着它们只能被写入一次。

class PostData {
    public function __construct(
        public readonly string $title,
        public readonly DateTimeImmutable $date,
    ) {}
}

在初始化后尝试更改只读属性将导致错误:

$post = new Post('Title', /* … */);

$post->title = 'Other';

Error: Cannot modify readonly property Post::$title

如果您想深入了解有关只读属性的更多信息,可以阅读我的后续帖子。

您想要了解更多有关 PHP 8.1 的内容吗?通往 PHP 8.1 之路。在接下来的 10 天内,您将每天收到一封电子邮件,其中包含 PHP 8.1 的新功能和现有功能;之后您将被自动退订,因此没有垃圾邮件或跟进。 现在订阅!

一流的可调用语法 rfc

您现在可以通过调用该可调用对象并将其…作为参数传递来从可调用对象中创建一个闭包:

function foo(int $a, int $b) { /* … */ }

$foo = foo(...);

$foo(a: 1, b: 2);

纯交叉口类型 rfc

您已经了解PHP 8.0 中的联合类型,并且交集类型是一个类似的特性。在联合类型要求输入是给定类型之一的情况下,交集类型要求输入是所有指定类型。当您使用大量接口时,交集类型特别有用:

function generateSlug(HasTitle&HasId $post) {
    return strtolower($post->getTitle()) . $post->getId();
}

如果您喜欢这种编程风格,则需要创建一个新接口Sluggable并在 中实现它$post,交集类型摆脱了这种开销。

新型never_rfc

该never类型可用于指示函数将实际停止程序流。这可以通过抛出异常、调用exit或其他类似函数来完成。

function dd(mixed $input): never
{
    // dump

    exit;
}

never不同之处void在于void仍然允许程序继续。这似乎是一个新奇的特性,但它实际上对静态分析器来说是一个非常有用的特性。

新array_is_list功能rfc

您可能不得不偶尔处理这个问题:确定数组的键是否按数字顺序排列,从索引 0 开始。就像json_encode决定一个数组是否应该编码为数组或对象一样。

PHP 8.1 添加了一个内置函数来确定数组是否是具有这些语义的列表:

$list = ["a", "b", "c"];

array_is_list($list); // true

$notAList = [1 => "a", 2 => "b", 3 => "c"];

array_is_list($notAList); // false

$alsoNotAList = ["a" => "a", "b" => "b", "c" => "c"];

array_is_list($alsoNotAList); // false

最终类常量rfc

PHP 中的类常量可以在继承期间被覆盖:

class Foo
{
    public const X = "foo";
}

class Bar extends Foo
{
    public const X = "bar";
}

从 PHP 8.1 开始,您可以将这些常量标记为final以防止出现这种情况:

class Foo
{
    final public const X = "foo";
}

class Bar extends Foo
{
    public const X = "bar";

Fatal error: Bar::X cannot override final constant Foo::X

}

新fsync功能rfc

PHP 8.1 添加了fsync和fdatasync函数来强制将文件更改同步到磁盘并确保操作系统写入缓冲区在返回之前已被刷新。

$file = fopen("sample.txt", "w");

fwrite($file, "Some content");

if (fsync($file)) {
    echo "File has been successfully persisted to disk.";
}

fclose($file);

由于磁盘同步是一种文件系统操作,因此该fsync功能仅适用于普通文件流。尝试同步非文件流将发出警告。

显式八进制整数文字表示法rfc

您现在可以使用0oand0O来表示八进制数。前面通过在数字前面加上前缀的表示法0仍然有效。

016 === 0o16; // true
016 === 0O16; // true

重大变化

虽然 PHP 8.1 是一个次要版本,但会有一些在技术上可能是重大更改的更改,并且也会被弃用。让我们一一讨论。

内部方法返回类型 rfc

升级到 PHP 8.1 时,您可能会遇到此弃用通知:

Return type should either be compatible with IteratorAggregate::getIterator(): Traversable,
or the #[ReturnTypeWillChange] attribute should be used to temporarily suppress the notice
phpunit/phpunit您可能会注意到在使用和symfony/finder其他一些流行的开源软件包时会弹出此错误。发生的事情是内部函数开始使用正确的返回类型。如果您从标准库(如IteratorAggregate)扩展一个类,您还需要添加这些返回类型。

修复很简单:如果错误发生在第三方包中,请更新您的供应商代码(其中大多数已经用最新版本修复)。如果错误发生在您的代码中,您可以添加ReturnTypeWillChange属性,在 PHP 9.0 之前抑制错误。这是扩展类的示例DateTime:

class MyDateTime extends DateTime
{
    /**
     * @return DateTime|false
     */
    #[ReturnTypeWillChange]
    public function modify(string $modifier) 
    { 
        return false; 
    }
}

或者您可以简单地添加返回类型:

class MyDateTime extends DateTime
{
    public function modify(string $modifier): DateTime|false 
    { 
        return false; 
    }
}

限制$GLOBALS使用rfc

使用方式的微小变化$GLOBALS将对所有阵列操作的性能产生重大影响。Nikita 很好地解释了RFC中的问题和解决方案。这一变化意味着某些极端情况无法再使用$GLOBALS. “不再支持将写入 $GLOBALS 视为一个整体。以下所有内容将生成编译时错误”:

$GLOBALS = [];
$GLOBALS += [];
$GLOBALS =& $x;
$x =& $GLOBALS;
unset($GLOBALS);

最重要的是,通过$GLOBALS引用传递会产生一个运行时错误:

by_ref($GLOBALS); // Run-time error
Nikita 分析了 Packagist 上排名前 2000 的软件包,仅发现 23 个案例会受到此更改的影响。我们可以得出结论,这种技术上的破坏性变化的影响将很小,这就是内部人员决定在 PHP 8.1 中添加它的原因。请记住,鉴于它在我们的代码中随处可见的积极性能影响,我们大多数人都会通过这种变化获胜。

资源到对象迁移

这些变化是将所有资源转换为专用对象的长期愿景的一部分。你可以在这里阅读更多关于它的信息。

finfo带有对象的 Fileinfo 函数

finfo_file类似和的函数finfo_open用于接受和返回资源。从 PHP 8.1 开始,它们使用finfo对象。

IMAPConnection带有对象的 IMAP 函数

就像 fileinfo 改变一样,IMAP 函数像imap_body并且imap_open不再与资源一起使用

不赞成将 null 传递给内部函数的不可为空的参数rfc

这种改变很简单:内部函数目前接受null不可为空的参数,这个 RFC 不赞成这种行为。例如,目前这是可能的:

str_contains("string", null);

在 PHP 8.1 中,这些类型的错误会抛出一个弃用警告,在 PHP 9 中它们将被转换为类型错误。

自动激活false rfc

来自 RFC:

PHP 本机允许自动激活(从错误值自动创建数组)。这个特性非常有用,并在很多 PHP 项目中使用,尤其是在变量未定义的情况下。但是,允许从 false 和 null 值创建数组有点奇怪。

您可以阅读 RFC 页面上的详细信息。总之,此行为已被弃用:

$array = false;

$array[] = 2;

Automatic conversion of false to array is deprecated

其他小改动

在每个版本中,都会对语言进行一些非常小的更改。所有这些都列在 GitHub 上的UPGRADING指南和小的弃用 RFC中,如果您想了解每一个小细节,请务必查看它。

以下是最重要变化的摘要:

MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH不再有效果
MYSQLI_STORE_RESULT_COPY_DATA不再有效果
PDO::ATTR_STRINGIFY_FETCHES现在也适用于布尔值
PDO MySQL 和 Sqlite 结果集中的整数和浮点数将在使用模拟预处理语句时使用原生 PHP 类型而不是字符串返回
htmlspecialchars和现在这样的函数htmlentities也默认转义’为'; 格式错误的 UTF-8 也将被替换为 unicode 字符,而不是导致空字符串
,hash和hash_file有hash_init一个额外的参数添加到他们称为$options,它有一个默认值,[]所以它不会影响你的代码
新的支持MurmurHash3和xxHash