PHP 8 新特性

PHP 8猫牡,PHP 的一個新的大版本,預(yù)計(jì)將于 2020 年 12 月 3 日發(fā)布燕锥,這意味著將不會有 PHP 7.5 版本。PHP8 目前正處于非趁醪酰活躍的開發(fā)階段归形,所以在接下來的幾個月里,情況可能會發(fā)生很大的變化鼻由。

我PHP學(xué)習(xí)交流群點(diǎn)擊此處暇榴。

在這篇文章中厚棵,我會維持一個最新的清單列表,列出預(yù)計(jì)會出現(xiàn)的新特性蔼紧、性能提升和突破性的變化婆硬。由于 PHP 8 是一個新的大版本,因此您的代碼被破壞的可能性更高奸例。如果您始終保持運(yùn)行 PHP 的最新版本彬犯,那么升級相對來說就會輕松很多,因?yàn)樵?7. * 版本中查吊,大多數(shù)重大更改均已棄用谐区。

除重大更改外,PHP 8 還帶來了一些不錯的新功能逻卖,比如說?JIT 編譯器?,?聯(lián)合類型?,?屬性宋列,以及更多。

新特性

從新特性開始评也,請記住 PHP8 仍處于活動開發(fā)階段炼杖,因此此列表將隨著時間的推移而增長。

聯(lián)合類型?rfc

考慮到 PHP 動態(tài)語言類型的特性仇参,現(xiàn)在很多情況下嘹叫,聯(lián)合類型都是很有用的。聯(lián)合類型是兩個或者多個類型的集合诈乒,表示可以使用其中任何一個類型罩扇。

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

請注意,聯(lián)合類型中不包含?void怕磨,因?yàn)?void?表示的含義是 “根本沒有返回值”喂饥。 另外,可以使用?|null?或者現(xiàn)有的???表示法來表示包含?nullable?的聯(lián)合體 :

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

public function bar(?Bar $bar): void;

JIT?rfc

JIT — just in time — 編譯器雖然不總是在 Web 請求的上下文中肠鲫,但是有望顯著地提高性能员帮。目前還沒有完成任何準(zhǔn)確的基準(zhǔn)測試,但是肯定會到來导饲。

如果您想進(jìn)一步了解 JIT 對 PHP 的作用捞高,可以閱讀我寫過的另一篇文章此處

屬性?rfc

屬性在其他語言中通常被稱為?注解?渣锦,提供一種在無需解析文檔塊的情況下將元數(shù)據(jù)添加到類中的方法硝岗。

快速瀏覽一下,這里有一份來自 RFC 的屬性示例:

use App\Attributes\ExampleAttribute;

<<ExampleAttribute>>

class Foo

{

? ? <<ExampleAttribute>>

? ? public const FOO = 'foo';

? ? <<ExampleAttribute>>

? ? public $x;

? ? <<ExampleAttribute>>

? ? public function foo(<<ExampleAttribute>> $bar) { }

}

<<PhpAttribute>>

class ExampleAttribute

{

? ? public $value;

? ? public function __construct($value)

? ? {

? ? ? ? $this->value = $value;

? ? }

}

如果您想深入了解屬性如何工作以及如何構(gòu)建自己的屬性袋毙,您可以在此博客上閱讀有關(guān)深入屬性的信息型檀。

新增 static 返回類型 rfc

盡管已經(jīng)可以返回 self,但是 static 直到 PHP 8 才是有效的返回類型 听盖≌湍纾考慮到 PHP 具有動態(tài)類型的性質(zhì)裂七,此功能對于許多開發(fā)人員將非常有用。

class Foo

{

? ? public function test(): static

? ? {

? ? ? ? return new static();

? ? }

}

新增?mixed?類型?rfc

有人可能將其稱為必要的邪惡:mixed?類型讓許多人感覺十分混亂仓坞。然而背零,有一個很好的論據(jù)支持去實(shí)現(xiàn)它:缺少類型在 PHP 中會導(dǎo)致很多情況:

函數(shù)不返回任何內(nèi)容或返回空值

我們需要多種類型的一種類型

我們需要的是 PHP 中不能進(jìn)行類型提示的類型

因?yàn)樯鲜鲈颍砑?mixed?類型是一件很棒的事兒无埃。mixed?本身代表下列類型中的任一類型:

array

bool

callable

int

float

null

object

resource

string

請注意捉兴,mixed 不僅僅可以用來作為返回類型,還可以用作參數(shù)和屬性類型录语。

另外,還需要注意禾乘,因?yàn)?mixed 類型已經(jīng)包括了 null澎埠,因此 mixed 類型不可為空。下面的代碼會觸發(fā)致命錯誤:

// 致命錯誤:混合類型不能為空始藕,null已經(jīng)是混合類型的一部分蒲稳。

function bar(): ?mixed {}

throw?表達(dá)式?rfc

該 RFC 將?throw?從一個語句更改為一個表達(dá)式,這使得可以在很多新地方拋出異常:

$triggerError = fn () => throw new MyError();

$foo = $bar['offset'] ?? throw new OffsetDoesNotExist('offset');

弱映射 rfc

基于在 PHP 7.4 中新增的 弱引用 RFC伍派,PHP 8 中新增了 WeakMaps(弱映射)的實(shí)現(xiàn)江耀。 WeakMaps(弱映射)在保持對一些對象的引用的同時,并不會組織這些對象被垃圾回收機(jī)制處理 诉植。

以 ORM 為例祥国,它們通常實(shí)現(xiàn)保存對實(shí)體類的引用的緩存,從而提高實(shí)體類之間關(guān)聯(lián)的性能晾腔。 只要緩存中存在對這些實(shí)體類的引用舌稀,那么這些類就無法被垃圾回收機(jī)制回收,盡管除了緩存中灼擂,已經(jīng)沒有別處再引用這些實(shí)體類壁查,它們依然不會被垃圾處理機(jī)制處理。

如果這個緩存層使用了弱引用和弱映射剔应,那么 PHP 將會在這些實(shí)體類沒有任何其他引用時睡腿,對其進(jìn)行垃圾回收。 尤其是對于 ORMs峻贮,它可以管理一個請求中的數(shù)百個 (如果不是數(shù)千個) 實(shí)體席怪;弱映射可以提供一種更好的、對資源更友好的方式來處理這些對象月洛。

下面是弱映射基本的例子何恶,摘抄自 RFC :

class Foo

{

? ? private WeakMap $cache;

? ? public function getSomethingWithCaching(object $obj): object

? ? {

? ? ? ? return $this->cache[$obj]

? ? ? ? ? ??= $this->computeSomethingExpensive($obj);

? ? }

}

允許對對象使用 ::class rfc

一個很小但是很有用的新特性:現(xiàn)在可以在對象上使用 :: class ,而不必在對象上使用 get_class() 嚼黔,它的工作方式跟 get_class() 相同细层。

$foo = new Foo();

var_dump($foo::class);

Non-capturing catches rfc

在 PHP 8 之前惜辑,無論何時你想要捕獲一個異常,你都需要先將其存儲到一個變量中疫赎,不管這個變量你是否會用到盛撑。通過 Non-capturing catches 你可以忽略變量,所以替換下面的代碼:

try {

? ? // Something goes wrong

} catch (MySpecialException $exception) {

? ? Log::error("Something went wrong");

}

你現(xiàn)在可以這么做:

try {

? ? // Something goes wrong

} catch (MySpecialException) {

? ? Log::error("Something went wrong");

}

請注意捧搞,必須始終指定類型抵卫,不允許將?catch?留空,如果你想要捕獲所有類型的異常和錯誤胎撇,需要使用?Throwable?作為捕獲類型介粘。

參數(shù)列表中的尾部逗號?rfc

當(dāng)調(diào)用函數(shù)時已經(jīng)支持尾部逗號,但是參數(shù)列表中仍然缺少尾隨逗號支持。現(xiàn)在 PHP8 中允許這樣做,這意味著您可以執(zhí)行以下操作:

public function(

? ? string $parameterA,

? ? int $parameterB,

? ? Foo $objectfoo,

) {

? ? // …

}

從接口創(chuàng)建 DateTime 對象

你已經(jīng)可以使用 DateTime::createFromImmutable($immutableDateTime) 從 DateTimeImmutable 對象創(chuàng)建一個 DateTime 對象近尚, 而另一種方法則更加取巧。通過添加 DateTime::createFromInterface() 和 DatetimeImmutable::createFromInterface() 現(xiàn)在有一種通用的方法可以將 DateTime 和 DatetimeImmutable 對象相互轉(zhuǎn)換慨亲。

DateTime::createFromInterface(DateTimeInterface $other);

DateTimeImmutable::createFromInterface(DateTimeInterface $other);

新增 Stringable 接口 rfc

Stringable 接口可用于鍵入提示任何字符串或?qū)崿F(xiàn)__ toString() 的內(nèi)容。此外宝鼓,每當(dāng)一個類實(shí)現(xiàn)__ toString() 時刑棵,它就會自動實(shí)現(xiàn)后臺接口,而無需手動實(shí)現(xiàn)愚铡。

class Foo

{

? ? public function __toString(): string

? ? {

? ? ? ? return 'foo';

? ? }

}

function bar(Stringable $stringable) { /* … */ }

bar(new Foo());

bar('abc');

新增?str_contains()?函數(shù)?rfc

有些人可能會說這是早該發(fā)生的蛉签,但我們最終不必再依賴 strpos 來知道一個字符串是否包含另一個字符串。

無需這樣做:

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

你可以這樣做:

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

新增?str_starts_with()?和?str_ends_with()?函數(shù)?rfc

這是另外兩個早該出現(xiàn)的函數(shù)沥寥,現(xiàn)在已在核心函數(shù)中添加了這兩個函數(shù)正蛙。

str_starts_with('haystack', 'hay'); // true

str_ends_with('haystack', 'stack'); // true

新增?fdiv()?函數(shù)?pr

新的?fdiv()?函數(shù)的作用類似于?fmod()?和?intdiv()?函數(shù),它們可以除以 0营曼。視情況而定乒验,將得到?INF,-INF?或?NAN蒂阱。

新增?get_debug_type()?函數(shù)?rfc

get_debug_type()?返回變量的類型锻全,聽起來好像跟?gettype()?的作用一樣啊录煤?get_debug_type()?可以為數(shù)組鳄厌,字符串,匿名類和對象返回更有用的輸出信息妈踊。

例如了嚎,在類?\ Foo \ Bar?上調(diào)用?gettype()?將返回?object,而使用?get_debug_type()?將返回類名。

如下表:

可以在 RFC 中找到?get_debug_type()?和?gettype()?之間的差異的完整列表歪泳。

新增?get_resource_id()?函數(shù)?pr

資源是 PHP 中的特殊變量萝勤,指的是外部資源。一個示例是 MySQL 連接呐伞,另一個是文件句柄敌卓。

這些資源中的每一個都分配有一個 ID,然而在這之前伶氢,如果想獲取某資源的 ID趟径,唯一方法是將資源轉(zhuǎn)換為?int:

$resourceId = (int) $resource;

PHP 8 添加了?get_resource_id()?函數(shù),使此操作更加明顯且類型安全:

$resourceId = get_resource_id($resource);

Traits 改進(jìn)中的抽象方法?rfc

Traits 可以指定必須由使用它們的類所實(shí)現(xiàn)的抽象方法癣防。需要注意的是: 在 PHP 8 之前蜗巧,尚未驗(yàn)證這些方法已經(jīng)實(shí)現(xiàn)的標(biāo)識。以下內(nèi)容有效:

trait Test {

? ? abstract public function test(int $input): int;

}

class UsesTrait

{

? ? use Test;

? ? public function test($input)

? ? {

? ? ? ? return $input;

? ? }

}

當(dāng)使用 Traits 并實(shí)現(xiàn)其抽象方法時蕾盯,PHP 8 將執(zhí)行適當(dāng)?shù)姆椒ㄟM(jìn)行標(biāo)識驗(yàn)證抽象方法是否確實(shí)被實(shí)現(xiàn)惧蛹。這意味著您需要編寫以下代碼:

class UsesTrait

{

? ? use Test;

? ? public function test(int $input): int

? ? {

? ? ? ? return $input;

? ? }

}

token_get_all()?rfc?的對象實(shí)現(xiàn)

token_get_all() 函數(shù)返回一個值數(shù)組,該 RFC 使用 PhpToken :: getAll() 方法新增了 PhpToken 類刑枝。此實(shí)現(xiàn)適用于對象而不是普通值。它消耗更少的內(nèi)存迅腔,并且更易于閱讀装畅。

可變語法調(diào)整?rfc

在 RFC 中:“統(tǒng)一變量語法 RFC 解決了 PHP 變量語法中的許多不一致之處。該 RFC 旨在解決一小部分被忽略的情況沧烈÷有郑”

內(nèi)部函數(shù)的類型注解?externals

許多人?投入?了為所有內(nèi)部函數(shù)添加適當(dāng)?shù)念愋妥⑨尩墓ぷ鳌_@是一個長期存在的問題锌雀,最終可以通過以前版本中對 PHP 所做的所有更改來解決蚂夕。這意味著內(nèi)部函數(shù)和方法將在反射中具有完整的類型信息。

重大變化

如前所述:這是一個重大更新腋逆,因此會有重大變化婿牍。最好的辦法是查看?升級?文檔中所列的重大變化的完整列表。

許多這些突破性的更改在以前的 7.* 版本中已被棄用惩歉,因此如果你多年來一直保持 PHP 在最新狀態(tài)等脂,升級到 PHP 8 應(yīng)該沒那么難。

一致的類型錯誤?rfc

之前版本在出現(xiàn)類型錯誤時撑蚌,PHP 中的用戶定義函數(shù)已經(jīng)會拋出?TypeErrors上遥,但是內(nèi)部函數(shù)不會這么做,而是發(fā)出警告并返回?null争涌。從 PHP 8 開始粉楚,內(nèi)部函數(shù)的行為已變得和用戶定義函數(shù)一致。

重新分類的引擎警告?rfc

許多以前僅觸發(fā)警告或通知的錯誤已轉(zhuǎn)換為適當(dāng)?shù)腻e誤。以下警告已更改模软。

變量未定義:Error 異常代替通知

數(shù)組索引未定義:警告代替通知

除以零:DivisionByZeroError 異常代替警告

嘗試添加 / 移除非對象的屬性 '% s' :Error 異常代替警告

嘗試修改非對象的屬性 '% s' :Error 異常代替警告

嘗試分配非對象的屬性 '% s' :Error 異常代替警告

從空值創(chuàng)建默認(rèn)對象:Error 異常代替警告

嘗試獲取非對象的屬性 '% s' :警告代替通知

未定義的屬性:% s::$% s:警告代替通知

無法添加元素到數(shù)組伟骨,因?yàn)橄乱粋€元素已被占用:Error 異常代替警告

無法在非數(shù)組變量中銷毀偏移量:Error 異常代替警告

無法將標(biāo)量值用作數(shù)組:Error 異常代替警告

只有數(shù)組和 Traversables 可以被解包:TypeError 異常代替警告

為 foreach () 提供了無效的參數(shù):TypeError 異常代替警告

偏移量類型非法:TypeError 異常代替警告

isset 或 empty 中的偏移量類型非法:TypeError 異常代替警告

unset 中的偏移量類型非法:TypeError 異常代替警告

數(shù)組到字符串的轉(zhuǎn)換:警告代替通知

資源 ID#% d 用作偏移量,轉(zhuǎn)換為整數(shù) (% d):警告代替通知

發(fā)生字符串偏移量轉(zhuǎn)換:警告代替通知

未初始化的字符串偏移量:% d:警告代替通知

無法將空字符串分配給字符串偏移量:Error 異常代替警告

提供的資源不是有效的流資源:TypeError 異常代替警告

@ 運(yùn)算符不再使致命錯誤不提醒

此更改可能會使 PHP 8 之前的版本被 @ 隱藏的錯誤再次顯示出來撵摆。請確保在生產(chǎn)服務(wù)器上設(shè)置了 display_errors=Off 底靠!

默認(rèn)錯誤報(bào)告級別

現(xiàn)在的默認(rèn)錯誤報(bào)告級別是 E_ALL 而不是之前的除 E_NOTICE 和 E_DEPRECATED 的所有內(nèi)容。這意味著可能會彈出許多錯誤特铝,這些錯誤以前曾被忽略暑中,盡管在 PHP 8 之前的版本中可能已經(jīng)存在。

默認(rèn) PDO 錯誤模式?rfc

根據(jù) RFC:當(dāng)前 PDO 的默認(rèn)錯誤模式為靜默鲫剿。這意味著當(dāng)出現(xiàn) SQL 錯誤時鳄逾,除非開發(fā)人員實(shí)現(xiàn)了自己的顯式錯誤處

理,否則不會發(fā)出任何錯誤或警告灵莲,也不會引發(fā)任何異常雕凹。

此 RFC 將在 PHP 8 中將默認(rèn) PDO 錯誤模式 改為?PDO::ERRMODE_EXCEPTION?。

串聯(lián)優(yōu)先級?rfc

在 PHP 7.4 中已廢棄的同時政冻,此變更開始生效枚抵。如果你像這樣子書寫:

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

PHP 以前會如是理解:

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

PHP 8 將這么做故理解為此:

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

更嚴(yán)格的算術(shù)和位運(yùn)算類型檢查?rfc

PHP 8 以前,算術(shù)或位運(yùn)算符用于數(shù)組明场、資源或?qū)ο笫强山邮艿摹汽摹,F(xiàn)在不再可接受,并會拋出一個?類型錯誤?:

[] % [42];

$object + 4;

反射方法簽名變更

反射類的 3 個方法簽名已變更:

ReflectionClass::newInstance($args);

ReflectionFunction::invoke($args);

ReflectionMethod::invoke($object, $args);

現(xiàn)在已變成:

ReflectionClass::newInstance(...$args);

ReflectionFunction::invoke(...$args);

ReflectionMethod::invoke($object, ...$args);

升級指南指定苦锨,如果要擴(kuò)展這些類逼泣,并且仍想同時支持 PHP 7 和 PHP 8,則允許以下簽名:

ReflectionClass::newInstance($arg = null, ...$args);

ReflectionFunction::invoke($arg = null, ...$args);

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

幾個棄用

在 PHP 7. * 的開發(fā)期間舟舒,添加了幾個棄用版本拉庶,這些棄用已于 PHP 8 最終確定。

PHP 7.2?中的棄用

PHP 7.3?中的棄用

PHP 7.4?中的棄用


更多PHP內(nèi)容請?jiān)L問:

騰訊T3-T4標(biāo)準(zhǔn)精品PHP架構(gòu)師教程目錄大全秃励,只要你看完保證薪資上升一個臺階(持續(xù)更新)

以上內(nèi)容希望幫助到大家氏仗,很多PHPer在進(jìn)階的時候總會遇到一些問題和瓶頸,業(yè)務(wù)代碼寫多了沒有方向感夺鲜,不知道該從那里入手去提升廓鞠,對此我整理了一些資料,包括但不限于:分布式架構(gòu)谣旁、高可擴(kuò)展床佳、高性能、高并發(fā)榄审、服務(wù)器性能調(diào)優(yōu)砌们、TP6,laravel,YII2浪感,Redis昔头,Swoole、Swoft影兽、Kafka揭斧、Mysql優(yōu)化、shell腳本峻堰、Docker讹开、微服務(wù)、Nginx等多個知識點(diǎn)高級進(jìn)階干貨需要的可以免費(fèi)分享給大家捐名,需要的可以加入我的官方群點(diǎn)擊此處旦万。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市镶蹋,隨后出現(xiàn)的幾起案子成艘,更是在濱河造成了極大的恐慌,老刑警劉巖贺归,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件淆两,死亡現(xiàn)場離奇詭異,居然都是意外死亡拂酣,警方通過查閱死者的電腦和手機(jī)秋冰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來踱葛,“玉大人,你說我怎么就攤上這事光坝∈蹋” “怎么了?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵盯另,是天一觀的道長性含。 經(jīng)常有香客問我,道長鸳惯,這世上最難降的妖魔是什么商蕴? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮芝发,結(jié)果婚禮上绪商,老公的妹妹穿的比我還像新娘。我一直安慰自己辅鲸,他們只是感情好格郁,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般例书。 火紅的嫁衣襯著肌膚如雪锣尉。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天决采,我揣著相機(jī)與錄音自沧,去河邊找鬼。 笑死树瞭,一個胖子當(dāng)著我的面吹牛拇厢,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播移迫,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼旺嬉,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了厨埋?” 一聲冷哼從身側(cè)響起邪媳,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎荡陷,沒想到半個月后雨效,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡废赞,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年徽龟,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片唉地。...
    茶點(diǎn)故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡据悔,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出耘沼,到底是詐尸還是另有隱情极颓,我是刑警寧澤,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布群嗤,位于F島的核電站菠隆,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏狂秘。R本人自食惡果不足惜骇径,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望者春。 院中可真熱鬧破衔,春花似錦、人聲如沸钱烟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至传惠,卻和暖如春迄沫,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背卦方。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工羊瘩, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人盼砍。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓尘吗,卻偏偏與公主長得像,于是被迫代替她去往敵國和親浇坐。 傳聞我的和親對象是個殘疾皇子睬捶,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評論 2 348