PHP 7.2 參考
PHP 7.1 參考
PHP 7 於 2015 年 12 月 3 日發布。
表現
特徵
組合比較運算符
空合併運算符
標量類型聲明
回傳類型聲明
匿名類
Unicode 代碼點轉義語法
關閉call()
方法
過濾反unserialize()
IntlChar
類
期望
團體use
聲明
生成器返回表達式
生成器委託
使用intdiv()
進行整數除法
session_start()
選項
preg_replace_callback_array()
函數
CSPRNG 函數
define()
中對陣列常數的支持
反射添加
變化
放寬保留字限制
統一變數語法
引擎中的異常
可拋出接口
整數語意
JSON 擴充替換為 JSOND
ZPP 外溢失敗
修復foreach()
的行為
list()
行為的更改
除以零語意的變化
修復自訂會話處理程序傳回值
棄用 PHP 4 風格的建構函數
刪除 date.timezone 警告
刪除替代 PHP 標籤
刪除 Switch 語句中的多個預設區塊
刪除重複名稱參數的重新定義
刪除死伺服器 API
刪除數字字串中的十六進制支持
刪除已棄用的功能
E_STRICT 通知的重新分類和刪除
棄用password_hash()
的 Salt 選項
無效八進位文字錯誤
substr()
傳回值變化
常問問題
PHP 6 發生了什麼事?
毫無疑問,PHP 7 最偉大的部分是它為應用程式提供了令人難以置信的效能提升。這是重構 Zend 引擎以使用更緊湊的資料結構和更少的堆分配/解除分配的結果。
實際應用程式的效能提升會有所不同,但許多應用程式似乎獲得了約 100% 的效能提升 - 記憶體消耗也更低!
重構的程式碼庫也為未來的最佳化(例如 JIT 編譯)提供了進一步的機會。所以看起來未來的 PHP 版本也會繼續看到效能增強。
PHP 7 效能圖表比較:
使用 PHP 7 增強 Web 效能
拉斯姆斯悉尼演講的基準
組合比較運算子(或太空船運算子)是用於從兩個操作數執行三向比較的簡寫符號。它有一個整數回傳值,可以是:
正整數(如果左側操作數大於右側操作數)
0(如果兩個操作數相等)
負整數(如果右側操作數大於左側操作數)
此運算子與相等運算子( ==
、 !=
、 ===
、 !==
)具有相同的優先權,並且與其他鬆散比較運算子( <
、 >=
等)具有完全相同的行為。它也像它們一樣是非關聯的,因此不允許連結操作數(如1 <=> 2 <=> 3
)。
// 比較字串 lexicallyvar_dump('PHP' <=> 'Node'); // int(1)// 依大小比較數字var_dump(123 <=> 456); // int(-1)// 將對應的陣列元素與另一個進行比較var_dump(['a', 'b'] <=> ['a', 'b']); // 整數(0)
物件不具有可比性,因此將它們用作此運算符的操作數將導致未定義的行為。
RFC:組合比較運算符
空合併運算子(或 isset 三元運算子)是在三元運算子中執行isset()
檢查的簡寫符號。這是應用程式中常見的事情,因此為此目的引入了新語法。
// PHP 7 之前的程式碼$route = isset($_GET['route']) ? $_GET['route'] : 'index';// PHP 7+ 代碼$route = $_GET['route'] ?? '指數';
RFC:空合併運算符
標量類型聲明有兩種風格:強制(預設)和嚴格。現在可以強制執行以下參數類型(強製或嚴格):字串 ( string
)、整數 ( int
)、浮點數 ( float
) 和布林值 ( bool
)。它們增強了 PHP 5.x 版本中引入的其他類型:類別名稱、介面、 array
和callable
。
// 強制模式function sumOfInts(int ...$ints) { 回傳 array_sum($ints); }var_dump(sumOfInts(2, '3', 4.1)); // 整數(9)
若要啟用嚴格模式,必須將單一declare()
指令放置在檔案頂部。這意味著標量輸入的嚴格性是基於每個檔案配置的。該指令不僅影響參數的類型聲明,還影響函數的返回類型(請參閱返回類型聲明)、內建 PHP 函數以及載入擴充功能中的函數。
如果類型檢查失敗,則會拋出TypeError
異常(請參閱引擎中的例外狀況)。嚴格型別中唯一的寬鬆之處是當在浮點上下文中提供整數時,自動將整數轉換為浮點數(反之亦然)。
宣告(strict_types=1);函數乘法(float $x, float $y) { 返回 $x * $y; }函數新增(int $x,int $y) { 返回 $x + $y; }var_dump(乘法(2, 3.5)); // float(7)var_dump(add('2', 3)); // 致命錯誤:未捕獲類型錯誤:傳遞給 add() 的參數 1 必須是整數類型,給定字串...
請注意,執行類型檢查時僅套用呼叫上下文。這意味著嚴格類型僅適用於函數/方法調用,而不適用於函數/方法定義。在上面的範例中,這兩個函數可以在嚴格檔案或強製檔案中聲明,但只要在嚴格檔案中呼叫它們,就將應用嚴格的類型規則。
BC 休息
現在禁止使用名稱為int
、 string
、 float
和bool
的類別。
RFC:標量類型聲明
傳回類型宣告可以指定函數、方法或閉包的傳回類型。支援以下回傳類型: string
、 int
、 float
、 bool
、 array
、 callable
、 self
(僅限方法)、 parent
(僅限方法)、 Closure
、類別的名稱和介面的名稱。
函式 arraysSum(array ...$arrays): array{ return array_map(function(array $array): int { return array_sum($array); } }, $數組); }print_r(arraysSum([1,2,3], [4,5,6], [7,8,9]));/* OutputArray( [0] => 6 [1] => 15 [2] => 24)*/
對於子類型化,傳回類型選擇了不變性。這僅僅意味著當一個方法在子類型類別中被重寫或按照協定中的定義實現時,其返回類型必須與其正在(重新)實現的方法完全匹配。
A 類 {}B 類別擴充 A {}C 類 { 公用函數測試():A { 返回新的 A; } }D 類別擴展了 C { // 重寫方法 C::test() : A public function test() : B // 由於變異數不符而導致致命錯誤 { 返回新的 B; } }
重寫方法D::test() : B
會導致E_COMPILE_ERROR
因為不允許協方差。為了使其工作, D::test()
方法必須具有A
的回傳類型。
A 類別{}介面 SomeInterface { 公用函數測試() : A; }B類別實作SomeInterface { public function test() : A // 一切都好! { 傳回空值; // 致命錯誤:未擷取型別錯誤:B::test() 的傳回值必須是 A 的實例,傳回 null... } }
這次,所實現的方法在執行時會引發TypeError
異常(請參閱引擎中的異常)。這是因為null
不是有效的回傳類型 - 只能傳回類別A
的實例。
RFC:傳回類型聲明
當需要建立簡單的一次性物件時,匿名類別非常有用。
// PHP 7 之前的程式碼類別記錄器 { 公用函數日誌($msg) { 回顯 $msg; } }$util->setLogger(new Logger());// PHP 7+ 程式碼$util->setLogger(new class { public function log($msg) { 回顯 $msg; } });
它們可以將參數傳遞給建構函式、擴展其他類別、實作介面以及使用特徵,就像普通類別一樣:
類別 SomeClass {}介面 SomeInterface {}特徵 SomeTrait {}var_dump(new class(10) 擴充 SomeClass 實作 SomeInterface { 私有 $num; 公用函數 __construct($num) { $this->num = $num; 使用 SomeTrait; });/** 輸出:object(class@anonymous)#1 (1) { ["命令列程式碼0x104c5b612":"class@anonymous":private]=> int(10)}*/
將匿名類別嵌套在另一個類別中不會使其存取該外部類別的任何私有或受保護的方法或屬性。為了使用外部類別的受保護的屬性或方法,匿名類別可以擴展外部類別。要在匿名類別中使用外部類別的私有或受保護屬性,必須透過其建構子傳遞它們:
<?phpclass 外部 { 私人 $prop = 1; 受保護的 $prop2 = 2; 受保護函數 fun1() { 返回 3; } 公用函數 func2() { return new class($this->prop) 擴充 Outer { private $prop3; 公用函數 __construct($prop) { $this->prop3 = $prop; } 公用函數 func3() { 回傳 $this->prop2 + $this->prop3 + $this->func1(); } }; } }echo (新外層)->func2()->func3(); // 6
RFC:匿名類
這使得 UTF-8 編碼的 unicode 代碼點能夠以雙引號字串或定界符輸出。接受任何有效的代碼點,前導0
是可選的。
回顯“u{aa}”; // ªecho "u{0000aa}"; // ª(與之前相同,但附有可選的前導 0)echo "u{9999}"; // 香
RFC:Unicode 代碼點轉義語法
閉包的新call()
方法用作呼叫閉包同時將物件範圍綁定到閉包的簡寫方式。透過消除在呼叫之前創建中間閉包的需要,這可以創建更高效能和更緊湊的程式碼。
class A {private $x = 1;}// PHP 7 之前的程式碼$getXCB = function() {return $this->x;};$getX = $getXCB->bindTo(new A, 'A'); // 中間的closureecho $getX(); // 1// PHP 7+ 程式碼$getX = function() {return $this->x;};echo $getX->call(new A); // 1
RFC:關閉::調用
unserialize()
此功能旨在在反序列化不受信任資料上的物件時提供更好的安全性。它使開發人員能夠將可反序列化的類別列入白名單,從而防止可能的程式碼注入。
// 將所有物件轉換為__PHP_Incomplete_Class object$data = unserialize($foo, ["allowed_classes" => false]);// 將除MyClass 和MyClass2 之外的所有物件轉換為__PHP_Incomplete_Class 物件$data = unMyserialize( $foo, [" allowed_classes" => ["MyClass", "MyClass2"]]);// 接受所有類別的預設行為(與省略第二個參數相同)$data = unserialize($foo, ["allowed_classes" => true]);
RFC:過濾反序列化()
IntlChar
類新的IntlChar
類別旨在公開額外的 ICU 功能。該類別本身定義了許多可用於操作 unicode 字元的靜態方法和常數。
printf('%x', IntlChar::CODEPOINT_MAX); // 10ffffecho IntlChar::charName('@'); // 商業 ATvar_dump(IntlChar::ispunct('!')); // 布林值(真)
為了使用此類,必須安裝Intl
擴充功能。
BC 休息
全域命名空間中的類別不得稱為IntlChar
。
RFC:IntlChar 類
期望是對舊的assert()
函數的向後相容增強。它們可以在生產程式碼中實現零成本斷言,並提供在錯誤時拋出自定義異常的能力。
assert()
函數的原型如下:
void assert (mixed $expression [, mixed $message]);
與舊的 API 一樣,如果$expression
是字串,那麼它將被求值。如果第一個參數為假,則斷言失敗。第二個參數可以是純字串(導致觸發 AssertionError),也可以是包含錯誤訊息的自訂異常物件。
ini_set('assert.exception', 1);class CustomError extends AssertionError {}assert(false, new CustomError('一些錯誤訊息'));
此功能附帶兩個 PHP.ini 設定(及其預設值):
zend.斷言= 1
斷言異常 = 0
zend.assertions有三個值:
1 = 產生並執行程式碼(開發模式)
0 = 產生程式碼並在運行時跳轉
-1 = 不產生任何程式碼(零成本,生產模式)
assert.exception表示斷言失敗時拋出異常。預設此功能處於關閉狀態,以保持與舊的assert()
函數相容。
RFC:期望
use
聲明這使得能夠根據父命名空間對多個use
聲明進行分組。這樣做的目的是在導入同一命名空間下的多個類別、函數或常數時消除程式碼冗長。
// PHP 7 之前的程式碼use somenamespaceClassA;use somenamespaceClassB;use somenamespaceClassC as C;use function somenamespacefn_a;use function somenamespacefn_b;use function somenamespacefn_a;use function somenamespacefn_b;use function some_ namespace fn_c;use const somenamespaceConstA;use const somenamespaceConstB;use const somenamespaceConstC;// PHP 7+ 程式碼use somenamespace{ClassA, ClassB, ClassC as C}use; function some命名空間{fn_a, fn_b, fn_c};使用 const some命名空間{ConstA, ConstB, ConstC};
RFC:群組使用聲明
此功能建立在 PHP 5.5 中引入的生成器功能的基礎上。它允許在生成器中使用return
語句來傳回最終表達式(不允許透過引用返回)。可以使用新的Generator::getReturn()
方法取得該值,該方法只能在生成器完成產生值後使用。
// 現在可以使用 IIFE 語法 - 請參閱「更改」部分的「統一變數語法」小節$gen = (function() { Yield 1; Yield 2; return 3; })();foreach ($gen as $val) { echo $val, PHP_EOL; }echo $gen->getReturn(), PHP_EOL;// 輸出:// 1// 2// 3
能夠從生成器明確傳回最終值是一種方便的能力。這是因為它允許生成器返回最終值(可能來自某種形式的協程計算),該最終值可以由執行生成器的客戶端程式碼專門處理。這比強制客戶端程式碼首先檢查是否已生成最終值,然後如果已生成,則專門處理該值要簡單得多。
RFC:生成器傳回表達式
生成器委託建立在能夠從生成器返回表達式的能力之上。它透過使用新的yield from <expr>
語法來實現此目的,其中可以是任何Traversable
物件或陣列。這將被推進直到不再有效,然後執行將在呼叫產生器中繼續。此功能使yield
語句能夠分解為更小的操作,從而促進具有更高可重用性的更簡潔的程式碼。
函數 gen() { 產量 1; 產量2; 從 gen2() 返回收益率; }函數 gen2() { 產量 3; 返回4; }$gen = gen();foreach ($gen as $val) { 回顯 $val, PHP_EOL; }echo $gen->getReturn();//輸出// 1// 2// 3// 4
RFC:生成器委託
intdiv()
進行整數除法引入了intdiv()
函數來處理要傳回整數的除法。
var_dump(intdiv(10, 3)); // 整數(3)
BC 休息
全域命名空間中的函數不得稱為intdiv
。
RFC:intdiv()
session_start()
選項此功能允許將選項陣列傳遞給session_start()
函數。這用於設定基於會話的 php.ini 選項:
session_start(['cache_limiter' => '私人']); // 將 session.cache_limiter 選項設為私有
此功能還引入了一個新的 php.ini 設定 ( session.lazy_write
),預設為 true,這表示會話資料僅在發生變更時才會重寫。
RFC:引入 session_start() 選項
preg_replace_callback_array()
函數這個新函數使使用preg_replace_callback()
函數時可以更乾淨地編寫程式碼。在 PHP 7 之前,需要以正規表示式執行的回呼需要回呼函數( preg_replace_callback()
的第二個參數)被大量分支污染(充其量是一種 hacky 方法)。
現在,可以使用關聯數組將回調註冊到每個正規表示式,其中鍵是正規表示式,值是回調。
函數簽名:
string preg_replace_callback_array(array $regexesAndCallbacks, string $input);
$tokenStream = []; // [tokenName, lexeme] 對$input = <<<'end'$a = 3; // 變數初始化end;// PHP 7 之前的程式碼preg_replace_callback( [ '~$[a-z_][azd_]*~i', '~=~', '~[d]+~', '~;~', '~//.*~' ], function ($match) use (&$tokenStream) { if (strpos($match[0], '$') === 0) { $tokenStream[] = ['T_VARIABLE', $match[0]] ; } elseif (strpos($match[0], '=') === 0) { $tokenStream[] = ['T_ASSIGN', $match[0]]; } elseif (ctype_digit($match[0])) { $tokenStream[] = ['T_NUM', $match[0]]; } elseif (strpos($match[0], ';') === 0) { $tokenStream[] = ['T_TERMINATE_STMT', $match[0]]; } elseif (strpos($match[0], '//') === 0) { $tokenStream[] = ['T_COMMENT', $match[0]]; } }, $input);// PHP 7+ 程式碼preg_replace_callback_array( [ '~$[a-z_][azd_]*~i' => function ($match) use (&$tokenStream) { $tokenStream[] = ['T_VARIABLE', $match[0]]; }, '~=~' => function ($match) use (&$tokenStream) { $tokenStream[] = ['T_ASSIGN', $match[0]]; }, '~[d]+~' => function ($match) use (&$tokenStream) { $tokenStream[] = ['T_NUM', $match[0]]; }, '~;~' => 函數 ($match) use (&$tokenStream) { $tokenStream[] = ['T_TERMINATE_STMT', $match[0]]; }, '~//.*~' => function ($match) use (&$tokenStream) { $tokenStream[] = ['T_COMMENT', $match[0]]; } ], $輸入);
BC 休息
全域命名空間中的函數不得稱為preg_replace_callback_array
。
RFC:新增 preg_replace_callback_array 函數
此功能引入了兩個新函數,用於產生加密安全整數和字串。它們公開簡單的 API 並且獨立於平台。
函數簽名:
string random_bytes(int length); int random_int(int min, int max);
如果找不到足夠的隨機性來源,這兩個函數都會發出Error
異常。
BC 休息
全域命名空間中的函數不得稱為random_int
或random_bytes
。
RFC:簡單的用戶態 CSPRNG
define()
中對陣列常數的支持PHP 5.6 中引入了使用const
關鍵字定義陣列常數的功能。此功能現在也已應用於define()
函數:
定義('ALLOWED_IMAGE_EXTENSIONS', ['jpg', 'jpeg', 'gif', 'png']);
RFC:沒有可用的 RFC
PHP 7 中引入了兩個新的反射ReflectionGenerator
。
反射生成器類 { 公共 __construct(Generator $gen) 公共數組 getTrace($options = DEBUG_BACKTRACE_PROVIDE_OBJECT) 公共 int getExecutingLine(void) 公有字串 getExecutingFile(void) 公共 ReflectionFunctionAbstract getFunction(void) 公共物件 getThis(void) 公共生成器 getExecutingGenerator(void) }
第二個是ReflectionType
以更好地支援標量和傳回類型聲明功能:
反射型別類 { 公用 bool allowedNull(void) 公用 bool isBuiltin(void) 公用字串 __toString(void) }
此外, ReflectionParameter
中也引進了兩種新方法:
反射參數類 { // ... public bool hasType(void) public ReflectionType getType(void) }
ReflectionFunctionAbstract
中還有兩個新方法:
ReflectionFunctionAbstract 類 { // ... public bool hasReturnType(void) public ReflectionType getReturnType(void) }
BC 休息
全域命名空間中的類別不得稱為ReflectionGenerator
或ReflectionType
。
RFC:沒有可用的 RFC
現在允許在類別、介面和特徵中使用全域保留字作為屬性、常數和方法名稱。這減少了引入新關鍵字時 BC 中斷的表面,並避免了 API 的命名限制。
這在創建具有流暢介面的內部 DSL 時特別有用:
// 'new'、'private' 和'for' 以前不可用Project::new('項目名稱')->private()->for('此處目的')->with('此處用戶名');
唯一的限制是class
關鍵字仍不能用作常數名,否則會與類別名稱解析語法( ClassName::class
)衝突。
RFC:上下文敏感詞法分析器
這項變更為 PHP 中的變數運算子帶來了更大的正交性。它支援以前不允許的許多新的運算符組合,因此引入了新方法來以簡潔的程式碼實現舊操作。
// 巢狀 ::$foo::$bar::$baz // 存取 $foo::$bar 屬性的 $baz // 巢狀 ()foo()() // 呼叫 foo() 的回傳// ()(function () {})() 中包含的表達式的運算子// 來自JS 的IIFE 語法
任意組合變數運算子的能力來自於反轉間接變數、屬性和方法所引用的求值語意。新的行為更加直觀,並且始終遵循從左到右的評估順序:
// 舊意義 // 新意義$$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']()
BC 休息
依賴舊評估順序的程式碼必須重寫,以明確使用帶有大括號的評估順序(請參閱上面的中間欄位)。這將使程式碼既向前相容 PHP 7.x,又向後相容 PHP 5.x
RFC:統一變數語法
引擎中的異常將許多致命和可恢復的致命錯誤轉換為異常。這樣可以透過自訂錯誤處理過程對應用程式進行正常降級。這也意味著現在將執行finally
子句和物件析構函數等清理驅動的功能。此外,透過使用應用程式錯誤異常,將產生堆疊追蹤以獲取附加偵錯資訊。
函數 sum(float ...$numbers) : float{ return array_sum($numbers); } 試 { $total = sum(3, 4, null); } catch (TypeError $typeErr) { // 在此處理類型錯誤}
新的異常層次結構如下:
interface Throwable |- Exception implements Throwable |- ... |- Error implements Throwable |- TypeError extends Error |- ParseError extends Error |- AssertionError extends Error |- ArithmeticError extends Error |- DivisionByZeroError extends ArithmeticError
有關此新異常層次結構的更多信息,請參閱“更改”部分中的“可拋出接口”小節。
BC 休息
用於處理(通常忽略)可恢復致命錯誤的自訂錯誤處理程序將不再起作用,因為現在將拋出異常
eval()
程式碼中發生的解析錯誤現在將成為異常,需要將它們包裝在try...catch
區塊中
RFC:引擎中的異常
由於在引擎中引入了異常,此變更會影響 PHP 的異常層次結構。我們決定實作一個新的Exception
層次結構,以防止 PHP 5.x 程式碼使用 catch-all ( catch (Exception $e)
) 條款。
新的異常層次結構如下:
interface Throwable |- Exception implements Throwable |- ... |- Error implements Throwable |- TypeError extends Error |- ParseError extends Error |- AssertionError extends Error |- ArithmeticError extends Error |- DivisionByZeroError extends ArithmeticError
Throwable
介面由Exception
和Error
基底類別層次結構實現,並定義以下約定:
interface Throwable { final public string getMessage ( void ) final public mixed getCode ( void ) final public string getFile ( void ) final public int getLine ( void ) final public array getTrace ( void ) final public string getTraceAsString ( void ) public string __toString ( void ) }
Throwable
不能由使用者定義的類別實作 - 相反,自訂異常類別應該會擴展 PHP 中預先存在的異常類別之一。
RFC:可拋出介面
某些基於整數的行為的語義已發生變化,以使它們更加直觀且獨立於平台。以下是這些變更的清單:
將NAN
和INF
轉換為整數將始終得到 0
現在不允許以負數位元進行位移位(導致 bool(false) 傳回並發出 E_WARNING)
按位左移超出整數位寬的位數將始終導致 0
按位右移超出整數位寬的位數將始終導致 0 或 -1(取決於符號)
BC 休息
對上述舊語意的任何依賴將不再有效
RFC:整數語意
舊的 JSON 擴充功能的許可被認為是非免費的,這給許多基於 Linux 的發行版帶來了問題。該擴充功能已被 JSOND 取代,並帶來了一些效能提升和向後相容性破壞。
BC 休息
數字不得以小數點結尾(即34.
必須更改為34.0
或僅更改為34
)
e
指數不得緊接小數點(即3.e3
必須改為3.0e3
或僅改為3e3
)
RFC:用 jsond 取代目前的 json 擴充
當將浮點數傳遞給需要整數的內部函數時,可能會發生浮點數到整數之間的強制轉換。如果浮點數太大而無法表示為整數,則該值將被靜默截斷(這可能會導致幅度和符號遺失)。這可能會引入難以發現的錯誤。因此,此變更旨在在發生從浮點到整數的隱式轉換並失敗時透過傳回null
並發出 E_WARNING 來通知開發人員。
BC 休息
曾經默默工作的程式碼現在將發出 E_WARNING,如果函數呼叫的結果直接傳遞給另一個函數(因為現在將傳入null
),則可能會失敗。
RFC:ZPP 溢位失敗
foreach()
的行為PHP 的foreach()
迴圈有許多奇怪的邊緣情況。這些都是實現驅動的,並且在數組的副本和引用之間進行迭代時、使用current()
和reset()
等迭代器操縱器時、修改當前正在迭代的數組時等時,會導致許多未定義和不一致的行為。
這項變更消除了這些邊緣情況的未定義行為,並使語義更加可預測和直觀。
foreach()
按數組值
$array = [1,2,3];$array2 = &$array;foreach($array as $val) { 取消設定($array[1]); // 修改正在迭代的陣列 echo "{$val} - ", current($array), PHP_EOL; }// PHP 7 之前的結果1 - 33 -// PHP 7+ 結果1 - 12 - 13 - 1
當使用按值語義時,正在迭代的數組現在不會就地修改。 current()
現在也定義了行為,它總是從陣列的開頭開始。
foreach()
透過數組和物件的引用以及物件的值
$array = [1,2,3];foreach($array as &$val) { echo "{$val} - ", current($array), PHP_EOL; }// PHP 7 之前的結果1 - 22 - 33 -// PHP 7+ 結果1 - 12 - 13 - 1
current()
函數不再受foreach()
在數組上的迭代的影響。此外,嵌套的foreach()
使用引用語義現在彼此獨立工作:
$array = [1,2,3];foreach($array as &$val) { echo $val, PHP_EOL; foreach ($array as &$val2) { 取消設定($array[1]); 回顯$val,PHP_EOL; } }// PHP 7 之前的結果111// PHP 7+ 結果111333
BC 休息
對舊的(古怪的和未記錄的)語義的任何依賴都將不再有效。
RFC:修復「foreach」行為
list()
行為的更改list()
函數被記錄為不支援字串,但在少數情況下可以使用字串:
// 陣列解引用$str[0] = 'ab';list($a, $b) = $str[0];echo $a; // 迴音 $b; // b// 物件解引用$obj = new StdClass();$obj->prop = 'ab';list($a, $b) = $obj->prop;echo $a; // 迴音 $b; // b// 函數傳回函數 func() { 返回 'ab'; }list($a, $b) = func();var_dump($a, $b);echo $a; // 迴音 $b; // 乙
現在這一點已更改,在所有情況下都禁止使用list()
進行字串使用。
此外,空list()
現在是一個致命錯誤,並且分配變數的順序已更改為從左到右:
$a = [1, 2];list($a, $b) = $a;// 舊的: $a = 1, $b = 2// 新的: $a = 1, $b = null + "未定義索引1"$b = [1, 2];list($a, $b) = $b;// 舊: $a = null + "未定義索引0", $b = 2// 新: $a = 1、$b = 2
BC 休息
使list()
等於任何非直接字串值不再可能。 null
現在將是上面範例中變數$a
和$b
的值
呼叫不帶任何變數的list()
將導致致命錯誤
依賴舊的從右到左的分配順序將不再起作用
RFC:修正 list() 行為不一致
RFC:抽象語法樹
在 PHP 7 之前,當除法 (/) 或模數 (%) 運算子的除數為 0 時,將發出 E_WARNING 並傳回false
。在某些情況下,算術運算會傳回布林值是荒謬的,因此該行為已在 PHP 7 中修正。
新行為導致除法運算子傳回 +INF、-INF 或 NAN 形式的浮點數。模數運算子 E_WARNING 已被刪除,並且(與新的intdiv()
函數一起)將引發DivisionByZeroError
異常。此外,當提供有效的整數參數時, intdiv()
函數也可能引發ArithmeticError
,從而導致不正確的結果(由於整數溢位)。
var_dump(3/0); // 浮動(INF) + E_WARNINGvar_dump(0/0); // 浮動(NAN) + E_WARNINGvar_dump(0%0); // DivisionByZeroErrorintdiv(PHP_INT_MIN, -1); // 算術錯誤
BC 休息
除法運算子將不再回傳false
(這可能在算術運算中默默地強制為 0)
模運算子現在將拋出除數為 0 的異常,而不是傳回false
RFC:沒有可用的 RFC
實作自訂會話處理程序時, SessionHandlerInterface
中期望傳回true
或false
值的謂詞函數未如預期執行。由於先前實作中的錯誤,只有-1
回傳值被認為是 false - 這表示即使使用布林值false
來表示失敗,也會被視為成功:
<?phpclass FileSessionHandler 實作 SessionHandlerInterface { 私人 $savePath; 函數開啟($savePath,$sessionName) { 返回假; // 總是失敗 } 函數 close(){return true;} 函數 read($id){} 函數 write($id, $data){} 函數 destroy($id){} 函數 gc($maxlifetime){} }session_set_save_handler(new FileSessionHandler());session_start(); // 在 PHP 7 之前的程式碼中不會導致錯誤
現在,上述操作將會失敗並出現致命錯誤。傳回值-1
也將繼續失敗,而0
和true
將繼續意味著成功。傳回的任何其他值現在都會導致失敗並發出 E_WARNING。
BC 休息
如果傳回boolean false
,現在實際上會失敗
如果傳回布林值、 0
或-1
以外的任何值,它將失敗並導致發出警告
RFC:修正自訂會話處理程序傳回值的處理
PHP 4 建構子會與新的__construct()
一起保留在 PHP 5 中。現在,PHP 4 風格的建構函式已被棄用,取而代之的是當物件建立時僅呼叫一個方法 ( __construct()
)。這是因為是否呼叫 PHP 4 樣式建構函數的條件會為開發人員帶來額外的認知開銷,這也可能會讓沒有經驗的人感到困惑。
例如,如果該類別是在命名空間中定義的,或者如果存在__construct()
方法,則 PHP 4 樣式的建構函數將被識別為普通方法。如果它是在__construct()
方法之上定義的,則會發出 E_STRICT 通知,但仍被識別為普通方法。
現在在 PHP 7 中,如果該類別不在命名空間中且不存在__construct()
方法,則 PHP 4 樣式建構函數將用作建構函數,但會發出 E_DEPRECATED。在 PHP 8 中,PHP 4 風格的建構函式將始終被辨識為普通方法,而 E_DEPRECATED 通知將會消失。
BC 休息
自訂錯誤處理程序可能會受到 E_DEPRECATED 警告的影響。要解決此問題,只需將類別建構子名稱更新為__construct
即可。
RFC:刪除 PHP 4 建構函數
當呼叫任何基於日期或時間的函數且尚未設定預設時區時,會發出警告。解決方法是簡單地將date.timezone
INI 設定設定為有效的時區,但這迫使使用者擁有 php.ini 檔案並預先配置它。由於這是唯一附加了警告的設置,並且無論如何它都預設為 UTC,因此該警告現在已被刪除。
RFC:刪除 date.timezone 警告
替代 PHP 標籤<%
(和<%=
)、 %>
、 <script language="php">
和</script>
現已刪除。
BC 休息
依賴這些替代標籤的程式碼需要更新為正常或短的開始和結束標籤。這可以手動完成,也可以使用此移植腳本自動完成。
RFC:刪除替代 PHP 標籤
先前,可以在 switch 語句中指定多個default
區塊語句(僅執行最後一個default
區塊)。這種(無用的)能力現已被刪除,並會導致致命錯誤。
BC 休息
任何使用多個default
區塊建立 switch 語句的編寫(或更可能產生)程式碼現在都會成為致命錯誤。
RFC:使在開關中定義多個預設情況成為語法錯誤
以前,可以在函數定義中指定具有重複名稱的參數。此功能現已刪除並會導致致命錯誤。
函數 foo($version, $version) { 返回 $版本; }echo foo(5, 7);// PHP 7 之前的結果7// PHP 7+ 結果致命錯誤:在 /redefinition-of-parameters.php 中重新定義參數 $version
BC 休息
具有重複名稱的函數參數現在將成為致命錯誤。
以下 SAPI 已從核心中刪除(其中大部分已移至 PECL):
sapi/aolserver
sapi/阿帕奇
sapi/apache_hooks
sapi/apache2filter
薩皮/卡迪姆
sapi/連續性
薩皮/伊薩皮
薩皮/米爾特
sapi/nsapi
sapi/phttpd
sapi/pi3web
薩皮/羅克森
sapi/thttpd
薩皮/晚禮服
sapi/webjames
分機/mssql
分機/mysql
ext/sybase_ct
分機/ereg
RFC:刪除死的或尚未 PHP7 移植的 SAPI 和擴充
Stringy 十六進位數不再被辨識為數字。
var_dump(is_numeric('0x123'));var_dump('0x123' == '291');echo '0x123' + '0x123';// PHP 7 之前的結果bool(true)bool(true)582// PHP 7+結果布爾(假)布爾(假)0
進行此更改的原因是為了提高跨語言處理字串十六進位數字之間的一致性。例如,明確轉換無法辨識字串十六進位數字:
var_dump((int) '0x123'); // 整數(0)
相反,應該使用filter_var()
函數來驗證和轉換字串十六進位數字:
var_dump(filter_var('0x123', FILTER_VALIDATE_INT, FILTER_FLAG_ALLOW_HEX)); // 整數(291)
BC 休息
此變更會影響is_numeric()
函數和各種運算符,包括==
、 +
、 -
、 *
、 /
、 %
、 **
、 ++
和--
RFC:刪除數字字串中的十六進位支持
所有已棄用的功能已被刪除,最值得注意的是:
原來的mysql擴充(ext/mysql)
ereg 副檔名 (ext/ereg)
透過引用分配new
來自不相容的$this
上下文的非靜態方法的作用域呼叫(例如來自類別外部的Foo::bar()
,其中bar()
不是靜態方法)
BC 休息
任何在 PHP 5 中運行時帶有棄用警告的程式碼都將不再工作(您已收到警告!)
RFC:刪除 PHP 7 中已棄用的功能
E_STRICT 通知的含義一直處於灰色地帶。此變更完全刪除了此錯誤類別,並且:刪除 E_STRICT 通知,如果將來將刪除該功能,則將其變更為 E_DEPRECATED,將其變更為 E_NOTICE,或將其提升為 E_WARNING。
BC 休息
由於 E_STRICT 屬於最低嚴重性錯誤類別,因此任何升級為 E_WARNING 的錯誤都可能會破壞自訂錯誤處理程序
RFC:重新分類 E_STRICT 通知
password_hash()
的 Salt 選項隨著 PHP 5.5 中新密碼雜湊 API 的引入,許多人開始實作它並產生自己的鹽。不幸的是,許多這些鹽是由像 mt_rand() 這樣的加密不安全函數產生的,使得鹽比預設產生的鹽要弱得多。 (是的,使用這個新 API 對密碼進行哈希處理時始終使用鹽!)因此,生成鹽的選項已被棄用,以防止開發人員創建不安全的鹽。
RFC:沒有可用的 RFC
無效的八進位文字現在將導致解析錯誤,而不是被截斷並默默地忽略。
迴聲0678; // 解析錯誤:無效的數字文字...
BC 休息
程式碼中任何無效的八進位文字現在都會導致解析錯誤
RFC:沒有可用的 RFC
substr()
傳回值變化當截斷的起始位置等於字串長度時, substr()
現在將傳回一個空字串而不是false
:
var_dump(substr('a', 1));// PHP 7 前 resultbool(false)// PHP 7+ resultstring(0) ""
然而,在其他情況下, substr()
仍可能傳回false
。
BC 休息
嚴格檢查bool(false)
回傳值的程式碼現在可能在語義上無效
RFC:沒有可用的 RFC
PHP 6 是從未曝光的主要 PHP 版本。它的核心應該是全面支援 Unicode,但這項努力過於雄心勃勃,帶來了太多的複雜性。此新主要版本跳過版本 6 的主要原因如下:
以防混亂。許多資源都是關於 PHP 6 的,社區中的許多人都知道其中的功能。 PHP 7 是一個完全不同的野獸,具有完全不同的焦點(特別是性能)和完全不同的功能集。因此,我們跳過了一個版本,以防止對 PHP 7 產生任何混淆或誤解。
讓熟睡的狗狗躺著。 PHP 6 被視為失敗,大量 PHP 6 程式碼仍然保留在 PHP 儲存庫中。因此,最好的方法是跳過版本 6,並在下一個主要版本(版本 6)上重新開始。
RFC:PHP 下一版的名稱