您是否經常希望獲得一個集合或字串助手中不存在的方法?你開始連結方法,結果發現其中一個方法遺失了,結果卻碰壁了。老實說,這是可以理解的;你知道,框架是一刀切的東西。我多次發現自己處於這種情況。每次,在深入研究如何擴展框架之前,我都會檢查我想要擴展的內容是否可宏。但這意味著什麼?這正是我們將要探索的!
假設我們有這個 JWT:
$jwt = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c';
我們需要擷取標題:
str($jwt) ->before('.') ->fromBase64() ->fromJson(); // does not exist ? // BadMethodCallException Method Illuminate\Support\Stringable::fromJson does not exist.
fromJson() 不存在?當然,人們可以簡單地這樣做:
json_decode(str($jwt)->before('.')->fromBase64());
但這有什麼樂趣呢?另外,這是我的文章?
所以,我們需要一個方法來擴充 Stringable 類別。有幾種方法可以做到這一點,但 Laravel 提前思考,它知道開發人員可能想要添加自訂方法,因此它使類別可宏,或者像我喜歡的那樣,可擴展。
如果您檢查 IlluminateSupportStringable 類,您會看到它使用 Macroable 特徵。
讓我們繼續擴展課程。在AppServiceProvider中,加入以下內容:
<?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); }); } }
現在讓我們重新運行程式碼:
str($jwt) ->before('.') ->fromBase64() ->fromJson(); // ["alg" => "HS256", "typ" => "JWT"]
效果完美嗎?但現在,您可能想知道,這是如何運作的? $this->value 到底是什麼?哈利波特裡發生了什麼事?
我們知道Stringable類別使用Macroable特徵,它提供了macro()方法。讓我們仔細看看它的作用:
// 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; }
這非常簡單,它只是將回調保存到靜態巨集數組中。現在,如果我們進一步檢查該特徵,我們會發現 __call 方法,每次呼叫不存在的方法時都會觸發方法。在我們的例子中,就是 fromJson()。讓我們深入了解:
/** * 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); }
首先,它檢查巨集是否已註冊,fromJson() 就是這種情況,然後從巨集數組中取得回呼(或物件)。現在讓我們來看看魔術,如果巨集是閉包(如我們的例子),它會呼叫bindTo(),它本質上告訴閉包$this應該引用作為第一個參數傳遞的任何內容。在本例中,它是 Stringable 實例,它恰好具有 $value 屬性。
// $this here is the stringable // $this inside the closure is now referencing the stringable class $macro->bindTo($this, static::class);
這就是為什麼我們可以做 $this->value。
我還想告訴你一件事!當我們多次擴展同一個類別時,服務提供者可能很快就會變得混亂。我們可以將所有自訂巨集提取到一個名為 Mixin 的類別中。
讓我們建立一個 StringableMixin:
$jwt = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c';
現在,在 AppServiceProvider 中,我們可以註冊這個 mixin:
str($jwt) ->before('.') ->fromBase64() ->fromJson(); // does not exist ? // BadMethodCallException Method Illuminate\Support\Stringable::fromJson does not exist.
就是這樣!現在我們可以做:
json_decode(str($jwt)->before('.')->fromBase64());
基本上是一樣的,只是比較乾淨一點。
如果您對它的工作原理感到好奇,Macroable 特徵上的 mixin() 方法使用反射 API。它從 Mixin 類別中檢索所有公共方法,期望每個方法傳回一個閉包,然後將閉包註冊為宏,就像我們之前看到的那樣。
嗯,正如您所看到的,有很多神奇的事情發生,IDE 不知道定義的巨集。如果您在團隊中工作,其他開發人員也不會知道這些宏,這不好。幸運的是,有一些工具可以幫助您做到這一點。 Laravel IDE 幫助程式包是一個免費開源選項。
您可以安裝該軟體包並產生 _ide_helper.php 文件,然後就可以開始了。
我們的範例相當簡單,但是您可以將巨集推得更遠,因為 Laravel 附帶的大多數常見類別都是可巨集的。例如,您可以新增一個新的 apiResponse() 宏,或者您認為在應用程式邏輯中非常常見且重複次數過多的任何內容。但不要做得太過分。巨集增加了新的複雜性,在團隊中工作時,它們可能會令人困惑。
Soo,每當您感覺應用程式缺少某些內容,但框架本身沒有缺少某些內容時,請使用巨集?
以上是Laravel 底層 - 一些宏的詳細內容。更多資訊請關注PHP中文網其他相關文章!