2024 年日本 PHP 研討會
已釋出!
PHP 8.4 是 PHP 語言的主要更新。
它包含許多新功能,例如屬性鉤子、非對稱可見性、更新的 DOM API、效能改進、錯誤修正和一般清理。

屬性鉤子 RFC 文件

PHP < 8.4
<?php
class 地區設定
{
private
string $語言代碼;
private
string $國家地區代碼;

public function
__construct(string $語言代碼, string $國家地區代碼)
{
$this->設定語言代碼($語言代碼);
$this->設定國家地區代碼($國家地區代碼);
}

public function
取得語言代碼(): string
{
return
$this->語言代碼;
}

public function
設定語言代碼(string $語言代碼): void
{
$this->語言代碼 = $語言代碼;
}

public function
取得國家地區代碼(): string
{
return
$this->國家地區代碼;
}

public function
設定國家地區代碼(string $國家地區代碼): void
{
$this->國家地區代碼 = strtoupper($國家地區代碼);
}

public function
設定組合代碼(string $組合代碼): void
{
[
$語言代碼, $國家地區代碼] = explode('_', $組合代碼, 2);

$this->設定語言代碼($語言代碼);
$this->設定國家地區代碼($國家地區代碼);
}

public function
取得組合代碼(): string
{
return
\sprintf("%s_%s", $this->語言代碼, $this->國家地區代碼);
}
}

$巴西葡萄牙語 = new 地區設定('pt', 'br');
var_dump($巴西葡萄牙語->取得國家地區代碼()); // BR
var_dump($巴西葡萄牙語->取得組合代碼()); // pt_BR
?>
PHP 8.4
<?php
class Locale
{
public
string $languageCode;

public
string $countryCode
{
set (string $countryCode) {
$this->countryCode = strtoupper($countryCode);
}
}

public
string $combinedCode
{
get => \sprintf("%s_%s", $this->languageCode, $this->countryCode);
set (string $value) {
[
$this->languageCode, $this->countryCode] = explode('_', $value, 2);
}
}

public function
__construct(string $languageCode, string $countryCode)
{
$this->languageCode = $languageCode;
$this->countryCode = $countryCode;
}
}

$brazilianPortuguese = new Locale('pt', 'br');
var_dump($brazilianPortuguese->countryCode); // BR
var_dump($brazilianPortuguese->combinedCode); // pt_BR
?>
屬性掛鉤(Property hooks)提供對計算屬性的支援,IDE 和靜態分析工具可以直接理解這些屬性,而無需編寫可能不同步的程式碼註釋。此外,它們允許對值進行可靠的預處理或後處理,而無需檢查類別中是否存在匹配的 getter 或 setter。

非對稱可見性 RFC 文件

PHP < 8.4
類別 PhpVersion
{
私有
字串 $version = '8.3';

公開 函式
getVersion(): 字串
{
返回
$this->version;
}

公開 函式
increment(): void
{
[$major
, $minor] = explode('.', $this->version);
$minor++;
$this->version = "{$major}.{$minor}";
}
}
PHP 8.4
類別 PhpVersion
{
公開 私有(
設定) 字串 $version = '8.4';

公開 函式
increment(): void
{
[$major
, $minor] = explode('.', $this->version);
$minor++;
$this->version = "{$major}.{$minor}";
}
}
現在可以獨立控制屬性的讀寫範圍,減少了使用樣板程式取得器方法來公開屬性值而不允許從類別外部修改的需求。

#[\Deprecated] 屬性 RFC 文件

PHP < 8.4
類別 PhpVersion
{
/**
* @deprecated 8.3 請改用 PhpVersion::getVersion()
*/
公開 函式 getPhpVersion(): 字串
{
返回
$this->getVersion();
}

公開 函式
getVersion(): 字串
{
返回
'8.3';
}
}

$phpVersion = new PhpVersion();
// 沒有提示該方法已被棄用。
echo $phpVersion->getPhpVersion();
PHP 8.4
類別 PhpVersion
{
#[
\Deprecated(
message: "請使用 PhpVersion::getVersion() 取代",
since: "8.4",
)]
public function
getPhpVersion(): string
{
return
$this->getVersion();
}

public function
getVersion(): string
{
return
'8.4';
}
}

$phpVersion = new PhpVersion();
// 已棄用:PhpVersion::getPhpVersion() 方法自 8.4 版起已棄用,請使用 PhpVersion::getVersion() 取代
echo $phpVersion->getPhpVersion();
新的 #[\Deprecated] 屬性讓 PHP 現有的棄用機制可供使用者自訂函式、方法和類別常數使用。

新的 ext-dom 功能和 HTML5 支援 RFC RFC 文件

PHP < 8.4
$dom = new DOMDocument();
$dom->loadHTML(
<<<'HTML'
<main>
<article>PHP 8.4 是一個功能豐富的版本!</article>
<article class="featured">PHP 8.4 新增了符合規範的新 DOM 類別,同時保留舊的類別以確保相容性。</article>
</main>
HTML,
LIBXML_NOERROR,
);

$xpath = new DOMXPath($dom);
$node = $xpath->query(".//main/article[not(following-sibling::*)]")[0];
$classes = explode(" ", $node->className); // 簡化
var_dump(in_array("featured", $classes)); // bool(true)
PHP 8.4
$dom = Dom\HTMLDocument::createFromString(
<<<'HTML'
<main>
<article>PHP 8.4 是一個功能豐富的版本!</article>
<article class="featured">PHP 8.4 新增了符合規範的 DOM 類別,並保留舊的類別以確保相容性。</article>
</main>
HTML,
LIBXML_NOERROR,
);

$node = $dom->querySelector('main > article:last-child');
var_dump($node->classList->contains("featured")); // bool(true)

新的 DOM API 包括對解析 HTML5 文件的標準 compliant 支援,修復了 DOM 功能行為中幾個長期存在的合規性錯誤,並添加了幾個函式,使處理文件更加方便。

新的 DOM API 可在 Dom 命名空間中使用。可以使用 Dom\HTMLDocumentDom\XMLDocument 類別建立使用新 DOM API 的文件。

BCMath 的物件 API RFC

PHP < 8.4
$num1 = '0.12345';
$num2 = 2;
$result = bcadd($num1, $num2, 5);

echo
$result; // '2.12345'
var_dump(bccomp($num1, $num2) > 0); // false
PHP 8.4
use BcMath\Number;

$num1 = new Number('0.12345');
$num2 = new Number('2');
$result = $num1 + $num2;

echo
$result; // '2.12345'
var_dump($num1 > $num2); // false

新的 BcMath\Number 物件可在處理任意精度數字時啟用物件導向用法和標準數學運算子。

這些物件是不可變的,並實作了 Stringable 介面,因此它們可以在字串上下文中使用,例如 echo $num

新的 array_*() 函式 RFC

PHP < 8.4
$animal = null;
foreach ([
'dog', 'cat', 'cow', 'duck', 'goose'] as $value) {
if (
str_starts_with($value, 'c')) {
$animal = $value;
break;
}
}

var_dump($animal); // string(3) "cat"
PHP 8.4
$animal = array_find(
[
'dog', 'cat', 'cow', 'duck', 'goose'],
static fn (
string $value): bool => str_starts_with($value, 'c'),
);

var_dump($animal); // 字串(3) "cat"

PDO 驅動程式專屬子類別 RFC

PHP < 8.4
$connection = new PDO(
'sqlite:foo.db',
$username,
$password,
);
// 物件(PDO)

$connection->sqliteCreateFunction(
'prepend_php',
static fn (
$string) => "PHP {$string}",
);

$connection->query('SELECT prepend_php(version) FROM php');
PHP 8.4
$connection = PDO::connect(
'sqlite:foo.db',
$username,
$password,
);
// 物件(Pdo\Sqlite)

$connection->createFunction(
'prepend_php',
static fn (
$string) => "PHP {$string}",
);
// 不相符的驅動程式上不存在。

$connection->query('SELECT prepend_php(version) FROM php');
新增了 PDO 的子類別 Pdo\DblibPdo\FirebirdPdo\MySqlPdo\OdbcPdo\PgsqlPdo\Sqlite

new MyClass()->method() 無括號 RFC 文件

PHP < 8.4
class PhpVersion
{
public function
getVersion(): string
{
return
'PHP 8.3';
}
}

var_dump((new PhpVersion())->getVersion());
PHP 8.4
類別 PhpVersion
{
public function
getVersion(): string
{
return
'PHP 8.4';
}
}

var_dump(new PhpVersion()->getVersion());
現在可以不必用括號包覆 new 運算式即可存取新建物件的屬性和方法。

新的類別、介面和函式

  • 新增延遲物件 (Lazy Objects)
  • 基於 IR 框架的新 JIT 實作。
  • 新增 request_parse_body() 函式。
  • 新增 bcceil()bcdivmod()bcfloor()bcround() 函式。
  • round() 新增 RoundingMode 列舉,包含 4 個新的捨入模式:TowardsZeroAwayFromZeroNegativeInfinityPositiveInfinity
  • 新增 DateTime::createFromTimestamp()DateTime::getMicrosecond()DateTime::setMicrosecond()DateTimeImmutable::createFromTimestamp()DateTimeImmutable::getMicrosecond()DateTimeImmutable::setMicrosecond() 方法。
  • 新增 mb_trim()mb_ltrim()mb_rtrim()mb_ucfirst()mb_lcfirst() 函式。
  • 新增 pcntl_getcpu()pcntl_getcpuaffinity()pcntl_getqos_class()pcntl_setns()pcntl_waitid() 函式。
  • 新增 ReflectionClassConstant::isDeprecated()ReflectionGenerator::isClosed()ReflectionProperty::isDynamic() 方法。
  • 新增 http_get_last_response_headers()http_clear_last_response_headers()fpow() 函式。
  • 新增 XMLReader::fromStream()XMLReader::fromUri()XMLReader::fromString()XMLWriter::toStream()XMLWriter::toUri()XMLWriter::toMemory() 方法。
  • 新增 grapheme_str_split() 函式。

棄用和向下相容性破壞

  • IMAP、OCI8、PDO_OCI 和 pspell 擴充套件已從核心程式庫中移除,並移至 PECL。
  • 隱式可為 Null 的參數類型現已棄用。
  • 使用 _ 作為類別名稱現已棄用。
  • 將零的負數次方現已棄用。
  • 傳遞無效模式到 round() 會擲出 ValueError
  • 來自 dateintlpdoreflectionsplsqlitexmlreader 擴充套件的類別常數現在已加上類型提示。
  • GMP 類別現在是 final 類別。
  • MYSQLI_SET_CHARSET_DIRMYSQLI_STMT_ATTR_PREFETCH_ROWSMYSQLI_CURSOR_TYPE_FOR_UPDATEMYSQLI_CURSOR_TYPE_SCROLLABLEMYSQLI_TYPE_INTERVAL 常數已被移除。
  • mysqli_ping()mysqli_kill()mysqli_refresh() 函式、mysqli::ping()mysqli::kill()mysqli::refresh() 方法和 MYSQLI_REFRESH_* 常數已被棄用。
  • stream_bucket_make_writeable()stream_bucket_new() 現在返回 StreamBucket 的實例,而不是 stdClass
  • exit() 行為變更.
  • E_STRICT 常數已被棄用。
To Top