Heim > Backend-Entwicklung > PHP-Tutorial > PHP-Generika in Laravel 11

PHP-Generika in Laravel 11

DDD
Freigeben: 2024-10-23 08:08:29
Original
599 Leute haben es durchsucht

PHP Generics in Laravel 11

Wenn Sie Webanwendungen mit Laravel erstellen und PHPStan für die statische Codeanalyse verwenden, werden beim Upgrade auf Laravel 11.x.

Bei einer Neuinstallation von Laravel mit

PHPStan wird beim ersten Ausführen von ./vendor/bin/phpstan der folgende Fehler ausgegeben:

 ------ -----------------------------------------------------------------------------------
  Line   app\Models\User.php
 ------ -----------------------------------------------------------------------------------
  13     Class App\Models\User uses generic trait
         Illuminate\Database\Eloquent\Factories\HasFactory but does not specify its types:
         TFactory
 ------ -----------------------------------------------------------------------------------
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Was wurde also geändert? In Laravel 11 verfügt das HasFactory-Merkmal jetzt über ein

PHPDoc mit dem @template-Tag, das eines der reservierten generischen Tags ist. Wie Sie vielleicht schon vermutet haben, werden in vielen Teilen des Frameworks Generika verwendet.

/**
 * @template TFactory of \Illuminate\Database\Eloquent\Factories\Factory
 */
trait HasFactory
{
    ...
}
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Obwohl dies nicht empfohlen wird, kann diese Fehlerkategorie ignoriert werden, indem Sie einfach die folgenden Codezeilen zu Ihrer phpstan.neon-Datei hinzufügen:


parameters:
    ignoreErrors:
        -
            identifier: missingType.generics
Nach dem Login kopieren
Nach dem Login kopieren
Aber Generika sind nicht so schwer zu verstehen, also fangen wir an!

Was sind Generika?

Generika beziehen sich in der Programmierung auf eine Funktion, die es Ihnen ermöglicht, Code zu schreiben, der mit mehreren Datentypen arbeiten kann. Anstatt für jeden Datentyp separaten Code zu schreiben, können Sie einen einzelnen, generischen Codeabschnitt schreiben, der mit verschiedenen Typen arbeiten kann und dabei die Typsicherheit aufrechterhält, im Gegensatz zur Verwendung allgemeiner Typen wie gemischt oder Objekt.

Nehmen Sie die IlluminateDatabaseConcernsBuildsQueries::first-Methode aus

Laravel 10, sie kann eine Instanz von Model, ein allgemeines Objekt, eine Instanz der Klasse, die es verwendet, wie IlluminateDatabaseEloquentBuilder oder null, zurückgeben.

/**
 * Execute the query and get the first result.
 *
 * @param  array|string  $columns
 * @return \Illuminate\Database\Eloquent\Model|object|static|null
 */
public function first($columns = ['*'])
{
    return $this->take(1)->get($columns)->first();
}
Nach dem Login kopieren
Nach dem Login kopieren
Generika-Syntax

Generika werden in PHP als erstklassiger Bürger nicht unterstützt. Um sie zu haben, verwenden wir die

PHPDocs-Tags @template, @template-covariant, @template-contravariant, @extends, @implements und @use.

Die Regeln der generischen Typen werden mithilfe von

Typparametern definiert. In PHPDocs kommentieren wir sie mit dem @template-Tag. Der Name des Typparameters kann beliebig sein, solange Sie keinen vorhandenen Klassennamen verwenden. Sie können mithilfe des Schlüsselworts of auch mit einer Obergrenze einschränken, welche Typen anstelle des Typparameters verwendet werden können. Dies wird als begrenzter Typparameter bezeichnet

<?php

namespace Illuminate\Database\Eloquent;

/**
 * @template TModel of \Illuminate\Database\Eloquent\Model
 *
 */
class Builder implements BuilderContract
{
}
Nach dem Login kopieren
Nach dem Login kopieren
Arten von PHP-Generika

Generische Funktion

Eine generische Funktion ist genau wie eine normale Funktion, verfügt jedoch über Typparameter. Dadurch kann die generische Methode allgemeiner genutzt werden.

Nehmen Sie die Methode IlluminateSupportValidatedInput::enum als Beispiel:

  • Es definiert einen Typparameter TEnum.

  • Der $enumClass-Parameter ist vom Pseudotyp „class-string“ und an den gleichen Typparameter TEnum gebunden.

  • Der Rückgabetyp kann auch entweder TEnum oder null sein.


 ------ -----------------------------------------------------------------------------------
  Line   app\Models\User.php
 ------ -----------------------------------------------------------------------------------
  13     Class App\Models\User uses generic trait
         Illuminate\Database\Eloquent\Factories\HasFactory but does not specify its types:
         TFactory
 ------ -----------------------------------------------------------------------------------
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Wenn Sie dann $request→validated()→enum(‘status‘, OrderStatus::class) aufrufen, weiß PHPStan, dass Sie ein OrderStatus-Objekt oder null erhalten!

Generische Klasse

Generische Klassen ermöglichen die Erstellung von Klassen, die mit jedem Datentyp arbeiten können und gleichzeitig die Typsicherheit gewährleisten. Sie ermöglichen die Definition einer Klasse mit einem Platzhalter für einen bestimmten Typ, der später bei der Instanziierung der Klasse ersetzt werden kann.

Ein gutes Beispiel aus dem Laravel-Quellcode wäre die IlluminateDatabaseEloquentBuilder-Klasse:

/**
 * @template TFactory of \Illuminate\Database\Eloquent\Factories\Factory
 */
trait HasFactory
{
    ...
}
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Ein Typparameter TModel ist definiert und an jede Unterklasse von IlluminateDatabaseEloquentModel gebunden. Derselbe Typparameter wird als Rückgabetyp der Methode make.

verwendet

Ein weiteres Beispiel wäre, wenn wir ein Auftragsmodell hätten, das einen lokalen Bereich zum Filtern von Aufträgen basierend auf ihrem Status hat. Die Scope-Methode sollte den TModel-Typ
angeben

parameters:
    ignoreErrors:
        -
            identifier: missingType.generics
Nach dem Login kopieren
Nach dem Login kopieren

ℹ️ Info: Alle Eloquent Beziehungsklassen im Namespace IlluminateDatabaseEloquentRelations wie BelongsTo und HasOne sind jetzt generisch.

Generische Schnittstelle

Generische Schnittstellen unterscheiden sich nicht so sehr. Das IlluminateContractsSupportArrayable ist ein Beispiel für eine generische Schnittstelle

/**
 * Execute the query and get the first result.
 *
 * @param  array|string  $columns
 * @return \Illuminate\Database\Eloquent\Model|object|static|null
 */
public function first($columns = ['*'])
{
    return $this->take(1)->get($columns)->first();
}
Nach dem Login kopieren
Nach dem Login kopieren

Die Schnittstelle definiert zwei Typparameter: TKey vom Typ Array-Key (kann int oder string sein) und TValue. Diese beiden Parameter werden verwendet, um den Rückgabetyp der toArray-Funktion zu definieren. Hier ist ein Beispiel:

<?php

namespace Illuminate\Database\Eloquent;

/**
 * @template TModel of \Illuminate\Database\Eloquent\Model
 *
 */
class Builder implements BuilderContract
{
}
Nach dem Login kopieren
Nach dem Login kopieren

Die Benutzerklasse implementiert die Arrayable-Schnittstelle und gibt den Tkey-Typ als int und den TValue als String an.

Generisches Merkmal

Wir sind im Fehler am Anfang dieses Beitrags auf das Merkmal IlluminateDatabaseEloquentFactoriesHasFactory gestoßen. Schauen wir uns das genauer an:

/**
 * @template TEnum
 *
 * @param string $key
 * @param class-string<TEnum> $enumClass
 * @return TEnum|null
 */
public function enum($key, $enumClass)
{
    if ($this->isNotFilled($key) ||
        ! enum_exists($enumClass) ||
        ! method_exists($enumClass, 'tryFrom')) {
        return null;
    }
    return $enumClass::tryFrom($this->input($key));
}
Nach dem Login kopieren

HasFactory definiert einen Typparameter TFactory, der an die Unterklassen von IlluminateDatabaseEloquentFactoriesFactory gebunden ist. Wie kann dieser Fehler behoben werden?

Der TFactory-Typ muss angegeben werden, wenn das Merkmal verwendet wird. Daher muss die Verwendungsanweisung des HasFactory-Merkmals mit PHPDocs @use:
annotiert werden

<?php

namespace Illuminate\Database\Eloquent;
/**
 * @template TModel of \Illuminate\Database\Eloquent\Model
 */
class Builder implements BuilderContract
{
    /**
     * @param  array  $attributes
     * @return TModel
     */
    public function make(array $attributes = [])
    {
        return $this->newModelInstance($attributes);
    }
}
Nach dem Login kopieren

Allgemeingültigkeit bewahren

Beim Erweitern einer Klasse, Implementieren einer Schnittstelle oder Verwenden eines Merkmals ist es möglich, die Generizität in der Unterklasse beizubehalten.

Die Wahrung der Generizität wird implementiert, indem die gleichen Typparameter über der untergeordneten Klasse definiert und an @extends, @implements und @use-Tags übergeben werden.

Wir werden das generische Merkmal IlluminateDatabaseConcernsBuildsQueries als Beispiel verwenden,

es definiert einen Typparameter TValue:

 ------ -----------------------------------------------------------------------------------
  Line   app\Models\User.php
 ------ -----------------------------------------------------------------------------------
  13     Class App\Models\User uses generic trait
         Illuminate\Database\Eloquent\Factories\HasFactory but does not specify its types:
         TFactory
 ------ -----------------------------------------------------------------------------------
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Die IlluminateDatabaseEloquentBuilder-Klasse verwendet dieses Merkmal, behält jedoch ihre Generischkeit bei, indem der TModel-Parametertyp an sie übergeben wird. Es bleibt nun dem Client-Code überlassen, den Typ von TModel und folglich TValue im BuildsQueries-Merkmal anzugeben.

/**
 * @template TFactory of \Illuminate\Database\Eloquent\Factories\Factory
 */
trait HasFactory
{
    ...
}
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Letzte Gedanken

Zusammenfassend lässt sich sagen, dass PHP Generics zwar nicht nativ in der gleichen Weise wie einige andere Programmiersprachen unterstützt, die Einführung erweiterter Typhinweise und Tools wie PHPStan Entwicklern jedoch die Implementierung generics-ähnlicher Funktionen in ihren Code ermöglicht . Durch die Nutzung von PHPDocs, parametrisierten Klassen und Schnittstellen können Sie flexiblere und typsicherere Anwendungen erstellen, die die Wiederverwendbarkeit und Wartbarkeit des Codes fördern. Während sich PHP weiterentwickelt, wird der wachsende Fokus der Community auf Typsicherheit und statische Analyse wahrscheinlich zu robusteren Lösungen für die Implementierung von Generika führen. Die Übernahme dieser Praktiken verbessert nicht nur Ihre Programmierfähigkeiten, sondern trägt auch zur Entwicklung hochwertiger Software bei, die den Test der Zeit besteht.

Das obige ist der detaillierte Inhalt vonPHP-Generika in Laravel 11. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Quelle:dev.to
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage