Berapa kerapkah anda menginginkan kaedah yang tidak wujud pada koleksi atau pembantu rentetan? Anda mula merantai kaedah, hanya untuk memukul dinding apabila salah satu daripadanya ternyata hilang. Secara jujur, ia boleh difahami; rangka kerja, anda tahu, adalah satu saiz yang sesuai untuk semua. Saya mendapati diri saya dalam situasi ini beberapa kali. Setiap kali, sebelum menyelami cara memanjangkan rangka kerja, saya semak untuk melihat sama ada apa yang saya ingin lanjutkan adalah macroable atau tidak. Tetapi apakah maksudnya? Itulah yang akan kami terokai!
Katakan kita ada JWT ini:
$jwt = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c';
Dan kita perlu mengekstrak tajuk:
str($jwt) ->before('.') ->fromBase64() ->fromJson(); // does not exist ? // BadMethodCallException Method Illuminate\Support\Stringable::fromJson does not exist.
FromJson() tidak wujud ? Sudah tentu, seseorang boleh melakukan:
json_decode(str($jwt)->before('.')->fromBase64());
Tetapi di manakah keseronokan itu? Selain itu, ia adalah artikel saya ?
Jadi, kami memerlukan cara untuk melanjutkan kelas Stringable. Terdapat beberapa cara untuk melakukan ini, tetapi Laravel berfikir lebih awal, ia tahu bahawa pembangun mungkin mahu menambah kaedah tersuai, jadi ia menjadikan kelas boleh makro, atau seperti yang saya suka memanggilnya, boleh dilanjutkan.
Jika anda memeriksa kelas IlluminateSupportStringable, anda akan melihat ia menggunakan sifat Macroable.
Mari kita teruskan dan lanjutkan kelas. Dalam AppServiceProvider, tambahkan yang berikut:
<?php namespace App\Providers; use Illuminate\Support\Stringable; use Illuminate\Support\ServiceProvider; class AppServiceProvider extends ServiceProvider { public function boot(): void { Stringable::macro('fromJson', function (bool $associative = true) { return json_decode($this->value, $associative); }); } }
Sekarang mari jalankan semula kod:
str($jwt) ->before('.') ->fromBase64() ->fromJson(); // ["alg" => "HS256", "typ" => "JWT"]
Ia berfungsi dengan sempurna ? Tetapi sekarang, anda mungkin tertanya-tanya, bagaimana ini berfungsi? Dan apakah sebenarnya $this->value? Apa yang berlaku dalam harry potter?
Kami tahu bahawa kelas Stringable menggunakan sifat Macroable, yang menyediakan kaedah makro(). Mari lihat lebih dekat apa yang dilakukannya:
// src/Illuminate/Macroable/Traits/Macroable.php /** * Register a custom macro. * * @param string $name * @param object|callable $macro * * @param-closure-this static $macro * * @return void */ public static function macro($name, $macro) { static::$macros[$name] = $macro; }
Ia agak mudah, ia hanya menyimpan panggilan balik ke tatasusunan makro statik. Sekarang, jika kita memeriksa sifat itu dengan lebih lanjut, kita akan menemui kaedah __panggilan, yang dicetuskan setiap kali kaedah yang tidak wujud dipanggil. Dalam kes kami, itu fromJson(). Jom selami:
/** * Dynamically handle calls to the class. * * @param string $method * @param array $parameters * @return mixed * * @throws \BadMethodCallException */ public function __call($method, $parameters) { if (! static::hasMacro($method)) { throw new BadMethodCallException(sprintf( 'Method %s::%s does not exist.', static::class, $method )); } $macro = static::$macros[$method]; if ($macro instanceof Closure) { $macro = $macro->bindTo($this, static::class); } return $macro(...$parameters); }
Mula-mula, ia menyemak sama ada makro didaftarkan, iaitu kes fromJson(), ia kemudian mengambil panggilan balik (atau objek) daripada tatasusunan makro. Sekarang untuk silap mata, jika makro ialah penutupan (seperti dalam kes kami), ia memanggil bindTo(), yang pada asasnya memberitahu penutupan bahawa $this harus merujuk kepada apa sahaja yang diluluskan sebagai hujah pertama. Dalam kes ini, ia ialah contoh Stringable, yang kebetulan mempunyai atribut $value.
// $this here is the stringable // $this inside the closure is now referencing the stringable class $macro->bindTo($this, static::class);
Dan inilah sebabnya kita boleh melakukan $this->value.
Ada satu lagi perkara yang saya ingin tunjukkan kepada anda! Apabila kami melanjutkan kelas yang sama beberapa kali, pembekal perkhidmatan mungkin menjadi kucar-kacir dengan cepat. Kami boleh mengekstrak semua makro tersuai kami ke kelas yang dipanggil Mixin.
Jom buat StringableMixin:
$jwt = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c';
Kini, dalam AppServiceProvider, kami boleh mendaftarkan campuran ini:
str($jwt) ->before('.') ->fromBase64() ->fromJson(); // does not exist ? // BadMethodCallException Method Illuminate\Support\Stringable::fromJson does not exist.
Dan itu sahaja! Sekarang kita boleh lakukan:
json_decode(str($jwt)->before('.')->fromBase64());
Yang pada asasnya sama, cuma lebih bersih.
Jika anda ingin tahu tentang cara ini berfungsi, kaedah mixin() pada sifat Macroable menggunakan API pantulan. Ia mendapatkan semula semua kaedah awam daripada kelas Mixin, mengharapkan setiap satu untuk mengembalikan penutupan, dan kemudian mendaftarkan penutupan sebagai makro seperti yang telah kita lihat sebelum ini.
Nah, seperti yang anda lihat, terdapat banyak keajaiban yang berlaku, dan IDE tidak akan mengetahui tentang makro yang ditentukan. Jika anda bekerja dalam satu pasukan, pembangun lain juga tidak akan mengetahui tentang makro ini, yang tidak bagus. Nasib baik, terdapat alat untuk membantu anda dengan itu. Pilihan percuma dan sumber terbuka ialah pakej pembantu IDE Laravel.
Anda boleh memasang pakej dan menjana fail _ide_helper.php, dan anda sepatutnya bersedia.
Contoh kami agak mudah, tetapi anda boleh menolak makro lebih jauh daripada ini, kerana kebanyakan kelas biasa yang dihantar oleh Laravel adalah makro. Contohnya, anda boleh menambah makro apiResponse() baharu, atau apa sahaja yang anda rasa sangat biasa dalam logik apl anda dan sedang diulang lebih daripada yang sepatutnya. Tetapi jangan berlebihan. Makro menambah lapisan kerumitan baharu dan apabila bekerja dalam satu pasukan, ia boleh mengelirukan.
Soo, apabila anda merasakan sesuatu yang hilang daripada aplikasi anda, tetapi bukan dari rangka kerja itu sendiri, gunakan makro ?
Atas ialah kandungan terperinci Laravel Under The Hood - Sedikit Makro. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!