PHP 7 簡介:新功能和新功能
已發表: 2022-03-112015 年 PHP 世界中最激動人心的事件之一是 PHP 7 的發布,距離上一個主要版本 PHP 5 的發布已經過去了 10 年。隨著向前邁出一大步,PHP 7 引入了大量新功能和性能升級.
但是,它也刪除了舊的、已棄用的功能,這引入了一些兼容性中斷,使舊應用程序更難遷移到新版本。 如果您計劃在 PHP 7 之上移動現有應用程序或構建新應用程序,本指南應該作為一個快速瀏覽。
但是等等,PHP 6 去哪兒了?
如果您最近沒有使用 PHP,您可能想知道 PHP 6 發生了什麼,為什麼從 PHP 5 跳到 PHP 7? 好吧,長話短說,PHP 6 失敗了。 版本 6 的主要特點是對 Unicode 字符的原生支持,因為 PHP 主要用於 Web 開發並且 Web 需要 Unicode,因此將 Unicode 引入 PHP 的舉動是有意義的。
這個想法是為核心本身帶來對 Unicode 的完全支持。 它將為該語言帶來擴展的功能,從使用愚蠢的表情符號作為變量和函數名稱的能力,到強大的國際字符串功能。 例如,當另一種語言使用與英文不同的大小寫字母時,或者當需要將漢字名稱轉換為英文時。
不幸的是,這個雄心勃勃的計劃被證明是一個比預期更大的問題。 必須移植大部分代碼庫以支持核心和重要擴展的 Unicode,這被證明是乏味和棘手的。 這減慢了語言中其他功能的開發速度,使許多 PHP 開發人員在此過程中感到沮喪。 出現了額外的障礙,導致對開發原生 Unicode 支持的興趣降低,最終導致該項目被放棄。
由於書籍和文章等資源是為 PHP 6 及其 Unicode 支持編寫的,因此新版本將重命名為 PHP 7 以避免混淆。
無論如何,在悲傷的過去已經足夠了,讓我們看看 PHP 7 給聚會帶來了什麼。
性能之戰,PHP 7 與 PHP 5
對於幾乎所有更新,預計會有較小的性能升級。 然而,這一次 PHP 帶來了對早期版本的顯著改進,使得純粹的性能成為 PHP 7 最吸引人的特性之一。 這是“PHPPNG”項目的一部分,該項目解決了 Zend 引擎本身的內部問題。
通過重構內部數據結構並以抽象語法樹 (AST) 的形式在代碼編譯中添加中間步驟,結果是卓越的性能和更高效的內存分配。 這些數字本身看起來很有希望。 在真實世界應用程序上進行的基準測試表明,PHP 7 的平均速度是 PHP 5.6 的兩倍,並且請求期間的內存消耗減少了 50%,這使得 PHP 7 成為 Facebook 的 HHVM JIT 編譯器的強大競爭對手。 看看 Zend 的這張信息圖,它描繪了一些常見的 CMS 和框架的性能。
內存消耗的減少還允許較小的機器更好地處理請求,並有機會圍繞 PHP 構建微服務。 內部變化,特別是 AST 實現,也為未來的優化開闢了可能性,從而進一步推動性能。 JIT 編譯器的新內部實現正在考慮用於未來版本。
PHP 7 語法糖
PHP 7 帶有新的語法特性。 雖然沒有擴展語言本身的功能,但它們提供了一種更好或更簡單的方法,使您的代碼編寫起來更加愉快和賞心悅目。
集團進口報關單
現在,我們可以將來自同一命名空間的類的導入聲明分組到單個use
行中。 這應該有助於以有意義的方式對齊聲明,或者只是在文件中保存一些字節。
use Framework\Module\Foo; use Framework\Module\Bar; use Framework\Module\Baz;
使用 PHP 7,我們可以使用:
use Framework\Module\{Foo, Bar, Baz};
或者,如果您更喜歡多線樣式:
use Framework\Module{ Foo, Bar, Baz };
空合併運算符
這解決了 PHP 編程中的一個常見問題,我們希望從另一個變量中為一個變量分配一個值,如果後者實際已設置,或者為它提供不同的值。 當我們使用用戶提供的輸入時,它通常被使用。
PHP 7 之前的版本:
if (isset($foo)) { $bar = $foo; } else { $bar = 'default'; // we would give $bar the value 'default' if $foo is NULL }
PHP 7 之後:
$bar = $foo ?? 'default';
這也可以與許多變量鏈接:
$bar = $foo ?? $baz ?? 'default';
宇宙飛船操作員
宇宙飛船運算符<=>
允許在兩個值之間進行三向比較,不僅指示它們是否相等,而且通過返回 1,0 或 -1 來指示不等式中哪個更大。
在這裡,我們可以根據值的不同採取不同的操作:
switch ($bar <=> $foo) { case 0: echo '$bar and $foo are equal'; case -1: echo '$foo is bigger'; case 1: echo '$bar is bigger'; }
比較的值可以是整數、浮點數、字符串甚至數組。 查看文檔以了解如何將不同的值相互比較。 [https://wiki.php.net/rfc/combined-comparison-operator]
PHP 7 中的新功能
當然,PHP 7 也帶來了新的令人興奮的功能。
標量參數類型和返回類型提示
PHP 7 通過添加四種標量類型擴展了方法(類、接口和數組)中參數的先前類型聲明; 整數 ( int
)、浮點數 ( float
)、布爾值 ( bool
) 和字符串 ( string
) 作為可能的參數類型。
此外,我們可以選擇指定方法和函數返回的類型。 支持的類型是bool 、 int 、 float 、 string 、 array 、 callable 、 Class或Interface的 name 、 self和parent (用於類方法)
class Calculator { // We declare that the parameters provided are of type integer public function addTwoInts(int $x, int $y): int { return $x + $y; // We also explicitly say that this method will return an integer } }
類型聲明允許構建更健壯的應用程序並避免從函數傳遞和返回錯誤值。 其他好處包括靜態代碼分析器和 IDE,如果缺少 DocBlock,它們可以更好地了解代碼庫。
由於 PHP 是一種弱類型語言,參數和返回類型的某些值將根據上下文進行強制轉換。 如果我們在一個聲明參數類型為int
的函數中傳遞值“3”,解釋器將接受它作為整數並且不會拋出任何錯誤。 如果你不想要這個,你可以通過添加一個declare
指令來啟用strict mode
。
declare(strict_types=1);
這是在每個文件的基礎上設置的,因為全局選項會將代碼存儲庫劃分為具有全局嚴格性構建的那些和沒有構建的那些,當我們組合來自兩者的代碼時會導致意外行為。
引擎異常
通過添加引擎異常,可以輕鬆捕獲和處理可能導致腳本終止的致命錯誤。
諸如調用不存在的方法之類的錯誤不會終止腳本,而是會引發可由 try catch 塊處理的異常,從而改進應用程序的錯誤處理。 這對於某些類型的應用程序、服務器和守護程序很重要,因為否則致命錯誤會要求它們重新啟動。 PHPUnit 中的測試也應該變得更有用,因為致命錯誤會丟棄整個測試套件。 將在每個測試用例的基礎上處理異常而不是錯誤。
PHP 7 根據可能遇到的錯誤類型添加了許多新的異常類。 為了保持版本之間的兼容性,添加了一個新的Throwable
接口,該接口可以從引擎異常和用戶異常中實現。 這是必要的,以避免引擎異常擴展基異常類,從而導致以前不存在的較舊的代碼捕獲異常。
在 PHP 7 之前,這會以致命錯誤終止腳本:
try { thisFunctionDoesNotEvenExist(); } catch (\EngineException $e) { // Clean things up and log error echo $e->getMessage(); }
匿名類
匿名類是匿名函數的近親,您可以在簡單的短期實例中使用它們。 匿名類很容易創建和使用,就像普通對像一樣。 這是文檔中的一個示例。
PHP 7 之前
class MyLogger { public function log($msg) { print_r($msg . "\n"); } } $pusher->setLogger( new MyLogger() );
使用匿名類:
$pusher->setLogger(new class { public function log($msg) { print_r($msg . "\n"); } });
匿名類在單元測試中很有用,尤其是在模擬測試對象和服務時。 通過創建一個提供我們想要模擬的接口的簡單對象,這有助於我們避免大量模擬庫和框架。

CSPRNG 函數
添加了兩個用於生成加密安全字符串和整數的新函數。
random_bytes(int $len);
返回一個長度$len
的隨機字符串。
random_int(int $min, int $max);
返回$min
和$max
之間的數字。
Unicode 代碼點轉義語法
與許多其他語言不同,在 PHP 7 之前,PHP 沒有辦法在字符串文字中轉義 Unicode 代碼點,. 此功能添加轉義\u
序列以使用其 UTF-8 代碼點生成此類字符。 這比直接插入字符要好,可以更好地處理不可見字符以及具有相同圖形表示但含義不同的字符。
echo "\u{1F602}"; // outputs ‚
請注意,這會使用\u
序列破壞現有代碼,因為它會改變行為。
發電機升級
PHP 中的生成器還有一些不錯的附加功能。 現在,生成器有一個 return 語句,可用於允許它在迭代後輸出最終值。 這可以用來檢查生成器是否已正確執行,並允許調用生成器的代碼適當地處理各種場景。
此外,生成器可以從其他生成器返回和生成表達式。 這使他們能夠將復雜的操作劃分為更簡單的模塊化單元。
function genA() { yield 2; yield 3; yield 4; } function genB() { yield 1; yield from genA(); // 'genA' gets called here and iterated over yield 5; return 'success'; // This is a final result we can check later } foreach (genB() as $val) { echo "\n $val"; // This will output values 1 to 5 in order } $genB()->getReturn(); // This should return 'success' when there are no errors.
期望
期望是對assert()
函數的增強,同時保持向後兼容性。 它們允許在生產代碼中進行零成本斷言,並提供在斷言失敗時拋出自定義異常的能力,這在開發過程中很有用。
assert()
成為 PHP 7 中的一種語言結構。斷言只能在開發和測試環境中用於調試目的。 為了配置它的行為,我們提供了兩個新指令。
-
zend.assertions
-
1
:生成並執行代碼(開發模式)(默認值) -
0
:生成代碼但在運行時跳轉 -1
:不生成代碼,使其零成本(生產模式)
-
-
assert.exception
-
1
:斷言失敗時拋出,通過拋出作為異常提供的對像或在未提供異常時拋出新的AssertionError對象 0
:使用或生成Throwable如上所述,但僅基於該對像生成警告而不是拋出它(與 PHP 5 行為兼容)
-
準備從 PHP 5 遷移到 PHP 7
主要版本的引入帶來了更改/更新舊功能的機會,甚至在它們被認為太舊或已被棄用一段時間時將其刪除。 此類更改可能會導致舊應用程序的兼容性中斷。
這種版本飛躍引發的另一個問題是,您所依賴的重要庫和框架可能尚未更新以支持最新版本。 PHP 團隊已嘗試使新更改盡可能向後兼容,並允許盡可能輕鬆地遷移到新版本。 更新和更新的應用程序應該更容易遷移到新版本,而舊應用程序可能必須決定收益是否超過成本,可能選擇不更新。
大多數休息時間都很輕微,可以輕鬆緩解,而其他休息時間可能需要更多的努力和時間。 基本上,如果您在安裝 PHP 7 之前在您的應用程序中出現了棄用警告,您可能會遇到錯誤,這些錯誤會破壞應用程序,直到修復為止。 你被警告了,對吧?
舊的 SAPI 和擴展
最重要的是,舊的和已棄用的 SAPI 像mysql
擴展一樣被刪除(但你不應該首先使用它,對吧?)。 有關已刪除的擴展和功能的完整列表,您可以在此處和此處查看此 RFC。
此外,其他 SAPI 正在移植到 PHP 7。
統一變量語法
此更新進行了一些更改,有利於變量結構的一致性。 這允許使用變量進行更高級的表達式,但在其他一些情況下會引入行為變化,如下所示。
// old meaning // new meaning $$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']()
這將破壞應用程序訪問此類值的行為。 另一方面,你可以做一些像這樣的整潔的東西:
// Nested () foo()(); // Calls the return of foo() $foo->bar()(); // IIFE syntax like JavaScript (function() { // Function body })(); // Nested :: $foo::$bar::$baz
舊樣式標籤已刪除
開始/結束標籤<% ... %>
、 <%= ... %>
、 <script language="php"> ... </script>
被刪除並且不再有效。 用有效的替換它們應該很容易,但是你用它們做什麼呢,怪人?
類、接口和特徵的無效名稱
由於添加了參數和返回類型等類、接口和特徵,不再允許使用以下名稱:
- 布爾
- 整數
- 漂浮
- 細繩
- 空值
- 真的
- 錯誤的
這些會破壞使用它們的現有應用程序和庫,但它們應該很容易修復。 此外,儘管它們不會導致任何錯誤並且有效,但不應使用以下內容,因為它們是為將來使用而保留的:
- 資源
- 目的
- 混合
- 數字
避免使用它們應該可以節省您將來更改它們的工作。
有關會破壞兼容性的更改的完整列表,請查看此文檔。
您還可以使用 php7cc,它會檢查您的代碼,並可以檢測到您遷移到 PHP 7 後可能出現的任何潛在問題。當然,沒有比安裝 PHP 7 並親自查看更好的方法了。
潛在的 PHP 7 兼容性問題
PHP 7 基礎架構兼容性
許多託管服務已開始添加對 PHP 7 的支持。這對於共享託管服務提供商來說是個好消息,因為性能提升將使他們能夠增加硬件上的客戶端網站數量,從而降低運營費用並提高利潤。 至於客戶本身,他們不應該期望在這些條件下獲得太多提升,但公平地說,共享主機無論如何都不是一個以性能為導向的選擇。
另一方面,提供虛擬專用服務器或專用服務器的服務將獲得這種性能提升的全部好處。 一些 PaaS 服務(如 Heroku)很早就支持 PHP 7,但其他服務(如 AWS Beanstalk 和 Oracle 的 OpenShift)則落後。 檢查您的 PaaS 提供商的網站,了解是否已經支持 PHP 7,或者是否在不久的將來提供支持。
當然,IaaS 提供商允許您控制硬件並安裝 PHP 7(如果您更喜歡的話,也可以編譯)。 PHP 7 包已經可用於主要的 IaaS 環境。
PHP 7 軟件兼容性
除了基礎架構兼容性之外,您還需要注意潛在的軟件兼容性問題。 WordPress、Joomla 和 Drupal 等流行的內容管理系統在其最新版本中增加了對 PHP 7 的支持。 Symfony 和 Laravel 等主要框架也得到了全面支持。
但是,現在是時候提個醒了。 這種支持不會擴展到以附加組件、插件、包或您的 CMS 或框架調用它們的任何形式的第三方代碼。 他們可能會遇到兼容性問題,您有責任確保一切都為 PHP 7 做好準備。
對於活動的、維護的存儲庫,這應該不是問題。 但是,缺乏 PHP 7 支持的較舊和未維護的存儲庫可能會使您的整個應用程序無法使用。
PHP 的未來
PHP 7 的發布刪除了舊的和過時的代碼,並為未來的新功能和性能升級鋪平了道路。 此外,預計 PHP 將很快獲得額外的性能優化。 儘管與過去的版本存在一些兼容性問題,但大多數問題都很容易解決。
庫和框架現在正在將其代碼遷移到 PHP 7,從而提供最新版本。 我鼓勵您嘗試一下並親自查看結果。 也許您的應用程序已經兼容並等待使用 PHP 7 並從中受益。