更多變更日誌 更多變更日誌

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()、DOMElement::contains()、DOMNode::getRootNode()、DOMNode::isEqualNode()、::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 手冊中提供了遷移指南。請參閱它以獲取新功能和向後不相容更改的詳細清單。

如果需要下載先前的版本,可以查看 更多變更日誌