更多变更日志 更多变更日志

PHP 8.3 是 PHP 语言的重大更新。

它包含许多新功能,例如类常量的显式类型、只读属性的深度克隆以及随机功能的添加。与往常一样,它还包括性能改进、错误修复和常规清理。

立即升级到 PHP 8.3!

类型化类常量

PHP < 8.3
interface I {
// We may naively assume that the PHP constant is always a string.
const PHP = 'PHP 8.2' ;
}

class Foo implements I {
// But implementing classes may define it as an array.
const PHP = [];
}
PHP 8.3
interface I {
const string PHP = 'PHP 8.2' ;
}

class Foo implements I {
const string PHP = [];
}
// Fatal error: Cannot use array as value for class constant
// Foo::PHP of type string

动态类常量获取

PHP < 8.3
class Foo {
const PHP = 'PHP 8.2' ;
}

$searchableConstant = 'PHP' ;

var_dump ( constant ( Foo ::class . ":: { $searchableConstant } " ));
PHP 8.3
class Foo {
const PHP = 'PHP 8.3' ;
}

$searchableConstant = 'PHP' ;

var_dump ( Foo :: { $searchableConstant } );

New #[Override] attribute

PHP < 8.3
use PHPUnit\Framework\TestCase ;

final class MyTest extends TestCase {
protected $logFile ;

protected function setUp (): void {
$this -> logFile = fopen ( '/tmp/logfile' , 'w' );
}

protected function taerDown (): void {
fclose ( $this -> logFile );
unlink ( '/tmp/logfile' );
}
}

// The log file will never be removed, because the
// method name was mistyped (taerDown vs tearDown).
PHP 8.3
use PHPUnit\Framework\TestCase ;

final class MyTest extends TestCase {
protected $logFile ;

protected function setUp (): void {
$this -> logFile = fopen ( '/tmp/logfile' , 'w' );
}

#[ \Override ]
protected function taerDown (): void {
fclose ( $this -> logFile );
unlink ( '/tmp/logfile' );
}
}

// The log file will never be removed, because the
// method name was mistyped (taerDown vs tearDown).

By adding the #[Override] attribute to a method, PHP will ensure that a method with the same name exists in a parent class or in an implemented interface. Adding the attribute makes it clear that overriding a parent method is intentional and simplifies refactoring, because the removal of an overridden parent method will be detected.

只读属性的深度克隆

PHP < 8.3
class PHP {
public string $version = '8.2' ;
}

readonly class Foo {
public function __construct (
public PHP $php
) {}

public function __clone (): void {
$this -> php = clone $this -> php ;
}
}

$instance = new Foo (new PHP ());
$cloned = clone $instance ;

// Fatal error: Cannot modify readonly property Foo::$php
PHP 8.3
class PHP {
public string $version = '8.2' ;
}

readonly class Foo {
public function __construct (
public PHP $php
) {}

public function __clone (): void {
$this -> php = clone $this -> php ;
}
}

$instance = new Foo (new PHP ());
$cloned = clone $instance ;

$cloned -> php -> version = '8.3' ;

现在可以在神奇的 __clone 方法中修改只读属性一次,以启用只读属性的深度克隆。

新增 json_validate() 函数

PHP < 8.3
function json_validate ( string $string ): bool {
json_decode ( $string );

return json_last_error () === JSON_ERROR_NONE ;
}

var_dump ( json_validate ( '{ "test": { "foo": "bar" }
}' )); // true
PHP 8.3
var_dump ( json_validate ( '{ "test": { "foo": "bar" }
}' )); // true

json_validate() 允许检查字符串在语法上是否是有效的 JSON,同时比 json_decode() 更高效。

新增 Randomizer::getBytesFromString() 方法

PHP < 8.3
// This function needs to be manually implemented.
function getBytesFromString ( string $string , int $length ) {
$stringLength = strlen ( $string );

$result = '' ;
for ( $i = 0 ; $i < $length ; $i ++) {
// random_int is not seedable for testing, but secure.
$result .= $string [ random_int ( 0 , $stringLength - 1 )];
}

return $result ;
}

$randomDomain = sprintf (
"%s.example.com" ,
getBytesFromString (
'abcdefghijklmnopqrstuvwxyz0123456789' ,
16 ,
),
);

echo $randomDomain ;
PHP 8.3
// A \Random\Engine may be passed for seeding,
// the default is the secure engine.
$randomizer = new \Random\Randomizer ();

$randomDomain = sprintf (
"%s.example.com" ,
$randomizer -> getBytesFromString (
'abcdefghijklmnopqrstuvwxyz0123456789' ,
16 ,
),
);

echo $randomDomain ;

PHP 8.2 中添加的随机扩展通过一种新方法进行了扩展,以生成仅由特定字节组成的随机字符串。该方法允许开发人员轻松生成随机标识符,例如域名和任意长度的数字字符串。

新增 Randomizer::getFloat() 和 Randomizer::nextFloat() 方法

PHP < 8.3
// Returns a random float between $min and $max, both including.
function getFloat ( float $min , float $max ) {
// This algorithm is biased for specific inputs and may
// return values outside the given range. This is impossible
// to work around in userland.
$offset = random_int ( 0 , PHP_INT_MAX ) / PHP_INT_MAX ;

return $offset * ( $max - $min ) + $min ;
}

$temperature = getFloat (- 89.2 , 56.7 );
$chanceForTrue = 0.1 ;
// getFloat(0, 1) might return the upper bound, i.e. 1,
// introducing a small bias.
$myBoolean = getFloat ( 0 , 1 ) < $chanceForTrue ;
PHP 8.3
$randomizer = new \Random\Randomizer ();

$temperature = $randomizer -> getFloat (
-89.2 ,
56.7 ,
\Random\IntervalBoundary :: ClosedClosed ,
);

$chanceForTrue = 0.1 ;
// Randomizer::nextFloat() is equivalent to
// Randomizer::getFloat(0, 1, \Random\IntervalBoundary::ClosedOpen).
// The upper bound, i.e. 1, will not be returned.
$myBoolean = $randomizer -> nextFloat () <
$chanceForTrue ;

由于浮点数的精度有限和隐式舍入,生成位于特定区间内的无偏浮点数并非易事,并且常用的用户态解决方案可能会生成有偏差的结果或超出请求范围的数字。

随机发生器还通过两种方法进行了扩展,以无偏的方式生成随机浮点数。 Randomizer::getFloat() 方法使用在 Drawing Random Floating-Point Numbers from an Interval 中发布的 γ 部分算法。 Frédéric Goualard,ACM 翻译。模型。计算。同时,32:3,2022 年。

命令行 linter 支持多个文件

PHP < 8.3
php -l foo.php bar.php
No syntax errors detected in foo.php
PHP 8.3
php -l foo.php bar.php
No syntax errors detected in foo.php
No syntax errors detected in bar.php

命令行 linter 现在接受文件名的可变输入以进行 lint

新增类、接口和函数

  • 新增 DOMElement::getAttributeNames()、DOMElement::insertAdjacentElement()、DOMElement::insertAdjacentText()、DOMElement::toggleAttribute()、DOMNode::contains()、DOMNode::getRootNode()、DOMNode::isEqualNode()、 DOMNameSpaceNode::contains() 和 DOMParentNode::replaceChildren() 方法。
  • 新增 IntlCalendar::setDate()、IntlCalendar::setDateTime()、IntlGregorianCalendar::createFromDate() 和 IntlGregorianCalendar::createFromDateTime() 方法。
  • 新增 ldap_connect_wallet() 和 ldap_exop_sync() 函数。
  • 新增 mb_str_pad() 函数。
  • 新增 posix_sysconf()、posix_pathconf()、posix_fpathconf() 和 posix_eaccess() 函数。
  • 新增 ReflectionMethod::createFromMethodName() 方法。
  • 新增 socket_atmark() 函数。
  • 新增 str_increment()、str_decrement() 和stream_context_set_options() 函数。
  • 新增 ZipArchive::getArchiveFlag() 方法。
  • Support for generation EC keys with custom EC parameters in OpenSSL extension.
  • 新增 INI 设置 zend.max_allowed_stack_size 来设置允许的最大堆栈大小。
  • php.ini 现在支持后备/默认值语法。
  • 匿名类现在可以是只读的。

弃用和向后兼容性中断

  • 更合适的日期/时间例外。
  • 现在,将负索引 n 分配给空数组将确保下一个索引是 n 1 而不是 0。
  • range() 函数的更改。
  • Changes in re-declaration of static properties in traits.
  • U_MULTIPLE_DECIMAL_SEPERATORS 常量已被弃用,取而代之的是 U_MULTIPLE_DECIMAL_SEPARATORS。
  • MT_RAND_PHP Mt19937 变体已弃用。
  • ReflectionClass::getStaticProperties() 不再可为空。
  • INI 设置assert.active、assert.bail、assert.callback、assert.exception 和assert.warning 已被弃用。
  • 不推荐调用不带参数的 get_class() 和 get_parent_class()。
  • SQLite3:默认错误模式设置为异常。
更好的性能、更好的语法、改进的类型安全性。 立即升级到 PHP 8.3!

PHP 手册中提供了迁移指南。请参阅它以获取新功能和向后不兼容更改的详细列表。

如果需要下载以前的版本,可以查看 更多变更日志