- PHP 7底層設計與源碼實現
- 陳雷等
- 1485字
- 2019-01-04 16:53:40
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、匿名類、類常量可見性等,讀者可以自行嘗試。
- Google Flutter Mobile Development Quick Start Guide
- Learn Type:Driven Development
- Flink SQL與DataStream入門、進階與實戰
- HTML5+CSS3基礎開發教程(第2版)
- 機器人Python青少年編程開發實例
- 數據結構(C語言)
- Learn React with TypeScript 3
- Python機器學習基礎教程
- 運用后端技術處理業務邏輯(藍橋杯軟件大賽培訓教材-Java方向)
- Microsoft 365 Certified Fundamentals MS-900 Exam Guide
- JavaScript設計模式與開發實踐
- Learning Zimbra Server Essentials
- Learning PrimeFaces Extensions Development
- AngularJS Web Application Development Cookbook
- Python數據分析與挖掘實戰(第2版)