2024 日本 PHP 研討會

不相容的變更

傳遞過少函式參數時拋出例外

先前,呼叫使用者定義函式時,如果參數過少,會發出警告。現在,此警告已提升為錯誤例外。此變更僅適用於使用者定義函式,不適用於內建函式。例如

<?php
function test($param){}
test();

以上範例將輸出類似以下的內容:

Fatal error: Uncaught ArgumentCountError: Too few arguments to function test(), 0 passed in %s on line %d and exactly 1 expected in %s:%d

禁止對範圍自省函式進行動態呼叫

某些函式的動態呼叫已被禁止(例如 $func()array_map('extract', ...) 等形式)。這些函式會檢查或修改其他範圍,並呈現出模稜兩可且不可靠的行為。這些函式如下:

<?php
(function () {
$func = 'func_num_args';
$func();
})();

以上範例將輸出:

Warning: Cannot call func_num_args() dynamically in %s on line %d

無效的類別、介面和特性名稱

以下名稱不能用於命名類別、介面或特性:

數值字串轉換現在會遵守科學記號表示法

對數值字串進行整數運算和轉換現在會遵守科學記號表示法。這也包括 (int) 轉型運算,以及以下函式:intval()(基數為 10 時)、settype()decbin()decoct()dechex()

修正 mt_rand() 演算法

mt_rand() 現在預設會使用修正後的梅森旋轉演算法版本。如果先前依賴 mt_rand() 的確定性輸出,則可以將 MT_RAND_PHP 作為 mt_srand() 的選用第二個參數,以保留舊的(不正確的)實現方式。

rand() 設定為 mt_rand() 的別名,srand() 設定為 mt_srand() 的別名

rand()srand() 現在分別設定為 mt_rand()mt_srand() 的別名。這表示以下函式的輸出已變更:rand()shuffle()str_shuffle()array_rand()

禁止在識別碼中使用 ASCII 刪除控制字元

ASCII 刪除控制字元 (0x7F) 不再能用於未加引號的識別名稱中。

error_log 設定會隨著 syslog 值而改變

如果 ini 設定檔中的 error_log 設定為 syslog,PHP 錯誤級別會映射到 syslog 錯誤級別。與先前所有錯誤都以 notice 級別記錄的做法相比,這在錯誤日誌中帶來了更細緻的區分。

不要對未完整建構的物件呼叫解構函式

對於在建構函式執行期間拋出例外狀況的物件,現在永遠不會呼叫解構函式。在以前的版本中,此行為取決於物件是否在建構函式外部被引用(例如,透過例外回溯)。

call_user_func() 處理參考參數的方式

現在,當呼叫需要參考作為參數的函式時,call_user_func() 總會產生警告。以前,這取決於呼叫是否完全限定。

此外,在這種情況下,call_user_func()call_user_func_array() 不再中止函式呼叫。將會發出「預期參考」警告,但呼叫將會照常進行。

不再支援對字串使用空的索引運算子

將空的索引運算子應用於字串(例如 $str[] = $x)會拋出致命錯誤,而不是靜默地轉換為陣列。

透過字串索引在空字串上進行賦值

現在,在空字串上透過字元修改字串的方式與非空字串相同,也就是說,寫入超出範圍的偏移量會以空格填充字串,其中非整數類型會轉換為整數,並且只使用賦值字串的第一個字元。以前,空字串會被靜默地視為空陣列。

<?php
$a
= '';
$a[10] = 'foo';
var_dump($a);
?>

以上範例在 PHP 7.0 中的輸出

array(1) {
  [10]=>
  string(3) "foo"
}

以上範例在 PHP 7.1 中的輸出

string(11) "          f"

已移除的 ini 指令

以下 ini 指令已被移除

  • session.entropy_file
  • session.entropy_length
  • session.hash_function
  • session.hash_bits_per_character

在透過參考賦值自動建立元素時,陣列的排序已更改

當陣列中的元素是透過在參考賦值中引用它們而自動建立時,這些元素的順序已更改。例如

<?php
$array
= [];
$array["a"] =& $array["b"];
$array["b"] = 1;
var_dump($array);
?>

以上範例在 PHP 7.0 中的輸出

array(2) {
  ["a"]=>
  &int(1)
  ["b"]=>
  &int(1)
}

以上範例在 PHP 7.1 中的輸出

array(2) {
  ["b"]=>
  &int(1)
  ["a"]=>
  &int(1)
}

相同元素的排序順序

內部排序演算法已改良,這可能導致比較結果相等的元素排序順序與以往不同。

注意:

不要依賴比較結果相等元素的順序;它隨時可能改變。

E_RECOVERABLE 錯誤的錯誤訊息

E_RECOVERABLE 錯誤的錯誤訊息已從「可捕捉的致命錯誤 (Catchable fatal error)」更改為「可恢復的致命錯誤 (Recoverable fatal error)」。

unserialize() 的 $options 參數

unserialize() 的 $options 參數中的 allowed_classes 元素現在是嚴格型別的,也就是說,如果給定的值不是 陣列布林值,unserialize() 將會回傳 false 並發出 E_WARNING 警告。

DateTime 建構函式納入微秒

DateTimeDateTimeImmutable 現在在根據目前時間建構時,無論是明確指定或使用相對字串(例如 "next month 的第一天"),都會正確地納入微秒。這表示兩個新建立的實例進行單純比較時,現在更有可能回傳 false 而不是 true

<?php
new DateTime() == new DateTime();
?>

致命錯誤轉換為 Error 例外

在日期擴充功能中,DateTimeDatePeriod 類別的無效序列化資料,或從序列化資料初始化時區失敗,現在會從 __wakeup()__set_state() 方法拋出 Error 例外,而不是造成致命錯誤。

在 DBA 擴充功能中,如果鍵值不包含恰好兩個元素,資料修改函式(例如 dba_insert())現在會拋出 Error 例外,而不是觸發可捕捉的致命錯誤。

在 DOM 擴充功能中,無效的 Schema 或 RelaxNG 驗證上下文現在會拋出 Error 例外,而不是造成致命錯誤。同樣地,嘗試註冊未繼承適當基底類別的節點類別,或嘗試讀取無效的屬性或寫入唯讀屬性,現在也會拋出 Error 例外。

在 IMAP 擴充功能中,超過 16385 位元組的電子郵件地址會拋出 Error 例外,而不是造成致命錯誤。

在 Intl 擴充功能中,在繼承 Collator 的類別中,如果在呼叫父方法之前未呼叫父建構函式,現在會拋出 Error 例外,而不是造成可恢復的致命錯誤。此外,複製 Transliterator 物件時,如果複製內部轉換器失敗,現在會拋出 Error 例外,而不是造成致命錯誤。

在 LDAP 擴充功能中,提供未知的修改類型給 ldap_batch_modify() 現在會拋出 Error 例外,而不是造成致命錯誤。

在 mbstring 擴充套件中,如果提供了無效的 PHP 表達式並使用了 'e' 選項,mb_ereg()mb_eregi() 函式現在將拋出 ParseError 異常。

在 Mcrypt 擴充套件中,如果無法初始化 mcrypt,mcrypt_encrypt()mcrypt_decrypt() 現在將拋出 Error 異常,而不是產生致命錯誤。

在 mysqli 擴充套件中,嘗試讀取無效的屬性或寫入唯讀屬性現在將拋出 Error 異常,而不是產生致命錯誤。

在 Reflection 擴充套件中,無法取得反射物件或取得物件屬性現在將拋出 Error 異常,而不是產生致命錯誤。

在 Session 擴充套件中,如果自訂的 session 處理器沒有傳回字串類型的 session ID,當呼叫必須產生 session ID 的函式時,現在將拋出 Error 異常,而不是產生致命錯誤。

在 SimpleXML 擴充套件中,建立未命名或重複的屬性現在將拋出 Error 異常,而不是產生致命錯誤。

在 SPL 擴充套件中,嘗試複製 SplDirectory 物件現在將拋出 Error 異常,而不是產生致命錯誤。同樣地,在迭代物件時呼叫 ArrayIterator::append() 現在也會拋出 Error 異常。

在標準擴充套件中,當 assert() 函式的第一個參數為字串參數時,如果 PHP 程式碼無效,現在將拋出 ParseError 異常,而不是產生可捕捉的致命錯誤。同樣地,在類別範圍之外呼叫 forward_static_call() 現在將拋出 Error 異常。

在 Tidy 擴充套件中,手動建立 tidyNode 現在將拋出 Error 異常,而不是產生致命錯誤。

在 WDDX 擴充套件中,序列化時出現循環引用現在將拋出 Error 異常,而不是產生致命錯誤。

在 XML-RPC 擴充套件中,序列化時出現循環引用現在將拋出 Error 異常的實例,而不是產生致命錯誤。

在 Zip 擴充套件中,如果沒有 glob 支援,ZipArchive::addGlob() 方法現在將拋出 Error 異常,而不是產生致命錯誤。

詞法綁定的變數不能重複使用名稱

透過 use 建構式綁定到 閉包 (closure) 的變數,不能與任何 超全域變數 (superglobals)$this 或任何參數使用相同的名稱。例如,以下所有函式定義都會導致致命錯誤:

<?php
$f
= function () use ($_SERVER) {};
$f = function () use ($this) {};
$f = function ($param) use ($param) {};

long2ip() 參數類型變更

long2ip() 現在預期接收 整數 (int) 而不是 字串 (string)

JSON 編碼和解碼

現在,ini 設定 serialize_precision 會在編碼 浮點數 (float) 時控制序列化精度。

解碼空鍵值現在會產生空的屬性名稱,而不是像以前那樣產生 _empty_ 作為屬性名稱。

<?php
var_dump
(json_decode(json_encode(['' => 1])));

以上範例將輸出類似以下的內容:

object(stdClass)#1 (1) {
  [""]=>
  int(1)
}

當提供 JSON_UNESCAPED_UNICODE 旗標給 json_encode() 時,序列 U+2028 和 U+2029 現在會被跳脫 (escaped)。

mb_ereg()mb_eregi() 參數語義的變更

如果沒有匹配到任何內容,mb_ereg()mb_eregi() 函式的第三個參數 (regs) 現在會被設定為空陣列。以前,該參數不會被修改。

不再支援 sslv2 串流

OpenSSL 中的 sslv2 串流已被移除。

在編譯時期禁止在已設定回傳型別的函式中使用 "return;"

在宣告了回傳型別的函式中,沒有參數的 return 陳述式現在會觸發 E_COMPILE_ERROR(除非回傳型別宣告為 void),即使該 return 陳述式永遠不會被執行到。

新增註記

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

love at sickpeople dot se
8 年前
給任何從 5.x 遷移到 7.1 的人

關於此頁面上的「當元素在透過參考賦值自動建立時,陣列排序已更改」

(https://php.dev.org.tw/manual/en/migration71.incompatible.php#migration71.incompatible.array-order)

7.1 的行為與 PHP 5 的行為相同。只有 7.0 不同。

請參閱 https://3v4l.org/frbUc

<?php

$array
= [];
$array["a"] =& $array["b"];
$array["b"] = 1;
var_dump($array);
kees at twekaers dot net
7 年前
向後不相容的變更「不再支援字串的空索引運算子」的影響,遠比在以下程式碼中產生致命錯誤來得大:

<?php
$a
= "";
$a[] = "hello world";
var_dump($a);
?>

這段程式碼在 7.1 版會產生致命錯誤,但在 7.0 或更低版本中會如預期般運作,並得到以下結果:(無通知,無警告)

array(1) {
[0]=>
string(11) "hello world"
}

然而,以下行為也有所改變:

<?php
$a
= "";
$a[0] = "hello world";
var_dump($a);
// 7.1: string(1) "h"
// 7.1 之前: array(1) { [0]=> string(11) "hello world" }

$a = "";
$a[5] = "hello world";
var_dump($a);
// 7.1: string(6) " h"
// 7.1 之前: array(1) { [0]=> string(11) "hello world" }

?>
m dot r dot sopacua at gmail dot com
7 年前
「我的天啊!為什麼 session.hash_function 被移除了?!老兄!」

https://wiki.php.net/rfc/session-id-without-hashing

在這。省得你搜尋了。
mikem at gmail dot com
7 年前
ArgumentCountError - 這個修改是避免在舊專案中使用此版本的主要原因。
david at artefactual dot com
5 年前
關於 ArgumentCountError,PHP 7.1+ 仍然支援具有可變數量參數的使用者函式,使用 "func(...$args) {}" 語法,請參閱:https://php.dev.org.tw/manual/en/functions.arguments.php#functions.variable-arg-list
To Top