PHP 8.3将于2023年11月23日发布;它对只读类、新json_validate()函数、最近添加的类的补充Randomizer、堆栈溢出检测等进行了改进。

在这篇文章中,我们将一一介绍所有功能、性能改进、更改和弃用。

只读修改rfc

该 RFC 提出了两项​​更改,但仅接受了一项:在克隆时能够重新初始化只读属性。这听起来可能是一件大事,但这个 RFC 只解决了一个非常具体(但重要)的边缘情况:覆盖 中的属性值__clone(),以便允许深度克隆只读属性。

readonly class Post
{
    public function __construct(
        public DateTime $createdAt,
    ) {}
    
    public function __clone()
    {
        $this->createdAt = new DateTime(); 
        // This is allowed,
        // even though `createdAt` is a readonly property.
    }
}

您可以在此处阅读有关此 RFC 的深入文章和一些旁注。


#类型化类常量rfc

您现在可以输入提示类常量:

class Foo
{
    const string BAR = 'baz'; 
} 

##[Override]属性rfc

新属性用于显示程序员的意图。它基本上是说“我知道这个方法正在重写父方法。如果这种情况发生变化,请告诉我”。#[Override]

这是一个例子:

abstract class Parent
{
    public function methodWithDefaultImplementation(): int
    {
        return 1;
    }
}

final class Child extends Parent
{
    #[Override]
    public function methodWithDefaultImplementation(): int
    {
        return 2; // The overridden method
    }
} 

现在,让我们想象一下父方法在某一时刻更改了其方法名称:

abstract class Parent
{
    public function methodWithNewImplementation(): int
    {
        return 1;
    }
}

由于该属性,PHP 将能够检测到不再覆盖任何内容,并且会抛出错误。#[Override]Child::methodWithDefaultImplementation()

您可以在此处阅读有关该属性的更多信息#[Override]


#数组中的负索引打破

如果您有一个空数组,请添加一个具有负索引的项目,然后添加另一个项目,第二个项目将始终从 index 开始0

$array = [];

$array[-5] = 'a';
$array[] = 'b';

var_export($array);

//array (
//  -5 => 'a',
//  0 => 'b',
//)

从 PHP 8.3 开始,下一项将添加到 index 处-4

//array (
//  -5 => 'a',
//  -4 => 'b',
//)

#匿名只读类升级

以前,您无法将匿名类标记为只读。PHP 8.3 中已修复此问题:

$class = new readonly class {
    public function __construct(
        public string $foo = 'bar',
    ) {}
};

#新json_validate()函数rfc

以前,验证字符串是否为有效 JSON 的唯一方法是对其进行解码并检测是否抛出任何错误。json_validate()如果您只需要知道输入是否是有效的 JSON,则此新函数非常有用,因为与解码字符串相比,它使用的内存更少。

json_validate(string $json, int $depth = 512, int $flags = 0): bool

#Randomizer补充rfc

PHP 8.2 添加了新的Randomizer类。本次更新带来了一些小补充:

Randomizer::getBytesFromString(string $string, int $length): string

此方法允许您生成具有给定长度的字符串,该字符串由给定字符串中随机选择的字节组成。

Randomizer::getFloat(
    float $min,
    float $max,
    IntervalBoundary $boundary = IntervalBoundary::ClosedOpen
): float

getFloat()$min返回和之间的浮点数$max。您可以通过枚举来定义是否包含$min以及$max应该包含在内IntervalBoundaryClosed表示包含该值,表示Open排除该值。

Randomizer::nextFloat(): float {}

最后,nextFloat()是 的简写,换句话说:它将为您提供 0 到 1 之间的随机浮点数,其中 1 被排除。getFloat(0, 1, IntervalBoundary::ClosedOpen)


#动态类常量获取rfc

PHP 8.3 允许您使用更动态的语法来获取常量:

class Foo 
{
    const BAR = 'bar';
}

$name = 'BAR';
 
// Instead of this:
constant(Foo::class . '::' . $name);

// You can now do this:
Foo::{$name};

#更合适的日期/时间异常rfc 打破

在许多情况下,PHP 只会抛出一个ExceptionorError对象;或者在处理日期和时间时出现错误时发出警告或错误。该 RFC 遍历了所有这些边缘情况,并为它们添加了适当的、专用的例外情况。

我们现在有DateMalformedIntervalStringExceptionDateInvalidOperationException、 和 等例外情况DateRangeError

一般来说,这些添加不会破坏任何代码,因为这些新添加的异常和错误是泛型ExceptionError类的子类。然而,此 RFC 带来了三个小的重大更改:

  • nowEpoch doesn't fit in a PHP integer返回一个 newDateRangeError而不是 generic ValueError,它不会子类化。这仅是 32 位平台的问题。
  • Only non-special relative time specifications are supported for subtraction带有和 的警告成为新的。DateTime::sub()date_sub()DateInvalidOperationException
  • 现在,当与 OO 接口一起使用时,解析错误/损坏的字符串时创建的Unknown or bad format (%s) at position %d (%c): %s和警告将抛出一个新的警告,而不是显示警告并返回 false。String '%s' contains non-relative elementsDateIntervalDateMalformedIntervalStringException

#改进的unserialize()错误处理rfc

unserialize()E_WARNING现在遇到问题时总是会发出 a而不是有时发出E_NOTICE.

该 RFC 还建议在运行时添加更多异常unserialize(),但该部分并未被接受。


#range()函数变更打破

从变更日志:

  • TypeError现在,当传递对象、资源或数组作为边界输入时会抛出A
  • ValueError当传递 0 时会抛出更具描述性的$step
  • ValueError现在,当使用负数$step来增加范围时会抛出A
  • 如果$step是一个可以解释为int的float,现在就这样做了
  • ValueError如果任何参数是infinity或,现在会抛出ANAN
  • 如果or是空字符串,E_WARNING现在会发出An 。该值继续转换为值 0。$start$end
  • 现在,如果或具有多个字节,且仅当它是非数字字符串时,E_WARNING才会发出An 。$start$end
  • E_WARNING现在,如果$startor被转换为整数,则会发出An $end,因为另一个边界输入是数字。(例如range(5, 'z');
  • E_WARNING现在,当尝试生成一系列字符时,如果 $step 是浮点数,则会发出 An ,除非两个边界输入都是数字字符串(例如,不会range('5', '9', 0.5);产生警告)
  • range()现在,如果边界输入之一是字符串数字,则生成字符列表,而不是将另一个输入转换为 int (例如range('5', 'z');

#特征和静态属性打破

从变更日志:

使用具有静态属性的特征现在将重新声明从父类继承的静态属性。这将为当前类创建一个单独的静态属性存储。这类似于直接将静态属性添加到没有特征的类中。


#堆栈溢出检测pr

PHP 8.3 添加了两个新的 ini 指令,称为zend.max_allowed_stack_sizezend.reserved_stack_sizeError当使用超过 和zend.max_allowed_stack_size之间的差异时,接近溢出调用堆栈的程序现在可能会抛出zend.reserved_stack_size

此功能的好处是堆栈溢出引起的分段错误将不再导致段错误,从而使调试变得更加容易。

默认值为,zend.max_allowed_stack_size0意味着 PHP 将自动确定一个值。您还可以提供-1以表明没有限制或特定的字节数。该zend.reserved_stack_size指令用于确定“缓冲区”,以便 PHP 仍然能够抛出错误而不是实际耗尽内存。这里的值应该是多个字节,但 PHP 将为您确定一个合理的默认值,因此您不一定需要设置它,除非您遇到特定程序的边缘情况。

最后一点,对于纤程,现有fiber.stack_size指令用作允许的最大堆栈大小。

zend.max_allowed_stack_size=128K

#新mb_str_pad函数rfc

来自 RFC:

在 PHP 中,各种字符串函数有两种变体:一种用于字节字符串,另一种用于多字节字符串。然而,多字节字符串函数中值得注意的一个缺陷mbstringstr_pad(). 该str_pad()函数缺乏多字节字符支持,因此在使用使用多字节编码(如 UTF-8)的语言时会出现问题。该 RFC 建议在 PHP 中添加这样一个函数,我们将其称为mb_str_pad().

该函数如下所示:

function mb_str_pad(
    string $string, 
    int $length, 
    string $pad_string = " ", 
    int $pad_type = STR_PAD_RIGHT, 
    ?string $encoding = null,
): string {}

#魔术方法闭包和命名参数pr

假设您有一个支持魔术方法的类:

class Test {
    public function __call($name, $args) 
    {
        var_dump($name, $args);
    }
    
    public static function __callStatic($name, $args) {
        var_dump($name, $args);
    }
}

PHP 8.3 允许您从这些方法创建闭包,然后将命名参数传递给这些闭包。这在以前是不可能的。

$test = new Test();

$closure = $test->magic(...);

$closure(a: 'hello', b: 'world'); 

#不变的恒定可见性打破

以前,在实现接口时不会检查常量的可​​见性。PHP 8.3 修复了此错误,但如果您不知道此行为,则可能会导致某些地方的代码损坏。

interface I {
    public const FOO = 'foo';
}

class C implements I {
    private const FOO = 'foo';
}

#RFC 的小弃用rfc

与每个版本一样,都有一个 RFC 添加了一堆小的弃用内容。请记住,弃用并不是错误,这些通常对于语言的发展是一件好事。这些是已通过的弃用,您可以在 RFC 中阅读有关它们的更多详细信息:

  • 不赞成将负数传递$widthsmb_strimwidth()
  • 弃用并删除常量NumberFormatter::TYPE_CURRENCY
  • 弃用并删除损坏的 PHP 7.1 之前的 Mt19937 实现 ( MT_RAND_PHP)
  • 弃用并删除ldap_connect()带有 2 个参数的$host调用$port
  • 弃用字符串评估代码断言的剩余部分

#小但显着的变化

并非 PHP 中的每个更改都会通过 RFC 流程。事实上,大多数更改包括维护和错误修复,并且不需要 RFC。所有这些更改都列在升级文档中。我将列出一些最突出的,但如果您想了解最微小的细节,您绝对应该阅读整个列表。

  • 使用FFI时,返回类型为voidnow returnnull而不是 returned 的C 函数FFI\CData:void
  • posix_getrlimit()现在采用可选$res参数来允许获取单个资源限制。
  • gc_status()有四个新字段:runningprotectedfullbuffer_size
  • class_alias()现在支持创建内部类的别名。
  • mysqli_poll()ValueError现在,当传递 read 或 error 参数时,会引发 a 。
  • array_pad()现在仅受数组可以拥有的最大元素数的限制。之前,一次最多只能添加 1048576 个元素。
  • 新的 posix 函数:posix_sysconf()posix_pathconf()posix_fpathconf()posix_eaccess()
  • 现在,在 posix 系统上执行proc_get_status()多次将始终返回正确的值。
  • opcache.consistency_checksini 指令已删除
  • 改进array_sum()array_product()

 

https://stitcher.io/blog/new-in-php-83

PHP 8.3 的新增功能特性
标签: