PHP 7.4 新功能更新列表

PHP 7.4 ,下一個 PHP 7 較小的發佈版,指望在 2019 年 11 月 28 日發佈。所以,如今是時候讓你們深刻了解這個版本添加哪些新特性使 PHP 更快、更可靠。
雖然 PHP 7.4 顯著地提高了性能和提升代碼可讀性,PHP 8 纔將會是 PHP 性能真正的里程碑,這在 JIT inclusion 的提案顯示已充分證實。

如今去無償遷移php

總之,今天咱們將概覽 PHP 7.4 最矚目的特性和性能提高。在繼續探索以前,你最好記住如下重要的時間節點:html

  • 6 月 6 日:PHP 7.4 Alpha 1
  • 7 月 18 日:PHP 7.4 Beta 1 – Feature freeze(特性固化)
  • 11 月 28 日:PHP 7.4 GA Release

你可從 the official RFC page 查看所有新特性和功能。git

QQ交流羣github


PHP 7.4 發佈日期:

PHP 7.4 將於 2019 年 11 月 28 日發佈。這是 PHP 7 的下一個小版本,會再次提高性能,提升代碼的可讀性和可維護性。docker


PHP 7.4 有什麼新功能?

在這邊文章中,咱們將討論 PHP 7.4 最終版本中應該增長一些變化和特性:數組


拋棄 array_merge : PHP 7.4 在數組表達式中引入了擴展運算符

從 PHP 5.6 開始,參數解析 是一種解析數組並遍歷到參數列表中的語法。要解析一個或遍歷一個數組,必須以 ...(三個點)做爲前綴,以下所示:瀏覽器

function test(...$args) { var_dump($args); }
test(1, 2, 3);複製代碼

如今 PHP 7.4 的 RFC 建議將這個功能擴展到數組定義中:安全

$arr = [...$args];複製代碼

擴展操做符在數組表達式 第一個明顯的優勢是性能。RFC 文檔bash

擴展操做符應該比 array_merge 性能更好。不只是由於擴展操做符是一種語言結構, array_merge 是一個函數,還由於能夠優化編譯常量數組的性能。

擴展操做符一個重要的優勢是支持任何可遍歷的對象, array_merge 函數只支持數組。服務器

下面是數組表達式中的參數解析示例:

$parts = ['apple', 'pear'];
$fruits = ['banana', 'orange', ...$parts, 'watermelon'];
var_dump($fruits);複製代碼

若是你在 PHP 7.3 或更早版本中運行此代碼,PHP 將拋出解析錯誤:

Parse error: syntax error, unexpected '...' (T_ELLIPSIS), expecting ']' in /app/spread-operator.php on line 3複製代碼

相反,PHP 7.4 將返回一個數組:

array(5) {
    [0]=>
    string(6) "banana"
    [1]=>
    string(6) "orange"
    [2]=>
    string(5) "apple"
    [3]=>
    string(4) "pear"
    [4]=>
    string(10) "watermelon"
}複製代碼

RFC 聲明咱們能夠屢次擴展同一個數組。並且,咱們能夠在數組中的任何地方使用擴展運算符語法,由於能夠在擴展運算符以前或以後添加普通元素。因此,就像下面代碼所示的那樣:

$arr1 = [1, 2, 3];
$arr2 = [4, 5, 6];
$arr3 = [...$arr1, ...$arr2];
$arr4 = [...$arr1, ...$arr3, 7, 8, 9];複製代碼

也能夠將函數返回的數組直接合併到另外一個數組:

function buildArray(){
    return ['red', 'green', 'blue'];
}
$arr1 = [...buildArray(), 'pink', 'violet', 'yellow'];複製代碼

PHP 7.4 輸出如下數組:

array(6) {
    [0]=>
    string(3) "red"
    [1]=>
    string(5) "green"
    [2]=>
    string(4) "blue"
    [3]=>
    string(4) "pink"
    [4]=>
    string(6) "violet"
    [5]=>
    string(6) "yellow"
}複製代碼

咱們也可使用 生成器:

function generator() {
    for ($i = 3; $i <= 5; $i++) {
        yield $i;
    }
}
$arr1 = [0, 1, 2, ...generator()];複製代碼

可是咱們不容許合併經過引用傳遞的數組。 考慮如下的例子:

$arr1 = ['red', 'green', 'blue'];
$arr2 = [...&$arr1];複製代碼

若是咱們嘗試按引用合併數組,則 PHP 會引起如下解析錯誤:

Parse error: syntax error, unexpected '&' in /app/spread-operator.php on line 3複製代碼

不管如何,若是第一個數組的元素是經過引用存儲的,則它們也將經過引用存儲在第二個數組中。 這是一個例子:

$arr0 = 'red';
$arr1 = [&$arr0, 'green', 'blue'];
$arr2 = ['white', ...$arr1, 'black'];複製代碼

這就是咱們使用 PHP 7.4 所得到的:

array(5) {
    [0]=>
    string(5) "white"
    [1]=>
    &string(3) "red"
    [2]=>
    string(5) "green"
    [3]=>
    string(4) "blue"
    [4]=>
    string(5) "black"
}複製代碼

The Spread operator 提案以 43 票對 1 票得到經過。


箭頭函數 2.0 (短閉包)

對於 PHP 而言,匿名函數 被認爲十分冗長而且難以使用和維護的。RFC 提出了更短而且語法更簡潔的 * 箭頭函數(短閉包),可以在很大程度上使咱們的 PHP 代碼更簡潔。

考慮以下例子:

function cube($n){
    return ($n * $n * $n);
}
$a = [1, 2, 3, 4, 5];
$b = array_map('cube', $a);
print_r($b);複製代碼

PHP 7.4 容許使用更簡潔的語法,上面的函數能夠重寫爲以下:

$a = [1, 2, 3, 4, 5];
$b = array_map(fn($n) => $n * $n * $n, $a);
print_r($b);複製代碼

目前,要感謝 use 語法,匿名函數 (閉包) 能夠從父做用域裏繼承已經定義的變量:

$factor = 10;
$calc = function($num) use($factor){
    return $num * $factor;
};複製代碼

可是在 PHP 7.4 中, 在父做用域裏定義的變量被隱式捕獲(隱式做用域綁定)了。如此一來,咱們可用只用一行代碼重寫整個上面的函數:

$factor = 10;
$calc = fn($num) => $num * $factor;複製代碼

咱們能夠像使用 use(變量) 同樣,直接使用在父做用域裏定義的變量,而且它也不會修改父做用域的變量。

新的語法對咱們構建更可讀可維護的代碼帶來了極大的改善。咱們也可使用參數和返回類型、默認值、變長參數列表(可變函數),能夠傳遞或返回引用等等。而後呢,短閉包還能夠被用做類方法,能夠像常規同樣使用 $this

RFC 已經以 51 票對 8 票經過了,因此咱們能夠期待在 PHP 7.4 新增功能裏見到它。


空合併賦值操做符

在 PHP 7 中,當咱們須要同時使用三元運算符和 isset() 時,合併運算符??)就能夠派上用場了。若是第一個操做數存在而且不爲 NULL,則返回該操做數。不然返回第二個操做數。示例以下:

$username = $_GET['user'] ?? 'nobody';複製代碼

這段代碼很簡單:獲取請求參數,若是不存在,則設置一個默認值。它的意思很明確,但若是出現像下方這個來自 RFC 示例中的更長的變量名呢?

$this->request->data['comments']['user_id'] = $this->request->data['comments']['user_id'] ?? 'value';複製代碼

從長遠的角度看,這段代碼可能有點難以維護。所以,爲了幫助開發人員編寫更直觀的代碼,這個 RFC 建議引入空合併賦值操做符??=)。所以,咱們能夠編寫以下代碼進行替代:

$this->request->data['comments']['user_id'] ??= 'value';複製代碼

若是左側的參數是 null,則使用右側參數的值。請注意,當合並運算符是比較運算符時,??= 就是一個賦值運算符。

這項建議以 37:4 的票數比例得到經過。


類型屬性 2.0

參數類型聲明(或類型提示)容許對將要傳遞給函數或者類方法的變量類型進行限定。該功能自 PHP 5 起可用,PHP 7.2 起可使用對象做爲數據類型。如今 PHP 7.4 經過添加 類屬性類型聲明 進一步擴展了類型提示。如下是一個基本的示例:

class User {
    public int $id;
    public string $name;
}複製代碼

支持 voidcallable 之外的全部類型

public int $scalarType;
protected ClassName $classType;
private ?ClassName $nullableClassType;複製代碼

這項 RFC 解釋了爲何不支持 voidcallable 返回值的緣由:

不支持 void 類型,由於它沒有用到而且語義不明確。
不支持 callable 類型,由於其行爲取決於上下文。

這樣咱們就能夠安全地使用 bool, int, float, string, array, object, iterable, self, parent, 任何類或接口名稱,而且能夠爲空 types (?type)。

類型能夠用於靜態屬性:

public static iterable $staticProp;複製代碼

也可使用 var 標記:

var bool $flag;複製代碼

能夠設置默認屬性值,固然必須與聲明的屬性類型匹配,可是隻有可爲空的屬性能夠具備默認的 null 值:

public string $str = "foo";
public ?string $nullableStr = null;複製代碼

相同類型適用於單個聲明中的全部屬性:

public float $x, $y;複製代碼

若是咱們對屬性類型進行錯誤處理會怎樣? 考慮如下代碼:

class User {
    public int $id;
    public string $name;
}

$user = new User;
$user->id = 10;
$user->name = [];複製代碼

在上面的代碼中,咱們聲明瞭字符串屬性類型,可是咱們將數組設置爲屬性值。 在這種狀況下,咱們將收到如下致命錯誤:

Fatal error: Uncaught TypeError: Typed property User::$name must be string, array used in /app/types.php:9複製代碼

該 RFC 已以 70 票對 1 票得到批准。


弱引用

在這項 RFC 中,PHP 7.4 引入了 WeakReference (弱引用) 類型,這樣開發者就能夠保留對對象的引用,而這不會阻止對象自己被破壞。

目前,PHP 經過使用諸如 pecl-weakref 之類的擴展名來支持弱引用。 不管如何,新的 API 與記錄的 WeakRef 類不一樣。

這是 一份簡單的 demo 來自這項提議的做者 Nikita Popov

$object = new stdClass;
$weakRef = WeakReference::create($object);

var_dump($weakRef->get());
unset($object);
var_dump($weakRef->get());複製代碼

第一個 var_dump 打印對象 object(stdClass)#1 (0) {} ,第二個 var_dump 打印引用爲 NULL,由於所引用的對象已被銷燬。

該 RFC 以 28 票對 5 票得到經過。


協變量返回和協變量參數

方差 是類層次結構的一個屬性,描述了類型構造函數的類型如何影響 subtypes。 一般,類型構造函數能夠是:

  • Invariant: 若是超類型的類型約束子類型的類型。
  • Covariant:若是保留類型的順序(類型從更具體到更通常)。
  • Contravariant:若是它顛倒了順序(類型從更通用到更具體地排序)。

目前,PHP 的參數和返回類型大部分不變,只有少數例外。 該 RFC 建議容許在參數類型和返回類型上進行協方差和協變,並提供一些代碼示例。

這是 協變量返回 的一個簡單例子:

interface Factory {
    function make(): object;
}

class UserFactory implements Factory {
    function make(): User;
}複製代碼

這個是 協變量參數 一個示例:

interface Concatable {
    function concat(Iterator $input); 
}

class Collection implements Concatable {
    // accepts all iterables, not just Iterator
    function concat(iterable $input) {/* . . . */}
}複製代碼

請參閱 RFC 以更詳細地瞭解 PHP 7.4 協變量返回和協變量參數。

該 RFC 以 39 對 1 票得到經過。


預加載

這項提議 來自 Dmitry Stogov ,這是咱們的受支持的提議之一,由於它能夠顯着提升 PHP 的性能。預加載 是在模塊初始化時將庫和框架加載到 OPCache 的過程,詳細瞭解 PHP 生命週期





PHP 生命週期 (資源鏡像: PHP Internals)

Dmitry 的話來講,預加載是這樣工做的:

在服務器啓動時(在運行任何應用程序代碼以前),咱們能夠將一組 PHP 文件加載到內存中,並使它們的內容 永久可用 給該服務器將服務的全部後續請求。 與內部實體徹底同樣,這些文件中定義的全部函數和類也可用於開箱即用的請求。

這些文件在服務器啓動時加載,在任何應用程序以前執行,而且對之後的任何請求都可用。 就性能而言,這很棒。

預加載由特定的 php.ini 指令控制:opcache.preload。 該指令指定在服務器啓動時要編譯和執行的 PHP 腳本。 此文件可用於預加載其餘文件,包括它們或經過 opcache_compile_file() 函數(有關更多信息,請參見 [PHP 文檔](www.php.net/manual/en/f… -file.php))。

可是有一個缺點。 實際上,RFC 裏有明確聲明:

預加載的文件將永遠保留在 opcache 內存中。 不從新啓動另外一臺服務器,對其相應源文件的修改將不會生效。

可是,在預加載的文件中定義的全部函數將被永久加載到 PHP 函數和類表中,而且對於之後的每一個請求都可用。 即便這些改進可能有很大的不一樣,也會帶來良好的性能改進。

您能夠在官方的 預加載 RFC 頁面 上閱讀有關預加載的限制和例外的更多信息。


新的自定義對象序列化機制

這是 Nikita Popov另外一項提議

當前,咱們有兩種不一樣的機制能夠在 PHP 中對對象進行自定義序列化:

  • __sleep()__wakeup() 魔術方法
  • Serializable 接口

根據 Nikita 的說法,這兩個選項都存在致使複雜且不可靠的代碼的問題。 您能夠在 RFC 中深刻研究此主題。 在這裏我只是提到新的序列化機制應該經過提供兩種新的魔術方法__serialize()__unserialize() 來解決這些問題,這兩種方法結合了兩個現有機制。

該提案以 20 票對 7 票得到經過。


已廢棄

PHP 7.4 不推薦使用如下功能。 要得到更全面的棄用列表,請查看 PHP 7.4 升級說明


更改串聯運算符的優先級

當前,在 PHP 中,+- 算術運算符以及 . 字符串運算符保持關聯性並具備相同的優先級。(閱讀更多相關信息運算符優先級)

例如,考慮如下行:

echo "sum: " . $a + $b;複製代碼

在 PHP 7.3 中,此代碼產生如下警告:

Warning: A non-numeric value encountered in /app/types.php on line 4複製代碼

這是由於從左到右評估了串聯。 與編寫如下代碼相同:

echo ("sum: " . $a) + $b;複製代碼

這項 RFC 建議更改運算符的優先級,給 . 賦予比 +- 運算符低的優先級,以便老是在字符串鏈接以前執行加法和減法。 該行代碼應等效於如下內容:

echo "sum: " . ($a + $b);複製代碼

這是一個兩步建議:

  • 從 7.4 版開始,PHP 在遇到帶有 +-. 的非括號表達式時應發出棄用通知。
  • 這些運算符的優先級的實際更改應在 PHP 8 中添加。

兩項提議均以絕大多數票得到批准。


棄用左聯想三元運算符

在 PHP 中,與許多其餘語言不一樣,三元運算符是左關聯的。 根據 Nikita Popof 的說法,這對於在不一樣語言之間進行切換的開發者可能會形成混淆。

當前,在 PHP 中,如下代碼是正確的:

$b = $a == 1 ? 'one' : $a == 2 ? 'two' : $a == 3 ? 'three' : 'other';複製代碼

解釋爲:

$b = (($a == 1 ? 'one' : $a == 2) ? 'two' : $a == 3) ? 'three' : 'other';複製代碼

這可能會致使錯誤,由於這可能不是咱們打算要作的。 所以,該 RFC 建議棄用並刪除三元運算符的左關聯性,並強制開發人員使用括號。

這是另外兩個步驟的建議:

  • 從 PHP 7.4 開始,不顯式使用括號的嵌套三元將拋出棄用警告。
  • 從 PHP 8.0 開始,將出現編譯時錯誤。

該提案以 35 到 10 票得到批准。


在 Docker 中安裝和運行 PHP 7.4

想在 Docker 上試試嗎?幸運的是在 Docker 環境下你不須要再手動編譯和配置 PHP 7.4 了 。若是你已經安裝了 Docker , 那隻須要花幾秒鐘安裝這個非官方的 PHP-FPM 7.4 Docker 鏡像 就能夠在命令行中進行測試了。





若是你想要運行 PHP 7.4 的代碼到你的瀏覽器中,那你還須要給 Docker 安裝 Nginx 或 Apache 鏡像。不用擔憂,只要按照開發指南。 將示例命令拷貝粘貼到命令行中並運行,就能夠了。

但願以上內容能幫助到你們,若是喜歡個人文章,想與一羣資深開發者一塊兒交流學習的話,獲取更多學習資料歡迎加入個人學習交流羣677079770一塊兒學習成長,一樣也能夠關注一下個人專欄。謝謝~

相關文章
相關標籤/搜索