>  기사  >  백엔드 개발  >  예제를 통해 PHP의 제네릭에 대해 자세히 알아보세요.

예제를 통해 PHP의 제네릭에 대해 자세히 알아보세요.

青灯夜游
青灯夜游앞으로
2022-04-12 11:12:405415검색

이 기사는 PHP의 제네릭에 대한 심층적인 이해를 제공하고 두 가지 일반적인 예를 소개합니다.

예제를 통해 PHP의 제네릭에 대해 자세히 알아보세요.

Deep into Generics

저는 이전 게시물에서 매우 지루한 제네릭 예제를 보여드렸고 이번 게시물에서는 더 잘하겠습니다.

$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

그럼 두 가지 예를 더 살펴보겠습니다.

예제를 통해 PHP의 제네릭에 대해 자세히 알아보세요.

이것 "app"이라는 함수입니다. Laravel과 같은 프레임워크를 사용하는 경우 익숙하게 보일 수 있습니다. 이 함수는 클래스 이름을 사용하고 종속성 컨테이너를 사용하여 해당 클래스의 인스턴스를 확인합니다.

/** @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와 기타 정적 분석기가 이 함수에 "UserRepository"라는 클래스 이름을 지정하면 UserRepository의 인스턴스만 반환하고 다른 것은 반환하지 않는다는 점을 이해하면 좋을 것입니다.

rrreee

좋아, 일반 Kata를 사용하면 이를 수행할 수 있습니다. . 🎜🎜 저는 지금이 제가 간직하고 있는 비밀을 언급하기에 좋은 시기라고 생각했습니다. 다음과 같이, 제 이전 게시물에서 제네릭은 PHP에 존재하지 않는다고 언급했는데, 그것은 전적으로 사실이 아닙니다. 모든 정적 분석기(코드를 실행하지 않고 읽는 도구, IDE와 같은 도구)에서는 문서 블록 주석을 제네릭에 사용할 수 있습니다. 🎜rrreee🎜 물론: 가장 완벽한 구문은 아니지만 모든 정적 분석기는 간단한 프로토콜에 의존합니다. 즉, 공식적인 표준 구문은 없습니다. 작동합니다. PHP 세계에서 가장 큰 세 가지 정적 분석기인 PhpStorm, Psalm 및 PhpStan은 모두 이 구문을 어느 정도 이해합니다. 🎜🎜PhpStorm과 같은 IDE는 이를 사용하여 프로그래머가 코드를 작성할 때 피드백을 제공하고, Psalm 및 PhpStan과 같은 도구는 이를 사용하여 주로 유형 정의를 기반으로 코드베이스를 대량 분석하고 잠재적인 버그를 감지합니다. 🎜🎜실제로 우리는 도구가 더 이상 어둠 속에서 실행되지 않도록 이 기능을 구축할 수 있습니다. 물론, PHP 자체는 반환 유형이 올바른지 보장할 수 없습니다. 왜냐하면 PHP는 런타임에 함수의 유형을 확인하지 않기 때문입니다. 그러나 정적 분석기가 정확하다고 신뢰할 수 있다면 이를 실행할 때 이 단락에는 코드가 거의 없습니다. - 중단될 가능성이 없습니다. 🎜🎜이것은 정적 분석의 놀라운 힘입니다. 코드를 실행하지 않고도 대부분이 예상대로 작동할 것이라고 확신할 수 있습니다. 이 모든 것은 제네릭을 포함한 유형 덕분에 가능합니다. 🎜🎜더 복잡한 예를 살펴보겠습니다. 🎜rrreee🎜여기에는 속성을 "쿼리"하고 즉시 인스턴스화할 수 있는 클래스가 있습니다. 리플렉션 API가 매우 장황하다는 사실을 알기 전에 속성을 사용한 적이 있는 경우 이 도우미 클래스가 매우 유용하다고 생각합니다. 🎜🎜 filter 메소드를 사용할 때 속성의 클래스 이름을 지정한 다음 newInstance 메소드를 호출하여 결과가 우리의 인스턴스가 될 것임을 알 수 있습니다. 필터 클래스. 다시 말하지만, 우리 IDE가 우리가 말하는 내용을 이해한다면 좋을 것입니다. 🎜🎜 짐작하셨겠지만, 제네릭을 사용하면 다음과 같은 작업이 가능합니다. 🎜rrreee🎜 간단한 유형 정보의 힘을 느끼시기 바랍니다. 몇 년 전에는 이러한 통찰력을 작동시키기 위해 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으로 문의하시기 바랍니다. 삭제