Generik PHP dalam Laravel 11

DDD
Lepaskan: 2024-10-23 08:08:29
asal
408 orang telah melayarinya

PHP Generics in Laravel 11

Jika anda seorang pembina aplikasi web dengan Laravel dan kebetulan menggunakan PHPStan untuk analisis kod statik, anda akan mula melihat ralat baharu apabila anda menaik taraf kepada Laravel 11.x.

Dalam pemasangan Laravel baharu dengan PHPStan, kali pertama menjalankan ./vendor/bin/phpstan ralat berikut akan dilemparkan:

 ------ -----------------------------------------------------------------------------------
  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
 ------ -----------------------------------------------------------------------------------
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Jadi apa yang diubah? Dalam Laravel 11, ciri HasFactory kini mempunyai PHPDoc dengan teg @template yang merupakan salah satu teg generik terpelihara. Seperti yang anda mungkin sudah meneka, generik sedang digunakan dalam banyak bahagian rangka kerja.

/**
 * @template TFactory of \Illuminate\Database\Eloquent\Factories\Factory
 */
trait HasFactory
{
    ...
}
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Walaupun tidak disyorkan, kategori ralat ini boleh diabaikan dengan hanya menambah baris kod ini pada fail phpstan.neon anda:

parameters:
    ignoreErrors:
        -
            identifier: missingType.generics
Salin selepas log masuk
Salin selepas log masuk

Tetapi, generik tidak begitu sukar untuk difahami jadi mari kita mulakan!

Apakah Generik?

Generik dalam pengaturcaraan merujuk kepada ciri yang membolehkan anda menulis kod yang boleh berfungsi dengan berbilang jenis data. Daripada menulis kod berasingan untuk setiap jenis data, anda boleh menulis sekeping kod generik tunggal yang boleh beroperasi pada pelbagai jenis sambil mengekalkan keselamatan jenis, tidak seperti menggunakan jenis umum seperti campuran atau objek.

Ambil kaedah IlluminateDatabaseConcernsBuildsQueries::first daripada Laravel 10, ia boleh mengembalikan contoh Model, objek umum, contoh kelas yang menggunakannya seperti IlluminateDatabaseEloquentBuilder atau null.

/**
 * 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();
}
Salin selepas log masuk
Salin selepas log masuk

Sintaks Generik

Generik tidak disokong dalam PHP sebagai warganegara kelas pertama, untuk mendapatkannya, kami menggunakan tag PHPDocs @template, @template-covariant, @template-contravariant, @extends, @implements dan @guna.

Peraturan jenis generik ditakrifkan menggunakan parameter jenis. Dalam PHPDocs kami menganotasinya dengan teg @template . Nama parameter jenis boleh menjadi apa sahaja, selagi anda tidak menggunakan nama kelas sedia ada. Anda juga boleh mengehadkan jenis yang boleh digunakan sebagai ganti parameter jenis dengan sempadan atas menggunakan kata kunci. Ini dipanggil parameter jenis terhad.

<?php

namespace Illuminate\Database\Eloquent;

/**
 * @template TModel of \Illuminate\Database\Eloquent\Model
 *
 */
class Builder implements BuilderContract
{
}
Salin selepas log masuk
Salin selepas log masuk

Jenis PHP Generik

Fungsi Generik

Fungsi generik adalah sama seperti fungsi biasa, namun, ia mempunyai parameter jenis. Ini membolehkan kaedah generik digunakan dengan cara yang lebih umum.

Ambil kaedah IlluminateSupportValidatedInput::enum sebagai contoh:

  • Ia mentakrifkan parameter jenis TEnum.

  • Parameter $enumClass adalah daripada rentetan kelas jenis pseudo dan dihadkan kepada parameter jenis yang sama TEnum.

  • Jenis pemulangan juga boleh sama ada TEnum atau null.

 ------ -----------------------------------------------------------------------------------
  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
 ------ -----------------------------------------------------------------------------------
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Jika anda kemudian memanggil $request→validated()→enum(‘status‘, OrderStatus::class), PHPStan akan mengetahui bahawa anda mendapat objek OrderStatus atau null!

Kelas Generik

Kelas generik membolehkan mencipta kelas yang boleh beroperasi pada sebarang jenis data sambil memastikan keselamatan jenis. Ia membolehkan kelas ditakrifkan dengan pemegang tempat untuk jenis tertentu, yang kemudiannya boleh digantikan apabila kelas itu dibuat seketika.

Contoh yang baik daripada Laravel kod sumber ialah kelas IlluminateDatabaseEloquentBuilder:

/**
 * @template TFactory of \Illuminate\Database\Eloquent\Factories\Factory
 */
trait HasFactory
{
    ...
}
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Parameter jenis TModel ditakrifkan dan dihadkan kepada mana-mana subkelas IlluminateDatabaseEloquentModel. Parameter jenis yang sama digunakan sebagai jenis pemulangan kaedah yang dibuat.

Contoh lain ialah jika kita mempunyai model Pesanan, yang mempunyai skop setempat untuk menapis pesanan berdasarkan statusnya. Kaedah skop harus menentukan jenis TModel

parameters:
    ignoreErrors:
        -
            identifier: missingType.generics
Salin selepas log masuk
Salin selepas log masuk

ℹ️ maklumat: Semua kelas perhubungan Fasih dalam ruang nama IlluminateDatabaseEloquentRelations seperti BelongsTo dan HasOne kini generik.

Antara Muka Generik

Antara muka generik tidak begitu berbeza. IlluminateContractsSupportArrayable ialah contoh antara muka generik

/**
 * 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();
}
Salin selepas log masuk
Salin selepas log masuk

Antara muka mentakrifkan dua jenis parameter: TKey jenis tatasusunan-kunci (ia boleh menjadi int atau rentetan) dan TValue. Kedua-dua parameter ini digunakan untuk menentukan jenis pemulangan fungsi toArray. Berikut ialah contoh:

<?php

namespace Illuminate\Database\Eloquent;

/**
 * @template TModel of \Illuminate\Database\Eloquent\Model
 *
 */
class Builder implements BuilderContract
{
}
Salin selepas log masuk
Salin selepas log masuk

Kelas pengguna melaksanakan antara muka Boleh Susun dan menentukan jenis Tkey sebagai int dan TValue sebagai rentetan.

Sifat Generik

Kami menemui sifat IlluminateDatabaseEloquentFactoriesHasFactory dalam ralat pada permulaan siaran ini. Mari lihat lebih dekat:

/**
 * @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));
}
Salin selepas log masuk

HasFactory mentakrifkan parameter jenis TFactory yang dihadkan kepada subkelas IlluminateDatabaseEloquentFactoriesFactory. Jadi bagaimanakah ralat itu boleh dibetulkan?

Jenis TFactory mesti dinyatakan apabila sifat sedang digunakan. Jadi, pernyataan penggunaan ciri HasFactory perlu dianotasi dengan PHPDocs @use:

<?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);
    }
}
Salin selepas log masuk

Memelihara Generik

Apabila melanjutkan kelas, melaksanakan antara muka atau menggunakan ciri adalah mungkin untuk mengekalkan generik dalam subkelas.

Memelihara generik dilaksanakan dengan mentakrifkan parameter jenis yang sama di atas kelas kanak-kanak dan menghantarnya kepada @extends, @implements dan @use tag.

Kami akan menggunakan sifat generik IlluminateDatabaseConcernsBuildsQueries sebagai contoh,

ia mentakrifkan parameter jenis 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
 ------ -----------------------------------------------------------------------------------
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Kelas IlluminateDatabaseEloquentBuilder menggunakan sifat ini tetapi mengekalkan generiknya dengan menghantar jenis parameter TModel kepadanya. Ia kini diserahkan kepada kod pelanggan untuk menentukan jenis TModel dan seterusnya TValue dalam sifat BuildsQueries.

/**
 * @template TFactory of \Illuminate\Database\Eloquent\Factories\Factory
 */
trait HasFactory
{
    ...
}
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Fikiran Akhir

Kesimpulannya, walaupun PHP tidak menyokong generik secara asli dengan cara yang sama seperti beberapa bahasa pengaturcaraan lain, pengenalan petunjuk dan alatan jenis lanjutan seperti PHPStan membolehkan pembangun melaksanakan fungsi seperti generik dalam kod mereka . Dengan memanfaatkan PHPDocs, kelas berparameter dan antara muka, anda boleh mencipta aplikasi yang lebih fleksibel dan selamat jenis yang menggalakkan kebolehgunaan semula dan kebolehselenggaraan kod. Memandangkan PHP terus berkembang, tumpuan komuniti yang semakin meningkat pada keselamatan jenis dan analisis statik mungkin akan membawa kepada penyelesaian yang lebih mantap untuk melaksanakan generik. Menerima amalan ini bukan sahaja meningkatkan kemahiran pengekodan anda tetapi juga menyumbang kepada pembangunan perisian berkualiti tinggi yang tahan ujian masa.

Atas ialah kandungan terperinci Generik PHP dalam Laravel 11. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

sumber:dev.to
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan
Tentang kita Penafian Sitemap
Laman web PHP Cina:Latihan PHP dalam talian kebajikan awam,Bantu pelajar PHP berkembang dengan cepat!