首頁  >  文章  >  後端開發  >  透過範例來深入了解PHP中的泛型

透過範例來深入了解PHP中的泛型

青灯夜游
青灯夜游轉載
2022-04-12 11:12:405372瀏覽

這篇文章帶大家深入了解PHP中的泛型,介紹兩個泛型範例,希望對大家有幫助!

 透過範例來深入了解PHP中的泛型

深入泛型

#我在上一篇 中展示了一個非常無聊的泛型示例,我們將在這個中做得更好。

$users = new Collection<User>();

$slugs = new Collection<string>();

集合 它們可能是解釋泛型的最簡單方法,但它們也是每個人在討論泛型時都會談論的範例。人們通常認為「泛型」和「具有類型的集合」是一回事。絕對不是這樣。

所以讓我們再看兩個例子。

透過範例來深入了解PHP中的泛型

這是一個名為「app」的函數-如果你使用像Laravel 這樣的框架,它可能看起來很熟悉:這個函數接受一個類別名,並且使用依賴容器解析該類別的一個實例:

function app(string $className): mixed
{
    return Container::get($className);
}

現在,你不需要知道容器是如何運作的,重要的是這個函數會給你一個你要求的類別的實例。

所以,基本上,它是一個通用函數;一個回傳類型取決於你給它的類別名稱。如果我們的IDE 和其他靜態分析器也明白,如果我給這個函數提供類別名稱“UserRepository”,我希望回傳一個UserRepository 的實例,而不是別的,那就太酷了:

function app(string $className): mixed
{ /* … */ }

app(UserRepository::class); // ?

好吧,泛型允許我們這樣做。

我想現在是提一下我一直保守秘密的好時機,就像: 我在 上一篇 中提到 PHP 中不存在泛型;好吧,這並不完全正確。那裡的所有靜態分析器——無需運行即可讀取程式碼的工具,像你的IDE 之類的工具——他們允許將doc 塊註釋用於泛型:

/**
 * @template Type
 * @param class-string<Type> $className
 * @return Type
 */
function app(string $className): mixed
{ /* … */ }

誠然:這不是最完美的語法,所有靜態分析器都依賴於一個簡單的協議,即這是沒有官方規範語法; 但是:它有效。 PHP 世界中最大的三個靜態分析器:PhpStorm、Psalm 和 PhpStan,都在某種程度上理解這種語法。

像PhpStorm 這樣的IDE 使用它,以便在程式設計師編寫程式碼時向他們提供回饋,而像Psalm 和PhpStan 這樣的工具使用它,來批次分析你的程式碼庫並偵測潛在的bug,主要基於類型定義。

所以實際上,我們可以建立這個 app 函數,使我們的工具不再在黑暗中運作。當然,PHP 本身並不能保證返回類型是正確的,因為PHP 不會在運行時對該函數進行類型檢查; 但是,如果我們可以相信我們的靜態分析器是正確的,那麼在運行它時,這段程式碼就很少——甚至沒有機會被中斷。

這就是靜態分析令人難以置信的力量:實際上,我們可以確定,無需運行我們的程式碼; 其中大部分將按預期工作。所有這一切都歸功於類型——包括泛型。

讓我們來看一個更複雜的範例:

Attributes::in(MyController::class)
    ->filter(RouteAttribute::class)
    ->newInstance()
    ->

在這裡,我們有一個可以「查詢」屬性並即時實例化它們的類別。如果你在知道它們的反射 API 相當冗長之前使用過屬性,那麼我發現這種輔助類別非常有用。

當我們使用filter 方法時,我們給它一個屬性的類別名稱; 然後呼叫newInstance 方法,我們知道結果將是我們過濾類別的實例。再說一次:如果我們的 IDE 能理解我們在說什麼,那就太好了。

你猜對了:泛型允許我們這樣做:

/** @template AttributeType */
class Attributes
{
    /**
     * @template InputType
     * @param class-string<InputType> $className
     * @return self<InputType>
     */
    public function filter(string $className): self
    { /* … */ }

    /**
     * @return AttributeType 
     */   
    public function newInstance(): mixed
    { /* … */ }

    // …
}

我希望你開始看到簡單類型資訊的強大功能。幾年前,我需要一個 IDE 插件才能讓這些洞察力發揮作用,現在我只需要添加一些類型資訊。

不過,這個最新的範例不僅依賴泛型,還有另一個同樣重要的部分在運作。類型推斷:靜態分析器「猜測」—— 或可靠地確定 —— 無需使用者指定類型的能力。這就是那裡的類別字串註解正在發生的事情。我們的 IDE 能夠將我們提供給此函數的輸入識別為類別名,並將該類型推斷為泛型類型。

所以,一切都解決了,對吧:PHP中有泛型,所有主要的靜態分析器都知道如何使用它們。嗯…有幾個警告。

首先,沒有關於泛型應該是什麼樣子的官方規範,現在每個靜態分析器都可以使用自己的語法;目前,他們碰巧已經就其中一個達成了一致;但未來幾乎沒有保障。

其次:在我看來,文檔區塊是次優的。他們覺得自己在我們的程式碼庫中不那麼重要。當然,泛型註解只提供靜態洞察,沒有執行時間功能,但我們已經看到了靜態分析的強大功能,即使沒有執行時間類型檢查。我認為將類型資訊視為“文檔註釋”是不公平的,它沒有在我們的程式碼中傳達這些類型的重要性。這就是為什麼我們在PHP8中得到了屬性:屬性提供的所有功能,在docblock註解中都是可能的,但感覺還不夠好。泛型也是如此。

最後一點:如果沒有合適的規範,所有三種主要的靜態分析儀在其泛型實作之間都存在差異。 PhpStorm是目前最缺乏的一種。理想情況下,會有一個來自PHP內部的官方規範。但是官方現在沒有。

這些是我認為值得在更持久、更永續的解決方案上投入時間的主要原因。那為什麼PHP還沒有合適的泛型呢?為什麼我們依賴沒有明確規範的文檔區塊?

原文網址:https://stitcher.io/blog/generics-in-php-2

翻譯網址:https://learnku.com/php/t/ 66484

推薦:《PHP影片教學

以上是透過範例來深入了解PHP中的泛型的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:learnku.com。如有侵權,請聯絡admin@php.cn刪除