溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

不能在PHP中使用泛型的原因是什么

發(fā)布時(shí)間:2022-03-29 10:39:08 來(lái)源:億速云 閱讀:170 作者:小新 欄目:編程語(yǔ)言

小編給大家分享一下不能在PHP中使用泛型的原因是什么,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

為什么我們不能在 PHP 中使用泛型

我們將深入探討泛型和 PHP 背后的情況。理解為什么泛型在 PHP 中還不被支持作為一等公民,這非常有趣,并且非常重要。

不能在PHP中使用泛型的原因是什么

讓我們看看吧。

PHP 中沒有泛型。這就是去年的 Nikita 的結(jié)論。這根本不可行。

為了理解 Nikita 為什么這么說(shuō),我們需要看看如何實(shí)現(xiàn)泛型。一般來(lái)說(shuō),有三種可能的方法;支持泛型的編程語(yǔ)言大多使用這三種方法之一。

第一個(gè)稱為 單態(tài)泛型。 讓我們回到這個(gè)系列的第一篇文章,在這篇文章中我展示了這個(gè)集合示例:

class StringCollection extends Collection
{
    public function offsetGet(mixed $key): string 
    { /* … */ }
}
class UserCollection extends Collection
{
    public function offsetGet(mixed $key): User 
    { /* … */ }
}

我解釋了我們可以為需要的集合的每種類型,手動(dòng)創(chuàng)建集合類的實(shí)現(xiàn)。 工作量將是巨大的,會(huì)有很多代碼,但是它會(huì)起作用。

單態(tài)泛型正是這樣做的,但在幕后自動(dòng)實(shí)現(xiàn)。 在運(yùn)行時(shí),PHP 不會(huì)知道泛型 Collection 類,而是知道兩個(gè)或多個(gè)特定實(shí)現(xiàn):

$users = new Collection<User>();
// Collection_User
$slugs = new Collection<string>();
// Collection_string

單態(tài)泛型是一種完全有效的方法。例如,Rust 就使用它們。 其一個(gè)優(yōu)點(diǎn)是有一系列的性能提升,因?yàn)樵谶\(yùn)行時(shí)沒有更多的泛型類型檢查,所以在運(yùn)行代碼之前,這些檢查都是分開的。

但是這立刻讓我們想到了 PHP 中單態(tài)泛型的問(wèn)題。 PHP 沒有像 Rust 那樣將一個(gè)泛型類分成幾個(gè)具體實(shí)現(xiàn)的顯式編譯步驟;最重要的是:?jiǎn)螒B(tài)泛型確實(shí)需要相當(dāng)多的內(nèi)存,因?yàn)槟阍谥谱魍粋€(gè)類的多個(gè)副本,但有一些差異。 對(duì)于已編譯的 Rust 二進(jìn)制文件來(lái)說(shuō),這可能不是一個(gè)大問(wèn)題,但對(duì)于從中心點(diǎn)(服務(wù)器)運(yùn)行的 PHP 代碼來(lái)說(shuō),這是一個(gè)嚴(yán)重的問(wèn)題;可能每秒處理數(shù)百或數(shù)千個(gè)請(qǐng)求。

下一個(gè)選項(xiàng)是具體化泛型。這是一個(gè)實(shí)現(xiàn),其中泛型類保持原樣,類型信息在運(yùn)行時(shí)動(dòng)態(tài)評(píng)估類型信息。C# 和 Kotlin 實(shí)現(xiàn)了泛型,它是最接近 PHP 當(dāng)前類型系統(tǒng)的,因?yàn)?PHP 在運(yùn)行時(shí)執(zhí)行所有類型檢查。這里的問(wèn)題是需要大量的核心代碼重構(gòu)才能使具體化泛型發(fā)揮作用,你可以想象,隨著我們?cè)谶\(yùn)行時(shí)進(jìn)行越來(lái)越多的類型檢查,一些性能開銷會(huì)逐漸增加。

這將我們帶到最后一個(gè)選項(xiàng):在運(yùn)行時(shí)完全忽略泛型。就像它們不在那里一樣;畢竟,例如集合類的泛型實(shí)現(xiàn)無(wú)論如何都可以處理所有類型的輸入。

因此,如果我們?cè)谶\(yùn)行時(shí)忽略所有泛型類型檢查,則不會(huì)有任何問(wèn)題。

好吧,沒有那么快。 在運(yùn)行時(shí)忽略泛型類型 —— 順便說(shuō)一下,它被稱為類型擦除,Java 和 Python 會(huì)這樣做 —— 這給 PHP 帶來(lái)了一些問(wèn)題。

舉一個(gè)例子:PHP 不僅使用類型進(jìn)行驗(yàn)證,它還使用類型信息將值從一種類型動(dòng)態(tài)轉(zhuǎn)換為另一種類型 —— 這就是我在本系列的第一篇文章中提到的類型雜耍:

function add(int $a, int $b): int 
{
    return $a + $b;
}
add('1', '2') // 3;

如果 PHP 忽略了這個(gè)「字符串」集合的泛型類型,并且我們不小心向它添加了一個(gè)整數(shù),那么如果泛型類型被刪除,它將無(wú)法警告我們:

$slugs = new Collection<string>();
$slugs[] = 1; // 1 不會(huì)被轉(zhuǎn)換為 '1'

類型擦除的第二個(gè)也是更重要的問(wèn)題 —— 也許你現(xiàn)在已經(jīng)在屏幕上大喊大叫了 —— 是類型消失了。如果泛型類型在運(yùn)行時(shí)被刪除,我們?yōu)槭裁匆砑铀鼈儯?/p>

這在 Java 和 Pyton 中是有意義的,因?yàn)樵谑褂渺o態(tài)分析器運(yùn)行代碼之前會(huì)檢查所有類型定義。 例如,Java 在編譯代碼時(shí)會(huì)運(yùn)行一個(gè)內(nèi)置的靜態(tài)分析器; PHP 根本不會(huì)做的事情:沒有編譯步驟,當(dāng)然也沒有內(nèi)置的靜態(tài)類型檢查器。

另一方面…… 類型檢查的所有優(yōu)點(diǎn),我們?cè)谥暗奈恼轮杏懻撨^(guò)的那些;它們不是來(lái)自 PHP 的內(nèi)置運(yùn)行時(shí)類型檢查器。當(dāng) PHP 的類型檢查器告訴我們有問(wèn)題時(shí),我們已經(jīng)在運(yùn)行代碼了。一個(gè)類型錯(cuò)誤本質(zhì)上是讓我們的程序崩潰。

相反,類型檢查的大部分附加值來(lái)自不需要我們運(yùn)行代碼的靜態(tài)分析器。只要程序員提供足夠的類型信息,他們就能很好地確保不會(huì)出現(xiàn)運(yùn)行時(shí)類型錯(cuò)誤。這并不意味著你的代碼中不能有任何錯(cuò)誤,但可以編寫完全靜態(tài)檢查并且在運(yùn)行時(shí)不會(huì)產(chǎn)生任何類型錯(cuò)誤的 PHP 代碼。最重要的是:我們?cè)诰帉懘a時(shí)獲得了所有靜態(tài)洞察;這是任何類型系統(tǒng)中最有價(jià)值的部分,與運(yùn)行時(shí)類型檢查無(wú)關(guān)。

那么我們真的需要運(yùn)行時(shí)類型檢查嗎?因?yàn)檫@是目前無(wú)法在 PHP 中添加泛型的主要原因:對(duì)于 PHP 來(lái)說(shuō),在運(yùn)行時(shí)驗(yàn)證泛型類型太復(fù)雜或太耗費(fèi)資源。

以上是“不能在PHP中使用泛型的原因是什么”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

php
AI