首页 / 教程资源

PHP 8.2的新特性

发布时间:2023-04-01 04:14:30

PHP 8.2 is released on December 8, 2022. In this post, we'll go through all features, performance improvements, changes and deprecations one by one.

PHP 8.2发布于2022年12月8日。在这篇文章中,我们将逐一介绍所有的特性、性能改进、更改和废弃。

Readonly classes 只读课程 rfc

Readonly properties were introduced in PHP 8.1. This RFC builds on top of them, and adds syntactic sugar to make all class properties readonly at once. Instead of writing this:

PHP 8.1中引入了只读属性。这个 RFC 构建在它们之上,并添加语法糖使所有类属性一次只读。而不是这样写:

class Post{    public function __construct(        public readonly string $title,         public readonly Author $author,        public readonly string $body,        public readonly DateTime $publishedAt,    ) {}}

You can now write this:

你现在可以这样写:

readonly class Post{    public function __construct(        public string $title,         public Author $author,        public string $body,        public DateTime $publishedAt,    ) {}}

Functionally, making a class readonly is entirely the same as making every property readonly; but it will also prevent dynamic properties being added on a class:

在功能上,使一个类只读与使每个属性都只读完全相同; 但是它也会阻止动态属性被添加到一个类上:

$post = new Post(/* … */);
$post->unknown = 'wrong';
Uncaught Error: Cannot create dynamic property Post::$unknown

Note that you can only extend from readonly classes if the child class is readonly as well.

注意,只有当子类也是只读类时,才能从只读类进行扩展。

PHP has changed quite a lot, and readonly classes are a welcome addition. You can take a look at my video about PHP's evolution if you want to as well:

PHP 已经发生了很大的变化,只读类是一个受欢迎的补充。

Deprecate dynamic properties 不推荐使用动态属性 rfc

I'd say this is a change for the better, but it will hurt a little bit. Dynamic properties are deprecated in PHP 8.2, and will throw an ErrorException in PHP 9.0:

我想说这是一个更好的变化,但它会有点伤害。在 PHP 8.2中不推荐使用动态属性,在 PHP 9.0中将抛出一个 ErrorException:

class Post{    public string $title;}
// …
$post->name = 'Name';

Keep in mind that classes implementing __get and __set will still work as intended:

请记住,实现 _ _ get 和 _ _ set 的类仍将按预期工作:

class Post{    private array $properties = [];        public function __set(string $name, mixed $value): void{        $this->properties[$name] = $value;    }}
// …
$post->name = 'Name';

New random extension 新的随机扩展 rfc

PHP 8.2 adds a new random number generator that fixes a lot of problems with the previous one: it’s more performant, more secure, it’s easier to maintain, and doesn’t rely on global state; eliminating a range of difficult to detect bugs when using PHP’s random functions.

PHP 8.2增加了一个新的随机数生成器,修复了前一个的许多问题: 它更加性能更好,更加安全,更容易维护,并且不依赖于全局状态; 消除了一系列在使用 PHP 的随机函数时难以检测到的错误。

There’s a new class called Randomizer, which accepts a randomizer engine. Now you can change that engine, depending on your needs. For example, to differentiate between a production and testing environment.

有一个新的类叫做随机发生器,它接受一个随机发生器引擎。现在您可以根据需要更换引擎。例如,区分生产环境和测试环境。

$rng = $is_production    ? new Random\Engine\Secure()    : new Random\Engine\Mt19937(1234); $randomizer = new Random\Randomizer($rng);$randomizer->shuffleString('foobar');

nulltrue, and 还有 false as standalone types 作为独立的类型 rfc

PHP 8.2 adds three new types — or something that looks like it. We'll avoid going down the rabbit hole of type safety in this post, but technically nulltrue, and false could be considered valid types on their own. Common examples are PHP's built-in functions, where false is used as the return type for when an error occurs. For example in file_get_contents:

PHP 8.2添加了三种新类型ーー或者类似的东西。在这篇文章中,我们将避免陷入类型安全的兔子洞,但是从技术上讲,null、 true 和 false 本身可以被认为是有效的类型。常见的例子是 PHP 的内置函数,其中 false 用作发生错误时的返回类型。例如,在 file _ get _ content 中:

file_get_contents(/* … */): string|false

Before PHP 8.2, you could already use false together with other types as a union; but now it can be used as a standalone type as well:

在 PHP 8.2之前,您已经可以将 false 与其他类型一起作为联合使用; 但是现在它也可以作为独立类型使用:

function alwaysFalse(): false{    return false;}

The same now also goes for true and null.

现在对 true 和 null 也是如此。

#Disjunctive Normal Form Types 析取范式 rfc

DNF types allow us to combine union and intersection types, following a strict rule: when combining union and intersection types, intersection types must be grouped with brackets. In practice, that looks like this:

DNF 类型允许我们组合联合类型和交叉类型,遵循一个严格的规则: 当组合联合类型和交叉类型时,交叉类型必须用括号分组。实际上,情况是这样的:

function generateSlug((HasTitle&HasId)|null $post) {    if ($post === null) {        return '';    }
return strtolower($post->getTitle()) . $post->getId();}

In this case, (HasTitle&HasId)|null is the DNF type.

在本例中,(HasTitle & HasId) | null 是 DNF 类型。

It's a nice addition, especially since it means that we can now have nullable intersection types, which is probably the most important use case for this feature.

这是一个很好的补充,特别是因为它意味着我们现在可以有可为空的交集类型,这可能是这个特性最重要的用例。

Constants in traits 性格中的常量 rfc

You can now use constants in traits:

现在可以在 trait 中使用常量:

trait Foo {    public const CONSTANT = 1;     public function bar(): int {        return self::CONSTANT;    }}

You won't be able to access the constant via the trait's name, either from outside the trait, or from inside it.

您将无法通过 trait 的名称访问常量,无论是从 trait 外部还是从 trait 内部。

trait Foo {    public const CONSTANT = 1;     public function bar(): int {        return Foo::CONSTANT;    }}
Foo::CONSTANT;

You can however access the constant via the class that uses the trait, given that it's public:

然而,您可以通过使用 trait 的类来访问该常量,因为它是公共的:

class MyClass{    use Foo;}
MyClass::CONSTANT; // 1

Redact parameters in back traces 反向跟踪中的编校参数 rfc

A common practice in any codebase is to send production errors to a service that keeps track of them, and will notify developers when something goes wrong. This practice often involves sending stack traces over the wire to a third party service. There are cases however where those stack traces can include sensitive information such as environment variables, passwords or usernames.

任何代码库中的一个常见实践是将生产错误发送到一个服务,该服务将跟踪这些错误,并在出现错误时通知开发人员。这种实践通常涉及通过线路向第三方服务发送堆栈跟踪。然而,在某些情况下,这些堆栈跟踪可能包含敏感信息,如环境变量、密码或用户名。

PHP 8.2 allows you to mark such "sensitive parameters" with an attribute, so that you don't need to worry about them being listed in your stack traces when something goes wrong. Here's an example from the RFC:

PHP 8.2允许您使用属性标记这些“敏感参数”,这样当出现错误时,您就不必担心它们被列在堆栈跟踪中。下面是 RFC 的一个例子:

function login(    string $user,    #[\SensitiveParameter] string $password) {    // …        throw new Exception('Error');} login('root', 'root'); Fatal error: Uncaught Exception: Error in login.php:8Stack trace:#0 login.php(11): login('root', Object(SensitiveParameterValue))#1 {main}  thrown in login.php on line 8

Fetch properties of enums in const expressions 获取常数表达式中枚举的属性 rfc

From the RFC:

来自 RFC 的消息:

This RFC proposes to allow the use of ->/?-> to fetch properties of enums in constant expressions. The primary motivation for this change is to allow fetching the name and value properties in places where enum objects aren't allowed, like array keys

这个 RFC 建议允许使用->/?- > 获取常量表达式中枚举的属性。此更改的主要动机是允许在不允许枚举对象的位置(如数组键)获取名称和值属性

That means that the following code is now valid:

这意味着以下代码现在是有效的:

enum A: string {    case B = 'B';        const C = [self::B->value => self::B];}

Return type changes for 返回 DateTime::createFromImmutable() and 还有 DateTimeImmutable::createFromMutable() breaking崩溃

Previously, these methods looked like this:

以前,这些方法看起来像这样:

DateTime::createFromImmutable(): DateTimeDateTimeImmutable::createFromMutable(): DateTimeImmutable

In PHP 8.2 those method signatures are changed like so:

在 PHP 8.2中,这些方法签名是这样更改的:

DateTime::createFromImmutable(): staticDateTimeImmutable::createFromMutable(): static

This change makes a lot more sense, as it improves static insight possibilities for classes extending from DateTime and DateTimeImmutable. However, technically, this is a breaking change that might affect custom implementations that extend from either of those two classes.

这个更改更有意义,因为它提高了从 DateTime 和 DateTimeImmutable 扩展的类的静态洞察可能性。但是,从技术上讲,这是一个重大变化,可能会影响从这两个类中的任何一个扩展的自定义实现。

utf8_encode() and 还有 utf8_decode() deprecations 反对意见 rfc

In PHP 8.2, using either utf8_encode() or utf8_decode() will trigger these deprecation notices:

在 PHP 8.2中,使用 utf8 _ encode ()或 utf8 _ decode ()将触发这些弃用通知:

Deprecated: Function utf8_encode() is deprecatedDeprecatedFunction utf8_decode() is deprecated

The RFC argues that these functions have a inaccurate name that often causes confusion: these functions only convert between ISO-8859-1 and UTF-8, while the function name suggest a more broader use. There's a more detailed explanation about the reasoning in the RFC.

RFC 认为,这些函数的名称不准确,经常会造成混淆: 这些函数只能在 ISO-8859-1和 UTF-8之间转换,而函数名则意味着使用范围更广。在 RFC 中有一个关于推理的更详细的解释。

The alternative? The RFC suggests using mb_convert_encoding() instead.

另一种选择呢? RFC 建议使用 mb _ trans _ coding ()来代替。

Locale-insensitive 对现场不敏感 strtolower() and 还有 strtoupper() breaking崩溃 rfc

Both strtolower() and strtoupper() are no longer locale-sensitive. You can use mb_strtolower() if you want localized case conversion.

Strtolower ()和 strtoupper ()都不再对区域设置敏感。

Signature changes to several SPL methods 对多个 SPL 方法的签名更改 breaking崩溃

Several methods of SPL classes have been changed to properly enforce their correct type signature:

SPL 类的几个方法已经进行了更改,以正确执行其正确的类型签名:

SplFileInfo::_bad_state_ex()SplFileObject::getCsvControl()SplFileObject::fflush()SplFileObject::ftell()SplFileObject::fgetc()SplFileObject::fpassthru()SplFileObject::hasChildren()SplFileObject::getChildren()

New 新的 n modifier in PCRE PCRE 的修饰语 upgrading升级

You can now use the n modifier (NO_AUTO_CAPTURE) in pcre* functions.

现在可以在 pcre * 函数中使用 n 修饰符(NO _ AUTO _ CAPTURE)。

ODBC username and password escaping ODBC 用户名和密码转义 breaking崩溃

From the UPGRADING guide:

来自升级指南:

The ODBC extension now escapes the username and password for the case when both a connection string and username/password are passed, and the string must be appended to.

当连接字符串和用户名/密码都被传递时,ODBC 扩展现在转义用户名和密码,并且必须将该字符串追加到。

The same applies to PDO_ODBC.

这同样适用于 PDO _ ODBC。

Deprecate 不赞成 ${} string interpolation 字符串插值 rfc

PHP has several ways of embedding variables in strings. This RFC deprecates two ways of doing so, since they are rarely used, and often lead to confusion:

PHP 有几种在字符串中嵌入变量的方法。这种 RFC 不赞成这样做的两种方式,因为它们很少被使用,而且经常导致混淆:

"Hello ${world}";
Deprecated: Using ${} in strings is deprecated

"Hello ${(world)}";
Deprecated: Using ${} (variable variables) in strings is deprecated

To be clear: the two popular ways of string interpolation still work:

需要说明的是: 两种流行的字符串插值方法仍然有效:

"Hello {$world}";
"Hello $world";

Deprecate partially supported callables 废弃部分支持的调用 rfc

Another change, although one with a slightly smaller impact, is that partially supported callables are now deprecated as well. Partially supported callables are callables which can be called using call_user_func($callable), but not by calling $callable() directly. The list of these kinds of callables is rather short, by the way:

另一个变化是部分支持的可调用现在也被弃用了,尽管这个变化的影响稍微小一些。部分支持的可调用是可以使用 call _ user _ func ($callable)调用的可调用,但不能直接调用 $callable ()。顺便说一句,这种类型的电话名单相当短:

"self::method""parent::method""static::method"["self", "method"]["parent", "method"]["static", "method"]["Foo", "Bar::method"][new Foo, "Bar::method"]

The reason for doing this? It's a step in the right direction towards being able to use callable for typed properties. Nikita explains it very well in the RFC:

为什么要这么做?这是朝着能够使用可调用的类型化属性迈出的正确一步。Nikita 在 RFC 中解释得很清楚:

all of these callables are context-dependent. The method that "self::method" refers to depends on which class the call or callability check is performed from. In practice, this usually also holds for the last two cases, when used in the form of [new Foo, "parent::method"].

所有这些调用都依赖于上下文。“ self: : method”引用的方法取决于执行调用或可调用性检查的类。在实践中,当以[ new Foo,“ father: : method”]的形式使用时,这通常也适用于最后两种情况。

Reducing the context-dependence of callables is the secondary goal of this RFC. After this RFC, the only scope-dependence still left is method visibility: "Foo::bar" may be visible in one scope, but not another. If callables were to be limited to public methods in the future (while private methods would have to use first-class callables or Closure::fromCallable() to be made scope-independent), then the callable type would become well-defined and could be used as a property type. However, changes to visibility handling are not proposed as part of this RFC.

减少调用的上下文依赖性是这个 RFC 的次要目标。在这个 RFC 之后,剩下的唯一依赖于作用域的是方法可见性: “ Foo: : bar”可能在一个作用域中可见,但在另一个作用域中不可见。如果将来可调用性仅限于公共方法(而私有方法必须使用第一类可调用性或 Closure: : from Callable ()才能与作用域无关) ,那么可调用类型将变得定义良好,可以用作属性类型。但是,可见性处理的更改不作为此 RFC 的一部分。

相关推荐