2024 年 PHP 日本研討會

新功能

PHP 核心

型別化屬性

類別屬性現在支援類型宣告。

<?php
class User {
public
int $id;
public
string $name;
}
?>
上述範例將強制要求 $user->id 只能賦值 整數 值,而 $user->name 只能賦值 字串 值。

箭頭函式

箭頭函式 提供了用於定義具有隱式按值範圍繫結的函式的簡寫語法。

<?php
$factor
= 10;
$nums = array_map(fn($n) => $n * $factor, [1, 2, 3, 4]);
// $nums = array(10, 20, 30, 40);
?>

有限的返回類型共變性和參數類型反變性

以下程式碼現在可以正常運作:

<?php
class A {}
class
B extends A {}

class
Producer {
public function
method(): A {}
}
class
ChildProducer extends Producer {
public function
method(): B {}
}
?>
完整的變異數支援僅在使用自動載入時可用。在單一檔案內,只有非循環類型參考是可行的,因為所有類別都需要在被參考之前可用。

Null 聯合賦值運算子

<?php
$array
['key'] ??= computeDefault();
// 大致等同於
if (!isset($array['key'])) {
$array['key'] = computeDefault();
}
?>

在陣列內解包

<?php
$parts
= ['apple', 'pear'];
$fruits = ['banana', 'orange', ...$parts, 'watermelon'];
// ['banana', 'orange', 'apple', 'pear', 'watermelon'];
?>

數字字面值分隔符號

數字字面值可以在數字之間包含底線。

<?php
6.674_083e-11
; // 浮點數
299_792_458; // 十進位
0xCAFE_F00D; // 十六進位
0b0101_1111; // 二進位
?>

弱參考

弱引用允許程式設計師保留對一個物件的引用,而不會阻止該物件被銷毀。

允許 __toString() 拋出例外

現在允許從 __toString() 拋出例外。以前這會導致致命錯誤。現有的字串轉換中可恢復的致命錯誤已轉換為 Error 例外。

CURL

如果擴充功能是針對 libcurl >= 7.56.0 建置的,CURLFile 現在除了支援純檔案名稱外,還支援串流包裝器。

過濾器

FILTER_VALIDATE_FLOAT 過濾器現在支援 min_rangemax_range 選項,語義與 FILTER_VALIDATE_INT 相同。

FFI

FFI 是一個新的擴充功能,它提供了一種簡單的方式來呼叫原生函式、存取原生變數,以及建立/存取 C 函式庫中定義的資料結構。

GD

新增了 IMG_FILTER_SCATTER 影像濾鏡,可將散射濾鏡應用於影像。

雜湊

使用 Castagnoli 多項式新增了 crc32c 雜湊。此 CRC32 變體用於儲存系統,例如 iSCSI、SCTP、Btrfs 和 ext4。

多位元組字串

新增了 mb_str_split() 函式,它提供與 str_split() 相同的功能,但作用於程式碼點而不是位元組。

OPcache

已新增預先載入程式碼的支援

正規表示式 (Perl 相容)

preg_replace_callback()preg_replace_callback_array() 函式現在接受額外的 flags 參數,並支援 PREG_OFFSET_CAPTUREPREG_UNMATCHED_AS_NULL 旗標。這會影響傳遞給回呼函式的相符陣列的格式。

PDO

現在可以將使用者名稱和密碼指定為 mysql、mssql、sybase、dblib、firebird 和 oci 驅動程式的 PDO DSN 的一部分。以前,只有 pgsql 驅動程式支援此功能。如果在建構函式和 DSN 中都指定了使用者名稱/密碼,則建構函式優先。

現在可以跳脫 SQL 查詢中的問號,以避免將其解釋為參數佔位符號。撰寫 ?? 允許向資料庫傳送單個問號,例如使用 PostgreSQL JSON 鍵存在 (?) 運算子。

PDO_OCI

PDOStatement::getColumnMeta() 現在可用。

PDO_SQLite

PDOStatement::getAttribute(PDO::SQLITE_ATTR_READONLY_STATEMENT) 允許檢查敘述是否為唯讀,即它是否不修改資料庫。

PDO::setAttribute(PDO::SQLITE_ATTR_EXTENDED_RESULT_CODES, true) 可在 PDO::errorInfo()PDOStatement::errorInfo() 中使用 SQLite3 擴充結果程式碼。

SQLite3

新增了 SQLite3::lastExtendedErrorCode() 來擷取最後一個擴充結果程式碼。

新增了 SQLite3::enableExtendedResultCodes($enable = true),這將使 SQLite3::lastErrorCode() 返回擴展的結果代碼。

標準

使用標籤名稱陣列的 strip_tags()

strip_tags() 現在也接受允許標籤的陣列:您現在可以寫 strip_tags($str, ['a', 'p']) 來取代 strip_tags($str, '<a><p>')

自訂物件序列化

新增了一種自訂物件序列化的新機制,它使用兩個新的魔術方法:__serialize__unserialize

<?php
// 返回包含物件所有必要狀態的陣列。
public function __serialize(): array;

// 從給定的數據陣列恢復物件狀態。
public function __unserialize(array $data): void;
?>
新的序列化機制將取代 Serializable 介面,該介面將在未來棄用。

不帶參數的陣列合併函數

array_merge()array_merge_recursive() 現在可以在不帶任何參數的情況下被呼叫,在這種情況下,它們將返回一個空陣列。這與展開運算符一起使用時很有用,例如 array_merge(...$arrays)

proc_open() 函數

proc_open() 現在接受一個陣列而不是字串作為命令。在這種情況下,進程將直接開啟(無需透過 shell),PHP 將負責任何必要的參數跳脫。

<?php
proc_open
(['php', '-r', '_r', 'echo "Hello World\n";'], $descriptors, $pipes);
?>

proc_open() 現在支援 redirectnull 描述符。

<?php
// 類似 shell 上的 2>&1
proc_open($cmd, [1 => ['pipe', 'w'], 2 => ['redirect', 1]], $pipes);
// 類似 shell 上的 2>/dev/null 或 2>nul
proc_open($cmd, [1 => ['pipe', 'w'], 2 => ['null']], $pipes);
?>

沒有 libargon 的 argon2i(d)

當 PHP 建置時沒有 libargon 時,password_hash() 現在可以使用來自 sodium 擴充的 argon2i 和 argon2id 實作。

新增註記

使用者貢獻的註記 2 則註記

Rain
4 年前
需要注意的是,型別化屬性在內部永遠不會初始化為預設的 null 值。當然,除非您自行將它們初始化為 null。這就是為什麼如果您在初始化之前嘗試存取它們,總是會遇到這個錯誤的原因。

**型別化屬性 foo::$bar 必須在初始化之前不能被存取**

<?php
class User
{
public
$id;
public
string $name; // 型別化屬性(未初始化)
public ?string $age = null; // 型別化屬性(已初始化)
}

$user = new User;
var_dump(is_null($user->id)); // bool(true)
var_dump(is_null($user->name)); // PHP 致命錯誤:型別化屬性 User::$name 必須在初始化之前不能被存取
var_dump(is_null($user->age));// bool(true)
?>

另一個值得注意的是,物件類型的屬性不能初始化為 null 以外的任何值。因為屬性的評估發生在編譯時,而物件的實例化發生在執行時。最後一點,由於 callable 類型的行為取決於上下文,因此不受支援。
wow-apps.pro
4 年前
<?php

// 如何取得屬性類型?例如用於測試:

class Foo
{
private
int $num;
private
bool $isPositive;
private
$notes;
}

$reflection = new \ReflectionClass(Foo::class);
$classProperties = $reflection->getProperties(\ReflectionProperty::IS_PRIVATE);
foreach (
$classProperties as $classProperty) {
var_dump((string) $classProperty->getType());
}

/**
* 結果:
* "int"
* "bool"
* ""
*/
To Top