官术网_书友最值得收藏!

1.1 PHP簡史與新特性

PHP是一種跨平臺開源語言,也是迄今為止最流行的Web開發語言,全球有超過80%的網站由PHP驅動。PHP自1994年由Rasmus Lerdorf創建以來已走過20多年,經歷了6個大版本的更迭。下面就來了解PHP簡史與PHP 7帶來的新特性。

1. PHP簡史

PHP最初是作為工具包出現的,作者Rasmus Lerdorf為了在自己的網站上追蹤訪客開發了PHP的雛形。而后隨著功能的增多,作者發布了第一個完整的版本并稱之為Personal Home Page Tools。1996年Rasmus Lerdorf發布了2.0版本,這是一個相對完善的版本,不僅可以訪問數據庫還可以把PHP代碼嵌入到HTML頁面中。2.0版本吸引了很多開發者,其中包括后來Zend引擎的核心開發者Zeev Suraski和Andi Gutmans。Zeev和Andi加入之后,重寫了代碼,帶來了PHP 3.0。

PHP 3.0強大的可擴展性吸引了更多的開發者加入并提交新的模塊。從這個版本開始,PHP被重命名為PHP:Hypertext Preprocessor。2000年夏初,4.0版本發布,Zend引擎正式登場,相比PHP 3.0,最高可以有近10倍的性能提升。此外還支持了更多的Web服務器。這個時候的PHP已經是很流行的編程語言了,但是相對于其他語言還缺乏一些關鍵特性,例如面向對象、異常處理等。

2004年7月,標志性的PHP 5正式發布,Zend引擎升級到2.0。PHP 5的最大特點是引入了面向對象的全部機制。另外引進了類型提示和異常處理機制,能更有效地處理異常和避免錯誤。2005年PHP社區發起了PHP 6的項目,主要的目的是為PHP引擎增加Unicode支持,但是由于種種原因,項目最終被取消。這個項目雖然被取消了,但是大量的功能陸續都添加進了PHP 5.x版本,例如命名空間、匿名函數、閉包等特性。

2015年夏天,備受矚目的PHP 7發布了第一個Alpha版本。之后,經過大概3個Beta版本和8個RC版本,2016年1月PHP 7正式發布。PHP 7是PHP一個非常重要的版本,相對于PHP 5.x版本,有著非常大的革新,尤其是在性能方面。如果讀者的網站使用的是PHP 5.x,那么使用PHP 7后幾乎將無成本地得到一倍的性能提升。感謝開發者!

下面我們來測試一下PHP 7性能到底提升了多少。本地環境下以相同的編譯參數分別安裝PHP 5.5.38、PHP 7的第一個正式版本7.0.2和7.1.0版本,在CLI模式下運行PHP源碼中的基準測試腳本。

1)測試環境:本地搭建的vagrant虛擬機,操作系統CentOS 7,單核CPU 2.00GHz,內存1GB。

2)基準測試指標:

? Time——執行時間,以秒為單位;

? %rel, gain——相對于上一版本節省的執行時間;

? %abs, gain——與PHP5.5.38相比,腳本節省的執行時間。

測試結果如表1-1所示。

表1-1 測試結果

由上邊的測試結果可以看出來,PHP 7.1.0的基準性能幾乎是PHP 5.5.38的3倍左右,在開啟了opcache的情況下更是達到了4.4倍之多,這是一個非常顯著的提升。這些性能提升是如何做到的呢?本書后續的章節將一一介紹。

注意

這里的測試是純CPU的基準測試,5次運行取平均值,不包括其他方面的測試,在實際的項目或者其他運行環境下可能有所差異。

2. PHP 7新特性

PHP 7除了在性能方面有極大提升外,還添加了很多新的特性,如太空船操作符、標量類型聲明、返回值的類型聲明、全局的throwable接口、抽象語法樹等,下邊分別介紹。

(1)太空船操作符

太空船操作符用于比較兩個表達式。例如,當$a小于、等于或大于$b時,它分別返回-1、0或1。比較的原則沿用PHP的常規比較規則進行。

    <? php
    // 整數
    echo 1 <=> 1; // 0
    echo 1 <=> 2; // -1
    echo 2 <=> 1; // 1

    // 浮點數
    echo 1.5 <=> 1.5; // 0
    echo 1.5 <=> 2.5; // -1
    echo 2.5 <=> 1.5; // 1

    // 字符串
    echo "a" <=> "a"; // 0
    echo "a" <=> "b"; // -1
    echo "b" <=> "a"; // 1

(2)標量類型聲明和返回值的類型聲明

PHP 7可以對下面幾種類型的參數做聲明:字符串(string)、整型(int)、浮點型(float)以及布爾型(bool)。注意參數類型聲明不受制于默認模式和嚴格模式。默認模式下,當傳入的參數不符合聲明類型時,會首先嘗試轉換類型;而嚴格模式下,則直接報錯。

例如下面的代碼:

    <? php
    declare(strict_types=1); // strict_types=1表示開啟嚴格模式
    function sumOfInts(int ...$ints)
    {
        return array_sum($ints);
    }
    var_dump(sumOfInts(2, '3.1', 4.1));
    // 運行結果:
    // Fatal error: Uncaught TypeError: Argument 2 passed to sumOfInts() must be of
        the type integer, string given…

當注釋掉第二行代碼,程序才可以正常運行——PHP會首先嘗試把’3.1’轉為int型的3,然后再執行。(注意:這里的類型轉換僅受制于可轉換的類型,例如不能把’a’轉為int型。)但是當開啟嚴格模式后,代碼會直接報錯。因為函數的參數被聲明為int型,但是傳入的參數中包含一個string型和一個float型。

修改上面代碼,再來看看返回值類型受限制的情況:

    <? php
    declare(strict_types=1);
    function sumOfInts(int ...$ints) : int
    {
        return array_sum($ints);
    }
    var_dump(sumOfInts(2, 3, 4));
    // 運行結果
    // int(9)

這段代碼額外聲明了返回值的類型為int型。如果返回值的類型不是int型,在默認模式下,PHP會首先嘗試轉換返回值的類型為int型,如果不能轉換,則會直接報錯。

PHP 7.1對函數返回值的聲明做了擴充,可以定義其返回值為void,無論是否開啟嚴格模式,只要函數中有“return; ”以外的其他return語句都會報錯。

注意:參數類型不可以是void。

    <? php
    declare(strict_types=1);
    function sumOfInts(int ...$ints) : void
    {
        // return array_sum($ints);
        // return null;
        return;
    }
    var_dump(sumOfInts(2, 3, 4));
    // 運行結果:
    // NULL

PHP 7.1.0對參數類型和返回值類型還有進一步的支持,其類型可以是可空類型,在參數或返回值類型聲明前邊加上“? ”,表示返回值要么是null,要么是聲明的類型:

    <? php
    declare(strict_types=1);
    function test(? int $a): ? int
    {
        return $a;
    }
    var_dump(test(null)); // NULL
    var_dump(test(1)); // 1
    var_dump(test('a')); // ERROR

(3)null合并操作符

在PHP 7之前,人們經常會寫這樣的代碼:

    <? php
    $page = isset($_GET['page']) ? $_GET['page'] : 0;

PHP 7提供了一個新的語法糖“? ? ”,如果變量存在且值不為null,它會返回自身的值,否則返回它的第二個操作數。可以這樣改寫代碼:

    <? php
    $page = $_GET['page'] ? ? 0;

當代碼中有連續的三元運算符的時候還可以像下邊這樣寫:

    <? php
    $page = $_GET['page'] ? ? $_POST['page'] ? ? 0;

看起來是不是簡化了很多?

(4)常量數組

在PHP 7之前是無法通過define來定義一個數組常量的,PHP 7支持了這個操作:

    <? php
    define('ANIMALS', [
        'dog',
        'cat',
        'bird'
    ]);

(5)namespace批量導入

在PHP 7之前,如果要導入一個namespace下的多個class,我們需要這樣寫:

    <? php
    use Space\ClassA;
    use Space\ClassB;
    use Space\ClassC as C;

在PHP 7中支持批量導入:

    <? php
    use Space\{ClassA, ClassB, ClassC as C};

(6)throwable接口

在PHP 7之前,如果代碼中有語法錯誤,或者fatal error時,程序會直接報錯退出,但是在PHP 7中有了改變。PHP 7實現了全局throwable接口,原來的Exception和部分Error實現了該接口。這種Error可以像Exception一樣被第一個匹配的try / catch塊捕獲。如果沒有匹配的catch塊,則調用異常處理函數進行處理。如果尚未注冊異常處理函數,則按照傳統方式處理(fatal error)。

Error類并非繼承自Exception類,所以不能用catch (Exception $e) { ... } 來捕獲Error。可以用catch (Error $e) { ... },或者通過注冊異常處理函數(set_exception_handler())來捕獲Error:

    <? php
    try {
        undefindfunc();
    } catch (Error $e) {
        var_dump($e);
    }

    // 或者
    set_exception_handler(function($e){
        var_dump($e);
    });
    undefindfunc();

(7)Closure::call()

在PHP 7之前,我們需要動態地給一個對象添加方法時,可以通過Closure來復制一個閉包對象,并綁定到一個$this對象和類作用域:

    <? php
    class Test {
    private $num = 1;
    }

    $f = function() {
    return $this->num + 1;
    };

    $test = $f->bindTo(new Test, 'Test');
    echo $test();
    // 2

在PHP 7中新添加了Closure::call(),可以通過call來暫時綁定一個閉包對象到$this對象并調用它:

    <? php
    class Test {
        private $num = 1;
    }

    $f = function() {
        return $this->num + 1;
    };

    echo $f->call(new Test);
    // 2

(8)intdiv函數

PHP 7還增加了一個新的整除函數,在代碼中不需要再手動轉了:

    <? php
    // var_dump(intval(10 / 3));
    var_dump(intdiv(10, 3));

(9)list的方括號寫法

我們知道可以通過list來實現解構賦值,如下:

    <? php
    $arr = [1, 2, 3];
    list($a, $b, $c) = $arr;

PHP 7.1.0對其做了進一步的優化,可以將其寫成如下方式:

    <? php
    $arr = [1, 2, 3];
    [$a, $b, $c] = $arr;

注意:這里的[]并不是數組的意思,只是list的簡略形式。

除了上文這些,PHP7還有很多其他的改變和特性。例如,foreach遍歷數組時不再修改內部指針、移除了ASP和script PHP標簽、移除了$HTTP_RAW_POST_DATA、匿名類、類常量可見性等,讀者可以自行嘗試。

主站蜘蛛池模板: 苏尼特右旗| 汉中市| 手机| 西安市| 临西县| 芜湖市| 营口市| 榆树市| 昆山市| 苏尼特左旗| 廊坊市| 汪清县| 和顺县| 民和| 宽城| 保靖县| 北安市| 临洮县| 商河县| 蒲城县| 阜阳市| 博乐市| 保靖县| 略阳县| 扬中市| 新津县| 邯郸县| 宽甸| 蛟河市| 石首市| 于田县| 盘锦市| 鹤岗市| 集安市| 阿城市| 尉氏县| 揭东县| 孟州市| 新干县| 南平市| 翁源县|