2024 日本 PHP 研討會
已釋出!
PHP 8.3 是 PHP 語言的主要更新版本。
它包含許多新功能,例如類別常數的顯式類型宣告、唯讀屬性的深度複製以及隨機性功能的增強。一如既往,它還包含效能改進、錯誤修復和一般清理。

具類型類別常數 RFC

PHP < 8.3
interface I {
// 我們可能天真地認為 PHP 常數始終是字串。
const PHP = 'PHP 8.2';
}

class
Foo implements I {
// 但是實作類別可能會將其定義為陣列。
const PHP = [];
}
PHP 8.3
介面 I {
const
string PHP = 'PHP 8.3';
}

類別
Foo 實作 I {
const
string PHP = [];
}

// 致命錯誤:類別常數不能使用陣列作為值
// Foo::PHP 的型別為字串

動態類別常數擷取 RFC

PHP < 8.3
類別 Foo {
const
PHP = 'PHP 8.2';
}

$searchableConstant = 'PHP';

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

$searchableConstant = 'PHP';

var_dump(Foo::{$searchableConstant});

新的 #[\Override] 屬性 RFC

PHP < 8.3
使用 PHPUnit\Framework\TestCase;

最終類別
MyTest 繼承 TestCase {
protected
$logFile;

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

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

// 日誌檔將永遠不會被刪除,因為
// 方法名稱拼寫錯誤(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');
}
}

// 致命錯誤:MyTest::taerDown() 擁有 #[\Override] 屬性,
// 但沒有找到對應的父類別方法
藉由將 #[\Override] 屬性添加到方法中,PHP 將會確保在父類別或實作的介面中存在具有相同名稱的方法。添加此屬性可以明確表示覆寫父類別方法的意圖,並簡化重構,因為移除被覆寫的父類別方法將會被偵測到。

唯讀屬性的深度複製 RFC

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;

// 致命錯誤:無法修改唯讀屬性 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';
唯讀(readonly)屬性現在可以在魔術方法 __clone 中修改一次,以啟用唯讀屬性的深度複製。

新增 json_validate() 函式 RFC 文件

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() 方法 RFC 文件

PHP < 8.3
// 這個函式需要手動實作。
function getBytesFromString(string $string, int $length) {
$stringLength = strlen($string);

$result = '';
for (
$i = 0; $i < $length; $i++) {
// random_int 不可設定種子以進行測試,但很安全。
$result .= $string[random_int(0, $stringLength - 1)];
}

return
$result;
}

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

echo
$randomDomain;
PHP 8.3
// 可以傳入一個 \Random\Engine 來設定種子,
// 預設為安全引擎。
$randomizer = new \Random\Randomizer();

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

echo
$randomDomain;
在 PHP 8.2 中新增的「亂數擴充功能」,新增了一個方法,可以產生僅由特定位元組組成的亂數字串。這個方法讓開發者可以輕鬆產生亂數識別碼,例如網域名稱和任意長度的數字字串。

新增 Randomizer::getFloat()Randomizer::nextFloat() 方法 RFC 文件

PHP < 8.3
// 傳回一個介於 $min 和 $max 之間的隨機浮點數,包含 $min 和 $max。
function getFloat(float $min, float $max) {
// 這個演算法對於特定輸入有偏差,並且可能
// 傳回超出給定範圍的值。這在使用者端程式碼中無法避免。
$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) 可能會傳回上限值,例如 1,
// 造成些微偏差。
$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() 等同於
// Randomizer::getFloat(0, 1, \Random\IntervalBoundary::ClosedOpen)。
// 不會傳回上限值,例如 1。
$myBoolean = $randomizer->nextFloat() < $chanceForTrue;

由於浮點數的精度有限且會隱含捨入,因此產生位於特定區間內的無偏差浮點數並非易事,常用的使用者端程式碼解決方案可能會產生偏差結果或超出要求範圍的數字。

Randomizer 也新增了兩個方法,可用於產生無偏差的隨機浮點數。Randomizer::getFloat() 方法使用 γ-section 演算法,該演算法發表於 從區間中繪製隨機浮點數。Frédéric Goualard,ACM Trans. Model. Comput. Simul.,32:3,2022 年。

命令列程式碼檢查器支援多個檔案 PR 文件

PHP < 8.3
php -l foo.php bar.php foo.php 中沒有偵測到語法錯誤
PHP 8.3
php -l foo.php bar.php foo.php 中沒有偵測到語法錯誤 bar.php 中沒有偵測到語法錯誤

命令列程式碼檢查器現在接受可變輸入的檔名以進行程式碼檢查

新的類別、介面和函式

棄用與向下相容性破壞

To Top