PHP 7.2 已經在 2017 年 11 月 30 日 正式發布 。這次發布包含新特性、功能,及優化,以讓我們寫出更好的代碼。在這篇文章裡,我將會介紹一些 PHP 7.2 最有趣的語言特性。
你可以在 Requests For Comments 頁面查看完整的更動清單。
核心改進
參數類型聲明
從 PHP5 起,我們可以指定函數參數的預期聲明類型。如果傳參類型錯誤,PHP 就會拋出一個錯誤。
參數類型聲明 (也稱類型提示) 指定預期要傳參給函數或者類方法的參數類型。
這里有個例子:
class MyClass {
public $var = 'Hello World';
}
$myclass = new MyClass;
function test(MyClass $myclass){
return $myclass->var;
}
echo test($myclass);
在這段代碼中,測試函數需要一個 MyClass 實例。不正確的參數數據類型會導致一個致命錯誤。
Fatal error: Uncaught TypeError: Argument 1 passed to test() must be an instance of MyClass, string given, called in /app/index.php on line 12 and defined in /app/index.php:8
從 PHP 7.2 類型提示 可以被用在對象型數據上,並且這個改進允許通用對象類型作為一個函數或者方法的參數。這里有個例子:
class MyClass {
public $var = '';
}
class FirstChild extends MyClass {
public $var = 'My name is Jim';
}
class SecondChild extends MyClass {
public $var = 'My name is John';
}
$firstchild = new FirstChild;
$secondchild = new SecondChild;
function test(object $arg) {
return $arg->var;
}
echo test($firstchild);
echo test($secondchild);
在以上示例中,我們調用了兩次測試函數,每次都傳遞一個不同的對象。這在之前的 PHP 版本中是前所未有的。
在 Docker 中測試 PHP 7.0 和 PHP 7.2 的類型提示。
對象返回類型聲明
若變量類型指定函數參數的預期類型,返回值類型同樣也可以被指定預期類型。
返回類型聲明 指定一個函數應該返回的預期類型。
PHP 7.2 起,對象數據類型可以使用返回類型聲明。這里有個例子:
class MyClass {
public $var = 'Hello World';
}
$myclass = new MyClass;
function test(MyClass $arg) : object {
return $arg;
}
echo test($myclass)->var;
之前的 PHP 版本會拋出以下致命錯誤:
Fatal error: Uncaught TypeError: Return value of test() must be an instance of object, instance of MyClass returned in /app/index.php:10
當然,PHP 7.2 的代碼會打印出 'Hello World'。
參數類型泛化
PHP 目前是不允許子類和它父類或者接口的參數類型有任何差異的。 這是什么意思呢? 參考下以下代碼:
<?php
class MyClass {
public function myFunction(array $myarray) { /* ... */ }
}
class MyChildClass extends MyClass {
public function myFunction($myarray) { /* ... */ }
}
這里我們省略了子類中的參數類型。 在 PHP 7.0 中,會產生以下警告:
Warning: Declaration of MyChildClass::myFunction($myarray) should be compatible with MyClass::myFunction(array $myarray) in %s on line 8
從 PHP 7.2 起,我們可以忽略子類中的類型 而不會破壞任何代碼。這個方案使得我們可以在庫中升級類,從而可以使用類型提示,卻無需更新其所有的子類。
列表語法中的尾隨逗號
在 PHP 數組的最后一個元素上使用尾隨逗號是 合法語法 ,並且 有時候鼓勵這么做 ,可以很輕松的避免增加新元素的時候出現缺失逗號的錯誤。 從 PHP 7.2 在 分組命名空間 中,我們可以使用尾隨逗號 。
參閱 列表語法中的尾隨逗號 獲得 RFC 的直觀感知和一些示例代碼。
安全性改進
密碼哈希中的Argon2
Argon2 是榮獲 2015 年密碼哈希算法比賽中的冠軍的強大哈希算法, PHP 7.2 將其作為安全 Bcrypt 算法的替代品。 新版的 PHP 中引入了 PASSWORD_ARGON2I 常量,現在可以在 password_* 系列函數中使用:
password_hash('password', PASSWORD_ARGON2I);
與只使用一個 cost 因子的 Bcrypt 不同, Argon2 使用三個 cost 因子 區分如下:
- 定義哈希計算期間應該消耗的KiB數量的內存開銷(默認值為1 << 10或1024 KiB或1 MiB)
- 定義哈希算法迭代次數的時間開銷(默認值為2)
- 並行因子,用於設置哈希計算時使用的並行線程數(缺省值為2)
以下三個新常量定義了默認的 cost 因子:
- PASSWORD_ARGON2_DEFAULT_MEMORY_COST
- PASSWORD_ARGON2_DEFAULT_TIME_COST
- PASSWORD_ARGON2_DEFAULT_THREADS
這里有個例子:
$options = ['memory_cost' => 1<<11, 'time_cost' => 4, 'threads' => 2];
password_hash('password', PASSWORD_ARGON2I, $options);
查閱 Argon2 密碼哈希 的更多信息。
Libsodium 成為 PHP 核心的組成部分
從 7.2 版開始,PHP 在其核心中涵蓋了 Sodium library 。 Libsodium 是一個跨平台和跨語言的庫,用於加密,解密,簽名,密碼哈希等。 這個庫之前是 通過 PECL 來提供的。 有關 Libsodium 函數列表,參閱 快速入門。 也可參閱 PHP 7.2: 第一個將現代加密技術添加到其標准庫的編程語言。
棄用
這里有個 PHP 7.2 棄用函數和特性 清單,PHP 8.0 之后將全部移除。
PHP 5.1 中 __autoload
函數已被 spl_autoload_register 取代。現在會在編譯期間報一個棄用通知。
當拋出致命錯誤的時候,會創建 $php_errormsg
局部變量。 PHP 7.2 中應該使用 error_get_last 和 error_clear_last 替代這種做法。
create_function()
可以創建一個具有函數名稱的函數,將函數參數和函數體作為該函數的列表傳入。因為安全問題和性能表現不佳,它被標記為棄用,鼓勵用封裝替代。
mbstring.func_overload
ini 設置為非零值已經被標記為棄用。
(unset) cast
是個總是返回 null 的表達式,並且毫無用處。
如果傳入第二個參數,parse_str() 將查詢字符串解析到數組當中, 否則解析到本地符號表。 因為安全原因, 不建議 在函數作用域中動態設置變量,使用不帶第二個參數的 parse_str() 將拋一個棄用通知。
gmp_random()
是平台相關的,將會被廢棄。使用 gmp_random_bits() 和 gmp_random_rage() 代替。
each()
在數組上迭代的行為非常像 foreach(),但 foreach() 基於一些原因而成為更優選擇,例如它的速度快上 10 倍。現在在循環中使用前者將會拋出一個廢棄提示。
assert()
函數檢查給定的斷言,並在結果為 FALSE 的時候進行相關處理。 帶有字符串參數的 assert()
現在已經棄用,因為它有 RCE 漏洞。 zend.assertion ini 選項可以關閉斷言表達式。
$errcontext
是一個包含產生錯誤時的局部變量數組。它可被作為錯誤處理程序 set_error_handler() 函數的最后一個參數。
PHP 7.2 對 WordPress 用戶意味着什么?
根據官方 WordPress 統計頁 所示,截至撰寫本文時,只有 19.8% 的 WordPress 用戶升級到了 PHP 7。只有 5%使用 PHP 7.1。你可以看到超過 40% 的用戶仍然使用 PHP 5.6,更可怕的是超過 39% 的用戶在使用已經不受支持的 PHP 版本。截至 2016 年 12 月,WordPress.org 為 PHP 5.6 版本的用戶修改 官方建議 為建議使用 PHP 7 或以上的版本。
WordPress PHP 7.1 數據統計
以上的數據表現並不令人愉悅,因為看上去 PHP 7 好像更快點。下面是一些統計數據:
- PHP 官方 基准測試 顯示 PHP 7 允許系統每秒執行2次請求,與 PHP 5.6 相比,幾乎只是一般的延遲。
- Christian Vigh 也發布了一個 PHP 性能測試對比 他發現 PHP 5.2 比 PHP 7 慢了近 400%。
我們在 2018 運行了性能基准測試 PHP 5.6 vs PHP 7 vs HHVM。與上述基准測試類似,我們發現 PHP 7.2 與 PHP 5.6 相比每秒可執行幾乎三倍數量的事務(請求)。
WordPress 基准測試
- WordPress 4.9.4 PHP 5.6 基准測試結果: 49.18 req/sec
- WordPress 4.9.4 PHP 7.0 基准測試結果: 133.55 req/sec
- WordPress 4.9.4 PHP 7.1 基准測試結果:134.24 req/sec
- WordPress 4.9.4 PHP 7.2 基准測試結果:148.80 req/sec 🏆
- WordPress 4.9.4 HHVM 基准測試結果:144.76 req/sec
許多東西在僅僅在更新上比較慢,因為要花時間去參與測試所有新的第三方插件和主題確保它們可以正常運行。很多時候,慢是因為它們還沒完成。不確定你運行的 PHP 是什么版本?其中一個很最簡單的方法就是使用這個工具 Pingdom 或者 Google Chrome開發工具.。第一個 HTTP 請求頭一般將會展示你的版本。
檢查 PHP 版本
這將依賴於主機不修改 X-Powered-By 頭信息的值。如果修改了的話,你可能就看不到 PHP 的版本信息了,這種情況下你需要 通過 FTP 上傳文件.。或者你總是去詢問主機。
升級到 PHP 7.2
PHP 7.2 還有一部分沒完成,但是你可以先嘗嘗鮮。你可以 測試你的 WordPress 本地站點 或者在類似 Docker 環境中檢查你的腳本,你可以在命令行中測試比較不同的 PHP 版本。
結語
准備好切換到 PHP 7.2 了嗎?不過至少希望你首先已經過渡到了 PHP 7 以上的版本了。如果你現在還沒准備好測試的話,那么,升級你的腳本,檢查你的代碼,說說你對 PHP 7.2 的首次體驗。
更多現代化 PHP 知識,請前往 Laravel / PHP 知識社區