Beberapa hari yang lalu, saya sedang membetulkan ujian yang tidak stabil, dan ternyata saya memerlukan beberapa nilai unik dan sah dalam kilang saya. Laravel membungkus FakerPHP, yang biasanya kami akses melalui pembantu () palsu. FakerPHP datang dengan pengubah suai seperti valid() dan unique(), tetapi anda boleh menggunakan hanya satu demi satu, jadi anda tidak boleh melakukan fake()->unique()->valid(), iaitu apa yang saya diperlukan. Ini membuatkan saya berfikir, bagaimana jika kita mahu mencipta pengubahsuai kita sendiri? Contohnya, uniqueAndValid(), atau mana-mana pengubah suai lain. Bagaimanakah kita boleh melanjutkan rangka kerja?
Saya akan membuang pemikiran saya.
Sebelum terjun ke mana-mana penyelesaian yang terlalu direkayasa, saya sentiasa ingin menyemak sama ada terdapat pilihan yang lebih mudah dan memahami perkara yang saya hadapi. Jadi, mari kita lihat pembantu palsu():
function fake($locale = null) { if (app()->bound('config')) { $locale ??= app('config')->get('app.faker_locale'); } $locale ??= 'en_US'; $abstract = \Faker\Generator::class.':'.$locale; if (! app()->bound($abstract)) { app()->singleton($abstract, fn () => \Faker\Factory::create($locale)); } return app()->make($abstract); }
Membaca kod, kita dapat melihat bahawa Laravel mengikat satu tunggal pada bekas. Walau bagaimanapun, jika kita memeriksa abstrak, ia adalah kelas biasa yang tidak melaksanakan sebarang antara muka, dan objek itu dicipta melalui kilang. Ini merumitkan perkara. Kenapa?
Penyelesaian ?? Seseorang mungkin berfikir, "Apakah yang menghalang kami daripada mencipta kilang kami sendiri yang mengembalikan penjana baharu seperti yang digariskan dalam perkara 1?" Nah, tiada apa-apa, kita boleh lakukan itu, tetapi kita tidak akan melakukannya! Kami menggunakan rangka kerja untuk beberapa sebab, salah satunya ialah kemas kini. Apakah yang akan berlaku jika FakerPHP menambah pembekal baharu atau mempunyai peningkatan besar? Laravel akan melaraskan kod dan orang yang tidak membuat sebarang perubahan tidak akan menyedari apa-apa. Walau bagaimanapun, kami akan ditinggalkan, dan kod kami mungkin pecah (kemungkinan besar). Jadi, ya, kami tidak mahu pergi sejauh itu.
Sekarang kita telah meneroka pilihan asas, kita boleh mula memikirkan pilihan yang lebih maju, seperti corak reka bentuk. Kami tidak memerlukan pelaksanaan yang tepat, hanya sesuatu yang biasa dengan masalah kami. Itulah sebabnya saya selalu mengatakan adalah baik untuk mengenali mereka. Dalam kes ini, kita boleh "menghiasi" kelas Generator dengan menambah ciri baharu sambil mengekalkan ciri lama. Kedengaran bagus? Jom tengok caranya!
Pertama, mari buat kelas baharu, FakerGenerator:
function fake($locale = null) { if (app()->bound('config')) { $locale ??= app('config')->get('app.faker_locale'); } $locale ??= 'en_US'; $abstract = \Faker\Generator::class.':'.$locale; if (! app()->bound($abstract)) { app()->singleton($abstract, fn () => \Faker\Factory::create($locale)); } return app()->make($abstract); }
Ini akan menjadi "penghias" kami (agak). Ia adalah kelas mudah yang menjangkakan Penjana asas sebagai kebergantungan dan memperkenalkan pengubah suai baharu, uniqueAndValid(). Ia juga menggunakan sifat ForwardsCalls daripada Laravel, yang membolehkannya membuat proksi panggilan ke objek asas.
Sifat ini mempunyai dua kaedah: forwardCallTo dan forwardDecoratedCallTo. Gunakan kaedah yang terakhir apabila anda ingin merantai kaedah pada objek yang dihias. Dalam kes kami, kami akan sentiasa mempunyai satu panggilan.
Kami juga perlu melaksanakan UniqueAndValidGenerator, iaitu pengubah suai tersuai, tetapi ini bukan maksud artikel. Jika anda berminat dengan pelaksanaannya, kelas ini pada asasnya adalah campuran ValidGenerator dan UniqueGenerator yang dihantar dengan FakerPHP, anda boleh menemuinya di sini.
Sekarang, mari lanjutkan rangka kerja, dalam AppServiceProvider:
<?php namespace App\Support; use Closure; use Faker\Generator; use Illuminate\Support\Traits\ForwardsCalls; class FakerGenerator { use ForwardsCalls; public function __construct(private readonly Generator $generator) { } public function uniqueAndValid(Closure $validator = null): UniqueAndValidGenerator { return new UniqueAndValidGenerator($this->generator, $validator); } public function __call($method, $parameters): mixed { return $this->forwardCallTo($this->generator, $method, $parameters); } }
Kaedah extend() menyemak sama ada abstrak yang sepadan dengan nama yang diberikan telah diikat pada bekas. Jika ya, ia mengatasi nilainya dengan hasil penutupan, sila lihat:
<?php namespace App\Providers; use Closure; use Faker\Generator; use App\Support\FakerGenerator; use Illuminate\Support\ServiceProvider; class AppServiceProvider extends ServiceProvider { public function register(): void { $this->app->extend( $this->fakerAbstractName(), fn (Generator $base) => new FakerGenerator($base) ); } private function fakerAbstractName(): string { // This is important, it matches the name bound by the fake() helper return Generator::class . ':' . app('config')->get('app.faker_locale'); } }
Itulah sebabnya kami menentukan kaedah fakerAbstractName(), yang menjana nama yang sama yang diikat oleh pembantu palsu() dalam bekas.
Semak semula kod di atas jika anda terlepas, saya tinggalkan komen.
Kini, setiap kali kami memanggil fake(), contoh FakerGenerator akan dikembalikan, dan kami akan mempunyai akses kepada pengubah suai tersuai yang kami perkenalkan. Setiap kali kami memanggil panggilan yang tidak wujud pada kelas FakerGenerator, __call() akan dicetuskan dan ia akan memproksikannya kepada Penjana asas menggunakan kaedah forwardCallTo().
Itu sahaja! Saya akhirnya boleh melakukan fake()->uniqueAndValid()->randomElement(), dan ia berfungsi seperti azimat!
Sebelum kita membuat kesimpulan, saya ingin menunjukkan bahawa ini bukan corak penghias tulen. Walau bagaimanapun, corak bukanlah teks suci; ubah suai untuk memenuhi keperluan anda dan selesaikan masalah.
Frameworks sangat membantu dan Laravel dilengkapi dengan banyak ciri terbina dalam. Walau bagaimanapun, mereka tidak dapat merangkumi semua kes kelebihan dalam projek anda, dan kadangkala anda mungkin menemui jalan buntu. Apabila itu berlaku, anda sentiasa boleh melanjutkan rangka kerja. Kami telah melihat betapa mudahnya ia, dan saya harap anda memahami idea utama, yang terpakai selain daripada contoh Faker ini.
Sentiasa mula mudah dan cari penyelesaian paling mudah untuk masalah itu. Kerumitan akan datang apabila perlu, jadi jika warisan asas berjaya, tidak perlu melaksanakan penghias atau apa-apa lagi. Apabila anda melanjutkan rangka kerja, pastikan anda tidak pergi terlalu jauh, di mana kerugian melebihi keuntungan. Anda tidak mahu mengekalkan sebahagian daripada rangka kerja anda sendiri.
Atas ialah kandungan terperinci Laravel Under The Hood - Memanjangkan rangka kerja. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!