在 PHP 7 中,許多致命錯誤和可復原的致命錯誤已轉換為例外。這些錯誤例外繼承自 Error 類別,該類別本身實作了 Throwable 介面(所有例外繼承的新基底介面)。
這意味著自訂錯誤處理器可能不再被觸發,因為可能會改為拋出例外(導致未捕獲的 Error 例外產生新的致命錯誤)。
關於 PHP 7 中錯誤如何運作的更完整描述,可以在PHP 7 錯誤頁面找到。本遷移指南僅列舉影響向下相容性的變更。
使用 Exception 類型宣告,以 set_exception_handler() 註冊例外處理器的程式碼,在拋出 Error 物件時,將會導致致命錯誤。
如果處理器需要同時在 PHP 5 和 7 上運作,您應該從處理器中移除類型宣告,而專門遷移到 PHP 7 上運作的程式碼,則可以簡單地將 Exception 類型宣告替換為 Throwable。
<?php
// PHP 5 時代的程式碼將會失效。
function handler(Exception $e) { ... }
set_exception_handler('handler');
// 與 PHP 5 和 7 相容。
function handler($e) { ... }
// 僅限 PHP 7。
function handler(Throwable $e) { ... }
?>
剖析器錯誤現在會拋出 ParseError 物件。 eval() 的錯誤處理現在應該包含一個可以處理此錯誤的 catch
區塊。
所有 E_STRICT
通知皆已重新分類到其他層級。E_STRICT
常數被保留,因此像 error_reporting(E_ALL|E_STRICT)
這樣的呼叫不會造成錯誤。
情況 | 新的層級/行為 |
---|---|
以資源作為索引 | E_NOTICE |
抽象靜態方法 | 已移除通知,不會觸發錯誤 |
「重新定義」建構函式 | 已移除通知,不會觸發錯誤 |
繼承期間的簽章不符 | E_WARNING |
兩個使用的 trait 中的相同(相容)屬性 | 已移除通知,不會觸發錯誤 |
以非靜態方式存取靜態屬性 | E_NOTICE |
只有變數應該透過參考賦值 | E_NOTICE |
只有變數應該透過參考傳遞 | E_NOTICE |
以靜態方式呼叫非靜態方法 | E_DEPRECATED |
PHP 7 現在在解析原始碼檔案時使用抽象語法樹 (AST)。這允許對語言進行許多先前由於早期 PHP 版本中解析器的限制而無法實現的改進,但也導致為了保持一致性而移除了一些特殊情況,從而造成了一些向後相容性的破壞。本節將詳細說明這些情況。
對變數、屬性和方法的間接存取現在將嚴格按照從左到右的順序進行評估,而不是像以前那樣混合使用特殊情況。下表顯示了評估順序的變化。
表達式 | PHP 5 的解譯 | PHP 7 的解譯 |
---|---|---|
$$foo['bar']['baz']
|
${$foo['bar']['baz']}
|
($$foo)['bar']['baz']
|
$foo->$bar['baz']
|
$foo->{$bar['baz']}
|
($foo->$bar)['baz']
|
$foo->$bar['baz']()
|
$foo->{$bar['baz']}()
|
($foo->$bar)['baz']()
|
Foo::$bar['baz']()
|
Foo::{$bar['baz']}()
|
(Foo::$bar)['baz']()
|
使用舊的從右到左評估順序的程式碼必須重寫,使用大括號明確指定該評估順序(參見上表中間一欄)。這將使程式碼同時向前相容於 PHP 7.x 和向後相容於 PHP 5.x。
這也會影響 global
關鍵字。如果需要,可以使用大括號語法來模擬先前的行為。
<?php
function f() {
// 僅在 PHP 5 中有效。
global $$foo->bar;
// 在 PHP 5 和 7 中都有效。
global ${$foo->bar};
}
?>
list() 現在將按照變數定義的順序賦值,而不是相反的順序。通常,這只會影響 list() 與陣列 []
運算子一起使用的情況,如下所示
<?php
list($a[], $a[], $a[]) = [1, 2, 3];
var_dump($a);
?>
上述範例在 PHP 5 中的輸出
array(3) { [0]=> int(3) [1]=> int(2) [2]=> int(1) }
上述範例在 PHP 7 中的輸出
array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) }
一般來說,建議不要依賴 list() 賦值的順序,因為這是一個實作細節,未來可能會再次改變。
list() 建構式不能再為空。以下用法不再允許
<?php
list() = $a;
list(,,) = $a;
list($x, list(), $y) = $a;
?>
list() 不再能解開字串變數。應使用 str_split() 取代。
當陣列元素是透過參照賦值自動建立時,元素的順序已改變。例如:
<?php
$array = [];
$array["a"] =& $array["b"];
$array["b"] = 1;
var_dump($array);
?>
上述範例在 PHP 5 中的輸出
array(2) { ["b"]=> &int(1) ["a"]=> &int(1) }
上述範例在 PHP 7 中的輸出
array(2) { ["a"]=> &int(1) ["b"]=> &int(1) }
在 PHP 5 中,在函式參數周圍使用多餘的括號可以在以參照方式傳遞函式參數時隱藏嚴格標準警告。現在將始終發出警告。
<?php
function getArray() {
return [1, 2, 3];
}
function squareArray(array &$a) {
foreach ($a as &$v) {
$v **= 2;
}
}
// 在 PHP 7 中會產生警告。
squareArray((getArray()));
?>
上述範例將輸出:
Notice: Only variables should be passed by reference in /tmp/test.php on line 13
foreach 控制結構的行為有一些小幅度的變更,主要圍繞在內部陣列指標的處理以及對迭代中陣列的修改。
在 PHP 7 之前,使用 foreach 迭代陣列時,內部陣列指標會被修改。現在已不再如此,如下例所示:
<?php
$array = [0, 1, 2];
foreach ($array as &$val) {
var_dump(current($array));
}
?>
上述範例在 PHP 5 中的輸出
int(1) int(2) bool(false)
上述範例在 PHP 7 中的輸出
int(0) int(0) int(0)
當使用預設的以值傳遞模式時,foreach 現在會操作正在迭代的陣列的副本,而不是陣列本身。這意味著在迭代期間對陣列所做的更改不會影響正在迭代的值。
當以參考傳遞進行迭代時,foreach 現在可以更好地追蹤迭代期間對陣列所做的更改。例如,在迭代時附加到陣列現在會導致附加的值也被迭代。
<?php
$array = [0];
foreach ($array as &$val) {
var_dump($val);
$array[1] = 1;
}
?>
上述範例在 PHP 5 中的輸出
int(0)
上述範例在 PHP 7 中的輸出
int(0) int(1)
迭代非 Traversable 物件現在將與迭代以參考傳遞的陣列具有相同的行為。這導致 在迭代期間修改陣列時的改進行為 也會在物件新增或移除屬性時套用。
以前,包含無效數字的八進位字面值會被靜默截斷(0128
被視為 012
)。現在,無效的八進位字面值將會導致剖析錯誤。
以負數進行位元位移現在將會拋出 ArithmeticError
<?php
var_dump(1 >> -1);
?>
上述範例在 PHP 5 中的輸出
int(0)
上述範例在 PHP 7 中的輸出
Fatal error: Uncaught ArithmeticError: Bit shift by negative number in /tmp/test.php:2 Stack trace: #0 {main} thrown in /tmp/test.php on line 2
超出 整數 位元寬度的位元位移(無論哪個方向)將永遠導致 0。以前,這種位移的行為取決於架構。
先前,當 0 作為除法 (/) 或取餘 (%) 運算子的除數時,會發出 E_WARNING 並返回 **false
**。現在,除法運算子會根據 IEEE 754 規範,返回一個浮點數,其值為 +INF、-INF 或 NAN。取餘運算子的 E_WARNING 已移除,並會拋出 DivisionByZeroError 例外。
<?php
var_dump(3/0);
var_dump(0/0);
var_dump(0%0);
?>
上述範例在 PHP 5 中的輸出
Warning: Division by zero in %s on line %d bool(false) Warning: Division by zero in %s on line %d bool(false) Warning: Division by zero in %s on line %d bool(false)
上述範例在 PHP 7 中的輸出
Warning: Division by zero in %s on line %d float(INF) Warning: Division by zero in %s on line %d float(NAN) PHP Fatal error: Uncaught DivisionByZeroError: Modulo by zero in %s line %d
包含十六進位數字的字串將不再被視為數值。例如:
<?php
var_dump("0x123" == "291");
var_dump(is_numeric("0x123"));
var_dump("0xe" + "0x1");
var_dump(substr("foo", "0x1"));
?>
上述範例在 PHP 5 中的輸出
bool(true) bool(true) int(15) string(2) "oo"
上述範例在 PHP 7 中的輸出
bool(false) bool(false) int(0) Notice: A non well formed numeric value encountered in /tmp/test.php on line 5 string(3) "foo"
可以使用 filter_var() 函式來檢查字串是否包含十六進位數字,也可以將這種類型的字串轉換為整數 (int)。
<?php
$str = "0xffff";
$int = filter_var($str, FILTER_VALIDATE_INT, FILTER_FLAG_ALLOW_HEX);
if (false === $int) {
throw new Exception("Invalid integer!");
}
var_dump($int); // int(65535)
?>
\u{
可能會造成錯誤由於新增了新的 Unicode 字碼點跳脫語法,包含字面 \u{
後接無效序列的字串將會造成致命錯誤。為了避免這種情況,開頭的反斜線應該要跳脫。
PHP 4.1.0 版中已將下列函式標記為棄用,建議改用 call_user_func() 和 call_user_func_array()。您也可以考慮使用可變函式以及/或者...
運算子。
所有 ereg
函式皆已移除。建議使用 PCRE 作為替代方案。
已移除棄用的 mcrypt_generic_end() 函式,建議改用 mcrypt_generic_deinit()。
此外,也已移除棄用的 mcrypt_ecb()、mcrypt_cbc()、mcrypt_cfb() 和 mcrypt_ofb() 函式,建議使用 mcrypt_decrypt() 搭配適當的 MCRYPT_MODE_*
常數。
所有 ext/mysql 函式皆已移除。關於選擇其他 MySQL API 的詳細資訊,請參閱 選擇 MySQL API。
已移除棄用的 datefmt_set_timezone_id() 和 IntlDateFormatter::setTimeZoneID() 別名,建議分別改用 datefmt_set_timezone() 和 IntlDateFormatter::setTimeZone()。
set_magic_quotes_runtime() 以及它的別名 magic_quotes_runtime() 已移除。它們在 PHP 5.3.0 中被標記為棄用,並在 PHP 5.4.0 中移除魔術引號後實際上失效。
已移除棄用的 set_socket_blocking() 別名,建議改用 stream_set_blocking()。
GD 擴充功能已移除對 PostScript Type1 字體的支援,導致以下函式也被移除:
建議改用 TrueType 字體及其相關函式。
由於相關功能已被移除,以下 INI 指令也已被移除:
always_populate_raw_post_data
asp_tags
xsl.security_prefs
xsl.security_prefs
指令已移除。建議改用 XsltProcessor::setSecurityPrefs() 方法,以便針對每個處理器控制安全性設定。
new
陳述式的結果已無法再以參照方式賦值給變數。
<?php
class C {}
$c =& new C;
?>
上述範例在 PHP 5 中的輸出
Deprecated: Assigning the return value of new by reference is deprecated in /tmp/test.php on line 3
上述範例在 PHP 7 中的輸出
Parse error: syntax error, unexpected 'new' (T_NEW) in /tmp/test.php on line 3
以下名稱不能用於命名類別、介面或 Trait:
此外,也不應該使用以下名稱。雖然它們在 PHP 7.0 中不會產生錯誤,但它們是保留給未來使用的,應視為已棄用。
不再支援使用 ASP 和 script 標籤來界定 PHP 程式碼。受影響的標籤如下:
起始標籤 | 結束標籤 |
---|---|
<% |
%> |
<%= |
%> |
<script language="php"> |
</script> |
在不相容的上下文中以靜態方式呼叫非靜態方法,先前在 PHP 5.6 中已棄用,現在將導致被呼叫的方法具有未定義的 $this
變數,並發出棄用警告。
<?php
class A {
public function test() { var_dump($this); }
}
// 注意:並未繼承 A
class B {
public function callNonStaticMethodOfA() { A::test(); }
}
(new B)->callNonStaticMethodOfA();
?>
上述範例在 PHP 5.6 中的輸出
Deprecated: Non-static method A::test() should not be called statically, assuming $this from incompatible context in /tmp/test.php on line 8 object(B)#1 (0) { }
上述範例在 PHP 7 中的輸出
Deprecated: Non-static method A::test() should not be called statically in /tmp/test.php on line 8 Notice: Undefined variable: this in /tmp/test.php on line 3 NULL
yield 建構式不再需要括號,並且已變更為右結合運算子,其優先順序介於 print
和 =>
之間。這可能會導致行為改變
<?php
echo yield -1;
// 之前的解釋方式為
echo (yield) - 1;
// 現在的解釋方式為
echo yield (-1);
yield $foo or die;
// 之前的解釋方式為
yield ($foo or die);
// 現在的解釋方式為
(yield $foo) or die;
?>
可以使用括號來消除這些情況的歧義。
定義兩個或多個同名函式參數將不再被允許。例如,以下函式將觸發 E_COMPILE_ERROR
錯誤
<?php
function foo($a, $b, $unused, $unused) {
//
}
?>
func_get_arg()、func_get_args()、debug_backtrace() 和例外回溯將不再回報傳遞給參數的原始值,而是提供目前的值(可能已被修改)。
<?php
function foo($x) {
$x++;
var_dump(func_get_arg(0));
}
foo(1);?>
上述範例在 PHP 5 中的輸出
1
上述範例在 PHP 7 中的輸出
2
在 switch 陳述式中定義兩個或多個預設區塊將不再被允許。例如,以下 switch 陳述式將觸發 E_COMPILE_ERROR
錯誤
<?php
switch (1) {
default:
break;
default:
break;
}
?>
$HTTP_RAW_POST_DATA 已不再可用。應改用 php://input
資料流。
#
註解已移除在 INI 檔案中使用 #
作為註解前綴的支援。應改用 ;
(分號)。此變更適用於 php.ini 以及 parse_ini_file() 和 parse_ini_string() 處理的檔案。
JSON 模組已由 JSOND 取代,造成三個輕微的向下相容性破壞。首先,數字不得以小數點結尾(即 34.
必須改為 34.0
或 34
)。其次,使用科學記號表示法時,e
指數不得緊接在小數點之後(即 3.e3
必須改為 3.0e3
或 3e3
)。最後,空字串不再被視為有效的 JSON。
先前,當浮點數太大而無法表示為整數時,內建函式會在浮點數轉換為整數時靜默地截斷數字。現在,將發出 E_WARNING 警告,並回傳 null
。
由自訂 Session 處理器實作的任何斷言函式,如果回傳 false
或 -1
都將造成致命錯誤。如果這些函式回傳的值不是布林值、-1
或 0
,則會失敗並發出 E_WARNING 警告。
內部排序演算法已改良,這可能導致比較結果相等的元素排序順序與之前不同。
注意:
不要依賴比較結果相等元素的排序順序;它隨時可能改變。
在迴圈或 switch
控制結構之外的 break
和 continue
陳述式現在會在編譯時而不是像以前一樣在執行時被偵測到,並觸發 E_COMPILE_ERROR
編譯錯誤。
break
和 continue
陳述式不再允許其參數為常數,並會觸發 E_COMPILE_ERROR
編譯錯誤。
Mhash 擴充套件已完全整合到 雜湊 (Hash) 擴充套件中。因此,不再能夠使用 extension_loaded() 函式來偵測 Mhash 支援;請改用 function_exists() 函式。此外,get_loaded_extensions() 和相關功能也不再回報 Mhash。
declare(ticks) 指令不再洩漏到不同的編譯單元。