【PHP7源碼分析】PHP7到底有多快,基準測試與特性分析告訴你

順風車運營研發團隊 王坤 發表至21CTO公衆號(https://mp.weixin.qq.com/s/ph...php

clipboard.png

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

2015年夏天,備受矚目的PHP7發佈了第一個Alpha版本。以後,通過大概3個 Beta 版本和8個RC 版本,2016年1月 PHP7正式發佈。PHP7是PHP一個很是重要的版本,相對於PHP5.x 版本,有着很是大的革新,尤爲是在性能方面。若是讀者的網站是使用的 PHP5.x,那麼使用PHP7後將幾乎無成本的獲得一倍的性能提高。感謝開發者!閉包

1. PHP7到底有多快!
下面咱們來測試下PHP7性能提高到底有多少。本地環境下以相同的編譯參數分別安裝PHP5.5.3八、PHP7的第一個正式版本7.0.2和7.1.0版本,在CLI 模式下運行PHP 源碼中的基準測試腳本。架構

(1)測試環境函數

本地搭建的vagrant虛擬機,操做系統CentOS7,單核CPU 2.00GHz,內存1GB。性能

(2)基準測試指標測試

q Time——執行時間,以秒爲單位;優化

q %rel, gain——相對於上一版本節省的執行時間;網站

q %abs, gain——與 PHP 5.5.38 相比腳本節省的執行時間。this

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

clipboard.png
表1-1 測試結果

由上邊的測試結果能夠看出來,PHP7.1.0 的基準性能幾乎是PHP5.5.38的3倍左右,開啓了 opcache 的狀況下更是達到了4.4倍之多,這是一個很是顯著的提高,這些性能提高是如何作到的呢,本書後續的章節將一一介紹。

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

2. PHP7炫目新特性

PHP7 除了在性能方面的極大提高,還添加了不少新的特性,如太空船操做符、標量類型聲明、返回值的類型聲明、全局的 throwable 接口、抽象語法樹等,下邊咱們分別介紹。

(1)太空船操做符

太空船操做符用於比較兩個表達式。例如,當 $a 小於、等於或大於 $b 時它分別返回 -一、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)標量類型聲明和返回值的類型聲明

PHP7 能夠對下面幾種類型的參數作聲明:字符串(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型,若是不能轉換則會直接報錯。

PHP7.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

PHP7.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合併操做符

在 PHP7 以前,咱們會常常寫這樣的代碼:

<?php

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

PHP7 提供了一個新的語法糖 ??,若是變量存在且值不爲NULL,它會返回自身的值,不然返回它的第二個操做數。咱們能夠這樣改寫代碼:

<?php

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

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

<?php

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

看起來是否是簡化了不少?

(4)常量數組

PHP7 以前是沒法經過 define 來定義一個數組常量的,PHP7 支持了這個操做:

<?php

define('ANIMALS', [

   'dog',

   'cat',

   'bird'

]);

(5)namespace 批量導入

PHP7 以前若是要導入一個 namespace 下的多個 class ,咱們須要這樣寫:

<?php

use Space\ClassA;

use Space\ClassB;

use Space\ClassC as C;

在 PHP7 中支持批量導入:

<?php

use Space\{ClassA, ClassB, ClassC asC};

(6)throwable 接口

在 PHP7 以前,若是代碼中有語法錯誤,或者 fater error 時,程序會直接報錯退出,可是在 PHP7 中有了改變。PHP7 實現了全局 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);

}

 

// or

set_exception_handler(function($e){

   var_dump($e);

});

undefindfunc();

(7)Closure::call()

在 PHP7 以前咱們須要動態給一個對象添加方法時能夠經過 Closure 來複制一個閉包對象綁定到一個 $this 對象和類做用域:

<?php

class Test {

   private $num = 1;

}

 

$f = function() {

   return $this->num + 1;

};

 

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

echo $test();

// 2

在 PHP7 中新添加了 Closure::call(),能夠經過 call 來暫時綁定一個閉包對象到 $this 對象並調用它:

<?php

class Test {

   private $num = 1;

}

 

$f = function() {

   return $this->num + 1;

};

 

echo $f->call(new Test);

// 2

(8)intdiv 函數

PHP7 還增長了一個新的整除函數,代碼中不須要再手動轉一下了:

<?php

// var_dump(intval(10 / 3));

var_dump(intdiv(10, 3));

(9)list 的方括號寫法

咱們知道能夠經過 list 來實現解構賦值,以下:

<?php

$arr = [1, 2, 3];

list($a, $b, $c) = $arr;

PHP7.1.0 對其作了進一步的優化,能夠寫成以下方式:

<?php

$arr = [1, 2, 3];

[$a, $b, $c] = $arr;

注意:這裏的 [] 並非數組的意思,只是 list 的簡略形式。

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

本文節選自《PHP 7底層設計與源碼實現》

clipboard.png

clipboard.png

推薦理由:

  • 滴滴出行專家聯合撰寫,PHP領域大咖夏緒宏、韓天峯、王晶、謝華亮(黑夜路人)、伍星聯袂推薦
  • 全面吃透PHP內核架構、核心實現與內存管理、詞法與句法解析、Zend 虛擬機、函數及關鍵擴展等設計細節與源碼實現
相關文章
相關標籤/搜索