Skip to main content
從套件為 Laravel 的服務加入功能時,有時會希望在服務被使用前不要建立實例,而若實例已經建立,也要能套用設定。服務提供者的 callAfterResolving() 就是結合這兩者的 protected 方法。 本頁將確認 Laravel Framework v13.35.0 的實作,深入探討Laravel 套件開發中從 boot() 進行擴充的方式。這並不是等待整個應用程式啟動完成的掛鉤,而是針對指定服務解析的掛鉤。

尚未解析就等待,已解析就立即執行

ServiceProvider::callAfterResolving() 會執行以下兩個階段的處理。
  1. 將回呼註冊到容器的 afterResolving()。
  2. 若 resolved() 為 true,就以 make() 取得實例,並當場呼叫回呼。
若尚未解析,此方法本身不會 make() 目標。在一般的解析流程中,容器會建構物件、套用 extender、呼叫 resolving 回呼,接著才呼叫 afterResolving 回呼。 在一般的 singleton 取得流程中,容器會提前 return 已儲存的實例,因此並不是每次取得都會觸發 afterResolving。重點在於,若只註冊 afterResolving(),註冊前已建立的 singleton 就會缺少設定。

為驗證 Factory 加入規則

以提供套件專屬字串規則為例,在 validator 解析後註冊規則。官方的 ValidationServiceProvider 將此鍵註冊為 singleton,而提供者本身支援延遲載入。
在使用套件的應用程式中,可與一般規則搭配使用。
此範例中的 extend() 是 Illuminate\Validation\Factory 的規則註冊 API,與後述容器的 extend() 是不同的方法。一般的自訂規則在值為空等情況下可能不會執行,因此必填性請以 required 指定。規則本身的詳細設計請參閱自訂驗證規則。 Factory::extend() 會覆寫相同規則名稱的陣列元素,因此像此範例這樣重複註冊相同的處理,也不會增加項目。不過,為了避免覆寫其他套件的規則,公開的規則名稱應加上套件專屬的前綴。
回呼會在 Factory 解析時執行。規則的驗證閉包則是在之後 Validator 驗證目標值時才執行。註冊掛鉤時並不會驗證輸入值。

讓目標鍵與已解析判定保持一致

在容器一般的解析事件中,除了與已註冊鍵相符的回呼外,與取得物件型別相符的回呼也會被選取。另一方面,callAfterResolving() 當場使用的 resolved($name),則是針對將別名正規化後的鍵,檢查是否有已解析旗標或已儲存的實例。它並不會搜尋所有已建立的物件。 因此,即使某個介面或類別已被解析,以其他鍵呼叫的 resolved() 也不一定會是 true。請確認目標服務實際的綁定與 alias,並以相同的鍵測試已解析的情況。上述範例指定的是官方提供者所註冊的 validator。 此外,resolved() 也包含「過去曾被解析」的判定,並不代表目前的實例一定仍然存在。

這不是保證「只執行一次」的 API

callAfterResolving() 會持續保留已註冊的回呼。即使已當場執行過,之後若有新解析的物件,已註冊的回呼仍會執行。再者,若再次呼叫此方法,回呼本身也會被追加。 特別是一般的非共用綁定已被解析過時需要注意。在確認過的實作中,流程如下。
  1. 註冊新的回呼。
  2. 由於 resolved() 為 true,因此呼叫 make()。
  3. make() 建立新的物件,並在其解析事件中執行回呼。
  4. 對於從 make() 回傳的同一個物件,也會當場執行回呼。
在這個路徑中,本次註冊的回呼會對同一個物件套用兩次。請勿將只針對取得 singleton 的設計直接沿用到一般綁定上。
請勿在回呼中寄送郵件、呼叫外部 API、進行計費或無條件追加監聽器等。應僅用於以冪等方式套用服務設定,並設計成即使重複註冊或重新解析也不會產生重複的副作用。

替換物件請使用其他 API

afterResolving 回呼的回傳值不會用於替換容器回傳的物件。若想回傳裝飾器來替換服務本身,請考慮使用容器的 extend()。此 API 的閉包依約定須回傳變更後的服務。 同樣地,callAfterResolving() 也不是用來更新所有已儲存在其他物件中之依賴的機制。若目的是在重新綁定時更新依賴,請確認官方文件中的 rebinding() 以及目標類別的設計。 真正延遲載入服務的提供者需求,請參閱 DeferrableProvider。使用掛鉤,與將註冊該掛鉤的提供者本身設為延遲載入,是兩回事。

更新時應確認的組合

發布套件前,除了一般的啟動順序外,也要驗證其他提供者先使用了該服務的情況。 若以靜態旗標記錄在整個應用程式中只使用過一次,可能會導致新的容器或在測試中重新建立的服務缺少設定。設定的冪等性應盡可能以目標物件或註冊鍵為單位來確保。

相關頁面

套件 View 的覆寫與更新

確認 loadViewsFrom() 使用解析後掛鉤註冊 View 命名空間的範例。

套件翻譯的覆寫與更新

確認 Translator 的命名空間註冊,以及已載入翻譯的處理方式。

參考的第一手資料

最後修改於 2026年10月10日