PHP 8 還有半年就要來了, 來看看有哪些新特性

新的 PHP 主要版本 PHP8 預計將於 2020 年底發佈。

它現在正處於非常活躍的開發中,所以在接下來的幾個月裏,開發速度和開發進程可能會有很大的變化。

官方羣點擊此處

在這篇文章中,我會羅列出 PHP8 中會發生的一些改變:新功能、性能改進和突破性變化。

因爲 PHP8 是一個新的主要版本,所以代碼及語法向下兼容性會更低。

如果您一直保持與最新版本保持同步,那麼升級應該不會太難,因爲大多數突破性的更改在 7.* 版本中都已棄用。

除了突破性的變化,PHP8 還帶來了一些不錯的新特性,比如 JIT 編譯器和 union types,當然還有其它更多的特性。

新特性

從新特性開始說起,但是 PHP8 仍在積極開發中,因此這個清單將隨着時間的推移而增長。

聯合類型 (Union types) RFC

考慮到 PHP 的動態類型特性,聯合類型在很多情況下都很有用。

聯合類型是兩個或多個類型的集合,這些類型指示可以使用這兩個類型中的任何一個。

public function foo(Foo|Bar $input): int|float;

我怎麼感覺這個和 C 語言裏的聯合體有點相似。

請注意,void 永遠不能是聯合類型的一部分,因爲它表示 “根本沒有返回值”。

此外,可以使用 |NULL 或使用現有的?。

public function foo(Foo|null $foo): void;
public function bar(?Bar $bar): void;

JIT RFC

JIT-Just-In-Time 編譯器承諾顯著提高性能,儘管在 Web 應用可能沒有較大的好處。

在這一點上還沒有任何準確的基準,但它們肯定會出現的。

靜態返回類型 (Static return type) RFC

雖然已經可以返回 self ,但在 PHP8 之前,靜態不是有效的返回類型。考慮到 PHP 的動態類型特性,它對許多開發人員都很有用。

class Foo
{
 public function test(): static
 {
 return new static();
 }
}

弱映射 (Weak maps) RFC

基於在 PHP 7.4 中添加的 WeakRefs RFC 的基礎上,在 PHP 8 中 添加了 WeakMap 實現。WeakMap 包含對對象的引用,這不會阻止這些對象被垃圾回收。

以 ORM 爲例,它們經常實現包含對實體類的引用的緩存,以提高實體之間關係的性能。

這些實體對象不能被垃圾回收,只要該緩存有對它們的引用,即使緩存是唯一引用它們的東西。

如果該緩存層改爲使用弱引用和映射,則 PHP 將在其他對象不再引用這些對象時對它們進行垃圾回收。

特別是在 ORM 的情況下,它可以在一個請求中管理數百個 (如果不是數千個) 實體;弱映射可以提供一種更好、更資源友好的方式來處理這些對象。

以下是 Weak maps 的用法,RFC 中的一個示例:

class Foo 
{
 private WeakMap $cache;
 public function getSomethingWithCaching(object $obj): object
 {
 return $this->cache[$obj]
 ??= $this->computeSomethingExpensive($obj);
 }
}

可以在對象上使用::class RFC

一個小而有用的新特性:現在可以對對象使用::class,而不必對它們使用 get_class()。

它的工作方式與 get_class() 相同。

$foo = new Foo();
var_dump($foo::class);

創建 DateTime 對象的接口

您已經可以使用 DateTime::createFromImmutable($immutableDateTime),從 DateTimeImmutable 對象創建 DateTime 對象,但是反過來很棘手。

通過添加 DateTime::createFromInterface() 和 DatetimeImmutable::createFromInterface(),現在有了一種將 DateTime 和 DateTimeImmutable 對象相互轉換的通用方法。

DateTime::createFromInterface(DateTimeInterface $other);
DateTimeImmutable::createFromInterface(DateTimeInterface $other);

新的 Stringable 接口 RFC

Stringable 接口可用於鍵入提示任何字符串或實現__toString()。

此外,每當類實現__toString() 時,它都會自動在幕後實現接口,不需要手動實現它。

class Foo
{
 public function __toString(): string
 {
 return 'foo';
 }
}
function bar(Stringable $stringable) { /* … */ }
bar(new Foo());
bar('abc'); 

新的 str_contains () 函數 RFC

有些人可能會說這是早就應該實現的功能,但是我們最終不必再依賴 strpos () 來知道一個字符串是否包含另一個字符串。

以前:

if (strpos('string with lots of words', 'words') !== false) { /* … */ }

現在:

if (str_contains('string with lots of words', 'words')) { /* … */ } 

新的 fdiv () 函數 PR

新的 fdiv () 函數的作用類似於 fmod () 和 intdiv () 函數,它們允許被 0 整除。

您將得到 INF、-INF 或 NaN ,而不是錯誤,具體取決於大小寫。

新的 get_debug_type () 函數 RFC

  • get_debug_type () 返回一個變量的類型。
  • 聽起來像是 gettype () 可以實現的功能。
  • get_debug_type () 爲數組、字符串、匿名類和對象返回更有用的輸出。
  • 例如,在類 \foo\Bar 上調用 gettype () 將返回 Object。
  • 使用 get_debug_type () 將返回類名。
  • 可以在 RFC 中找到 get_debug_type () 和 gettype () 之間差異的完整列表。

改進 traits 裏的抽象方法 RFC

traits 可以指定必須由使用它們的類實現的抽象方法。

但是有一個警告:在 PHP8 之前,這些方法實現的簽名沒有經過驗證。

在以下代碼中有效:

trait Test {
 abstract public function test(int $input): int;
}
class UsesTrait
{
 use Test;
 public function test($input)
 {
 return $input;
 }
}

在使用 traits 並實現其抽象方法時,PHP8 將執行正確的方法簽名驗證。

這意味着您需要改寫以下內容:

class UsesTrait
{
 use Test;
 public function test(int $input): int
 {
 return $input;
 }
}

token_get_all () 的對象接口 RFC

函數的作用是:返回值的是一個數組。

此 RFC 使用 PhpToken::getall () 方法添加一個 PhpToken 類。

此實現使用對象,而不是普通值。

它消耗更少的內存,更容易閱讀。

變量語法調整 RFC

來自 RFC:“統一變量語法 RFC 解決了 PHP 變量語法中的一些不一致問題”,這個 RFC 打算解決少數被忽略的情況。

內部函數的類型批註

很多人都參與到爲所有內部函數添加適當類型註釋的工作中。

這是一個長期存在的問題,通過在以前版本中對 PHP 所做的所有更改,最終可以解決這個問題。

這意味着內部函數和方法在反射中將具有完整的類型信息。

統一錯誤類型 RFC

PHP 中的用戶定義函數已經拋出 TypeErrors,但是內部函數沒有拋出 TypeErrors,而是發出警告並返回 NULL。

從 PHP8 開始,內部函數的行爲已經保持一致。

重新分類 zend engine 報錯 RFC

許多以前只觸發警告或通知的錯誤已轉換爲適當的錯誤。

以下警告已更改。

未定義變量:錯誤異常而不是通知。

未定義的數組索引:警告而不是通知。

被零除:DivisionByZeroError 異常而不是警告。

嘗試遞增 / 遞減非對象的屬性‘% s’:錯誤異常而不是警告。

試圖修改非對象的屬性‘% s’:錯誤異常而不是警告。

嘗試分配非對象的屬性‘% s’:錯誤異常而不是警告。

從空值創建默認對象:錯誤異常而不是警告。

正在嘗試獲取非對象的屬性‘% s’:警告而不是通知。

未定義屬性:% s::$% s:警告而不是通知。

無法將元素添加到數組,因爲下一個元素已被佔用:錯誤異常而不是警告。

無法取消設置非數組變量中的偏移量:錯誤異常而不是警告。

不能將標量值用作數組:錯誤異常而不是警告。

只能解包數組和遍歷:TypeError 異常而不是警告。

爲 foreach () 提供的參數無效:TypeError 異常而不是警告。

偏移類型非法:TypeError 異常而不是警告。

isset 中的偏移類型非法或爲空:TypeError 異常而不是警告。

未設置中的偏移類型非法:TypeError 異常而不是警告。

數組到字符串的轉換:警告而不是通知。

資源 ID#% d 用作偏移量,轉換爲整數 (% d):警告而不是通知。

發生字符串偏移量轉換:警告而不是通知。

未初始化的字符串偏移量:% d:警告而不是通知。

無法將空字符串分配給字符串偏移量:錯誤異常而不是警告

默認錯誤報告級別

現在是 E_ALL,而不是除 E_NOTICE 和 E_DEVERATED 之外的所有內容。

這意味着可能會彈出許多以前被悄悄忽略的錯誤,儘管在 PHP8 之前可能已經存在。

@運算符不再忽略致命錯誤

此更改可能會揭示在 PHP8 之前隱藏的錯誤。請確保在生產服務器上設置 display_errors=off !

串聯優先級 RFC

雖然在 PHP7.4 中已不推薦使用,但此更改現在生效。

如果你這樣寫的話:

echo "sum: " . $a + $b;

PHP 以前會這樣解釋它:

echo ("sum: " . $a) + $b;

PHP 8 將會這樣解釋它:

echo "sum: " . ($a + $b);

反射方法簽名更改

反射類的三個方法簽名已更改:

ReflectionClass::newInstance($args);
ReflectionFunction::invoke($args);
ReflectionMethod::invoke($object, $args);

現已成爲:

ReflectionClass::newInstance(...$args);
ReflectionFunction::invoke(...$args);
ReflectionMethod::invoke($object, ...$args);

升級指南指定,如果您擴展了這些類,並且仍然希望同時支持 PHP 7 和 PHP 8,則允許以下簽名:

ReflectionClass::newInstance($arg = null, ...$args);
ReflectionFunction::invoke($arg = null, ...$args);
ReflectionMethod::invoke($object, $arg = null, ...$args); 

 

更多學習內容請訪問:

騰訊T3-T4標準精品PHP架構師教程目錄大全,只要你看完保證薪資上升一個臺階(持續更新)

以上內容希望幫助到大家,很多PHPer在進階的時候總會遇到一些問題和瓶頸,業務代碼寫多了沒有方向感,不知道該從那裏入手去提升,對此我整理了一些資料,包括但不限於:分佈式架構、高可擴展、高性能、高併發、服務器性能調優、TP6,laravel,YII2,Redis,Swoole、Swoft、Kafka、Mysql優化、shell腳本、Docker、微服務、Nginx等多個知識點高級進階乾貨需要的可以免費分享給大家,需要的可以加入我的官方羣點擊此處

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章