PHP 7 值得期待的新特性(上)

OneAPM官方技術部落格發表於2015-10-29

這是我們期待已久的 PHP 7 系列文章的第一篇。

或許你已經知道了,我在 PHP 5.0.0 時間軸 提的 RFC (Request For Comments)通過了, PHP 7 成為 PHP 下一個主要版本的名稱。

無論你對此話題有任何感想,PHP 7 是一個大事件,而且它將在今年釋出! PHP 7.0 時間軸 的 RFC 幾乎全票通過(32 對 2 )後,所有功能現在已經確立了,我們將在六月中旬看到首個候選版本( RC )釋出。

但這對你意味著什麼呢?我們看到 5.x 新版本釋出後,許多 Web 主機都不願升級。一個重要的新版本釋出難道不會帶來巨大的向後相容隔斷,使得升級更加緩慢麼?

答案是:視情況而定。請繼續往下讀。

在新版本中,許多語言邊界情況已經得到處理。此外,效能與不一致性修復也是該版重點關注的問題。

接下來是細節討論。

不相容性修復

不幸的是,needle/haystack 問題還未得到修復。然而,兩個重要的 RFC 已經獲得通過,它們將帶來一些期望已久的內部與使用者層的一致性。

最大的(也是最難以察覺的)變化是新增的一種 抽象語法樹( AST )——程式碼在編譯過程中的中間表示。有了這種表示,我們可以清理一些邊緣情況的不一致,併為將來開發一些極好的工具做好準備,比如使用 AST 生成效能更好的 OpCode。

其次,統一變數語法 的引入,可能會導致更多問題。這解決了表示式求值中的許多不相容問題。例如,可以使用 ($object->closureProperty)() 呼叫分配給屬性的閉包函式 ,以及執行鏈靜態呼叫,如下所示:

    class foo { static $bar = 'baz'; }
    class baz { static $bat = 'Hello World'; }

    baz::$bat = function () { echo "Hello World"; };

    $foo = 'foo';
    ($foo::$bar::$bat)();

然而,一些語法也在改變。特別是使用 variable->variables/properties 的語法。

在 PHP 7 之前,$obj->$properties['name'] 將訪問名稱屬於 “$properties” 陣列名稱鍵(name key)的屬性。使用通用變數語法(Universal Variable Syntax)後,它將訪問名稱屬於 “$properties” 的屬性的名稱鍵。

或者更簡潔地說,如果使用以下語法:

    $obj->$properties['name']

在 PHP 5.6,它將被解析為:

    $obj->{$properties['name']}

而在 PHP 7 中則為:

    {$obj->$properties}['name']

variable->variables 通常使用在邊界情況,根據我的經驗, variable->properties  則更加常用,且不易用。然而,使用花括號(如上例所示)後,就可以輕易確保在 PHP 5.6 和 7 中達到相同效果。

效能

升級到 PHP 7 的最大原因是效能提升,此效能提升主要是由於引入 phpng 的變化帶來的。實際上,效能提升可能帶來更高的採納率,尤其是那些一般情況下不願意升級的小主機,為了讓同一臺機器承載更多客戶,他們極有可能升級。

到目前為止,根據不同的基準測試,PHP 7 的效能與 Facebooks HHVM 持平,後者的特點是藉助實時(Just In Time)編譯器將 PHP 程式碼編譯至機器指令(只要可以)。

PHP 7 不具備 JIT ,雖然相關討論沸沸揚揚。新增 JIT 之後能帶來多少效能提升尚未可知,但若有人有興趣建立一個的話,肯定非常有趣!

除了效能提升,還應該節省大量的記憶體,因為內部資料結構的優化一直是效能改進實現的主要途徑。

向後不相容的改變

雖然內部開發人員盡力不去打破向後相容性( BC ),但是想要推進語言的進步,沒法總是兼顧相容性。

然而,像由於統一變數語法(Uniform Variable Syntax)導致打破的向後相容性,這些不相容多是輕微的,比如 在試圖呼叫一個非物件的方法時導致的可捕獲的致命錯誤

    set_error_handler(function($code, $message) {
      var_dump($code, $message);
    });

    $var = null;
    $var->method();
    echo $e->getMessage(); // Fatal Error: Call to a member function method() on null
    echo "Hello World"; // 依舊會執行

此外,ASP 與指令碼標籤已被刪除,這意味著不可以再使用 <% 和 <%=,或 <script language="php”>(以及各自的結束標籤:%>,和 </script>)。

其他更大的改變,可以在 移除的所有棄用函式 中看到。

最重要的不相容性改變還包括,相容 POSIX 的正規表示式擴充套件、EXT/ereg(在 5.3 版本被棄用)和舊的 EXT/mysql 擴充套件(在 5.5 版本被棄用)均被移除。

另一個小的不相容性改變是不允許在 switch 中有多個 default cases 。PHP 7 之前,以下是允許的:

        switch ($expr) {
            default:
                 echo "Hello World";
                 break;
            default:
                 echo "Goodbye Moon!";
                 break;
        }

這將導致只有後者被執行。在 PHP 7 中,這將導致:

    Fatal error: Switch statements may only contain one default clause
                - Switch 語法只允許包含一個預設子句

新功能

在面對向後不相容帶來的影響時,我們頗有微詞。效能上的提升又讓我們歡欣鼓舞。但是,最讓我們醉心的是新的特性!新特性才是讓每次釋出充滿樂趣的關鍵—— PHP 7 可不缺乏新特性。

標量型別提示和返回型別

我會最先介紹 PHP 7 新增的最具爭議的變化:標量型別提示。這一特性的新增一開始並未通過投票。接著該作者撤回了該 RFC。之後,許多執行之後相互牴觸的 RFC 被提了出來,經過一番公開的討論,原先的這個 RFC 還是通過了。

對於你,終端使用者,而言,這意味著你可以對標量型別進行型別提示( type-hint )。具體地說,標量型別包括:int,float,string,和 bool 。預設情況下,型別提示不是嚴格的,這意味著他們將迫使原始型別轉化為型別提示指定的型別。這意味著,如果你將 int(1) 傳入需要 float 型別的函式,它會變為 float(1)。將 float(1.5) 傳入需要 int 型別的函式,它會變為 int(1)。

這裡的一個例子:

    function sendHttpStatus(int $statusCode, string $message) {
         header('HTTP/1.0 ' .$statusCode. ' ' .$message);
    }

    sendHttpStatus(404, "File Not Found"); // 傳了整形和字串
    sendHttpStatus("403", "OK"); // 字串 "403" 強轉為 int(403)

此外,將宣告 declare(strict_types=1); 放在任意文件的頂部,可以啟用嚴格模式,文件中的任何函式呼叫都必須遵從指定的型別。Strict 與否取決於函式呼叫的檔案,而非函式定義的檔案。

如果一個型別提示不匹配,一個可捕獲的致命錯誤會被丟擲:

    <?php
    declare(strict_types=1); // 必須放置在第一行

    sendHttpStatus(404, "File Not Found"); //  傳了整型和字串
    sendHttpStatus("403", "OK"); 

    // Catchable fatal error: 傳給 sendHttpStatus() 的第一個引數型別必須是整形,目前提供的是字串

此外,PHP 7  還支援 返回型別提示,它支援所有相同的型別作引數。這遵循與 hack 相同的語法,在括號後面插入冒號,然後是型別:

    function isValidStatusCode(int $statusCode): bool {
        return isset($this->statuses[$statusCode]);
    }

在這個例子中:bool 表明該函式將返回一個布林值。

返回型別提示的嚴格模式遵從與型別提示相同的法則。

綜合比較運算子

我個人最喜歡的 PHP 7 新增特性是 綜合比較運算子,<=>,也稱為飛船操作符。此處我可能是帶個人喜好的,因為是我寫的最初補丁,也影響了命名(T_SPACESHIP)。但這仍是對 PHP 語言的一個好補充,與大於和小於操作符形成互補。

實際上,該操作符的工作方式與 strcmp(),或 version_compare() 基本一致。如果左側運算元小於右側,則返回 -1 , 兩邊相等則返回 0 ,如果左側大於右側則返回 1 。主要的區別在於,它可以用在任何兩個運算元間,不僅是字串,還可以是整數,浮點數,陣列等等。

該操作符最常見的用法是在排序回撥中:

    // Pre Spacefaring^W PHP 7
    function order_func($a, $b) {
        return ($a < $b) ? -1 : (($a > $b) ? 1 : 0);
    }

    // Post PHP 7
    function order_func($a, $b) {
        return $a <=> $b;
    }

OneAPM for PHP 能夠深入到所有 PHP 應用內部完成應用效能管理 能夠深入到所有 PHP 應用內部完成應用效能管理和監控,包括程式碼級別效能問題的可見性、效能瓶頸的快速識別與追溯、真實使用者體驗監控、伺服器監控和端到端的應用效能管理。

下一步

在本文中,我們瞭解了 PHP 7 中最重要的不相容性修復,已經兩大新特性。

在接下來的第二篇文章中,我們將介紹 PHP 7 中重要的其他六個功能。另外,我們將在文章系列的最後介紹一些幫助 PHP 7 發展的方法。

原文連結:https://blog.engineyard.com/2015/what-to-expect-php-7

相關文章