技術ブログ: 「Laravel コンセプト」ファサード(façade)のデコード

11 8月, 2023 /

Laravel コンセプトのシリーズでは、サービス コンテナー、サービス プロバイダー、ファサード等のLaravel フレームワークの中核と知られる技術について学びます。

コンセプト・メリット

概要

Laravel の使用経験がある場合は、次のコードに遭遇したことがあるでしょう。

Cache::set(‘access_token’, \Illuminate\Support\Facades\Request::get(‘token’));

ファサードである「Cache::set(), Request::get(), DB::table(), Http::get()」に注目してください。 

では、ファサードとは具体的に何なのかを話しましょう。

ファサードは、コンテナー内のクラスに静的プロキシ クラスを提供します。これにより、非静的関数を静的に呼び出すことができます。

それは複雑だと思いませんか? 明確にするために次の例を見てみましょう。

非静的関数を呼び出す標準的な方法は次のとおりです。

$cache = new CacheManager(app());

ここでは、キャッシュは静的に呼び出されます。

Cache::set(‘access_token’, $token);

 PHPの基礎知識があれば、「::」キーワードがクラス オブジェクトをインスタンス化せずに静的関数を呼び出すのに役立つことは誰でも知っています。

ファサードのメリット・ユースケース

  • 構文は短く、覚えやすい:上記のCache Facadeの例を振り返ると、ファサード以外の方法で使用する場合は、CacheManagerクラスの名前を覚えておく必要があります。状況に応じて、CacheService、CacheDriver等、まったく異なる名前が付けられることもあります。しかし、Cacheという名前を使用すると、元の概念 (キャッシュ) に非常に近いため、覚えるのが非常に簡単になります。また、staticの呼び出しも非常に短いです (1行でも2行より短いはずなので🤣)
  • ディペンデンシーや設定を気にすることが無い:新しいCacheManager(app())を見ると、クラスをインスタンス化するときに、すべてのディペンデンシーや設定値を提供する必要が明確になります。それに、ディペンデンシーの中に別のディペンデンシーがある場合、それを完全に宣言する必要がある時、本当に悪夢になります。しかし、ファサードではすべてがフレームワークに行われるため、この問題は完全に無視できます。
  • 配下の実際の実装を隠す: Http::get() を呼び出すとき、それが何をするかを把握する必要はありません。単に呼び出して結果を楽しむだけで良いです😊。または、InvoiceFacade::send(‘target@gmail.com’, ‘2022-02’, ‘month’) の例として、月ごとに集計されたデータを「target@gmail.com」への請求書送信のロジックを読み進めると簡単に理解できます。send関数には、データの取得、データの絞り込み、メールのチェック、ファイルの作成、s3へのアップロード等、さまざまなロジックを使用できます。しかし、ファサードを作成するときは、send関数を呼び出すだけで十分です。これはあくまで一例であり、実際には問題に応じて柔軟に適用する必要があります。
  • テストの実行が簡単

ファサードの仕組み

さて、次はファサードがどのように動くかを見ていきましょう。

次の例を使用してみましょう。

use Illuminate\Support\Facades\URL;

上記はファサードのURLを使用した例です。ご覧のとおり、Illuminate\Support\Facades\URLクラスを通常どおり使用しました。ただし、そのクラスを開くと、単一の関数を備えたクラスしか得られません。

/**

待って、Cacheクラスはファサードクラスを継承しています。そのクラスを開こうとすると、その中にset()関数 が定義されているのではないでしょうか? クラスを開いたら、ああ、何もない😒。

ここがファサードの魔法を発揮するところです。

PHPの話に戻ると、クラスに存在しない静的関数が呼び出される場合、代わりに __callStaticという、魔法があるようなメソッドが呼び出されます。次のコードを見てみましょう。

<?php

上記のコードをコピーしてテストを実行してみましょう。get()関数を呼び出すと、「Get関数」の結果が得られることが直ぐに把握できます。

テストクラスにはset()関数はありません。これで、__callStatic()関数が完全な関数名と引数で呼び出されます。結果を確認すると、次のようになります。

__callStatic: set function [].

ファサード クラスを再度開き、__callStatic関数を見つけてみましょう。URL::route()関数を呼び出すと、例外を投げらずに、__callStaticが実行されることを理解できるでしょう。

   /**

しかし、URL::route()のroute()関数は実際にはどこにあり、そしてどのように記載されているのでしょうか?

__callStatic を呼び出すときにファサードが実行する手順は次のとおりです。

  • getFacadeAccessor()関数を通じてインスタンスのバインディング値を取得します。Illuminate\Support\Facades\URL.phpクラスでは、この関数が「url」の値を返していることを理解できます。
  • サービス コンテナ内で、ファサード アクセサーにバインドされている値を確認します。これが「url」です (64行目の Illuminate\Routing\RoutingServiceProvider.phpクラスを参照してください)。
  • サービス コンテナからバインディング値を解決すると、Illuminate\Routing\UrlGenerator.phpクラスのインスタンスが得られます。ここに、route()関数のコードが記載されます。解決後、結果を一時的に$instanceResolvedと呼びます。
  • 非静的な方法で$instanceResolvedから関数を呼び出します。

ファサード作成の練習

Invoice.phpクラスを作成

<?php

Invoiceクラスをコンテナにバインドします。

AppServiceProviderクラスに、次のコードを追加します。

    public function register(): void

InvoiceFacadeクラスを作成します。

<?php

getFacadeAccessor()の戻り値は、コンテナーにバインドされている(「invoice」) 値と一致する必要があることに注意してください。

Invoice Façadeを使用

    public function Test()

そのため、初期化または実装するための構成方法を知らずに、Invoice Facadeのsend() 関数を呼び出したことを把握できます。

ファサードのエイリアス

Route::URL() の例に戻り、次のコード行を削除するとどうなるでしょうか。

use Illuminate\Support\Facades\URL;

答えは、コードがまだ適切に動作するということです。 これは、ファサード エイリアスと呼ばれる仕組みによるものです。

Illuminate\Support\Facades\Facade.phpクラスを再度開き、defaultAliases() 関数を見つけます。この関数はデフォルトのファサードのエイリアスを定義するため、このクラスを使用する必要はありません。

練習例で、エイリアスも使用したい場合はどうすればよいでしょうか? 以下の手順で実施してください。

エイリアスを作成

次のコードをconfigs/app.phpに追加します。

‘aliases’ => Facade::defaultAliases()->merge([

ファサードが使用されている次の行を削除します。

use App\InvoiceFacade;

もう一度試してください。結果も同じです。

まとめ

これで、Laravelファサードとその魔法の仕組みが理解できました。 次回の投稿では、サービス コンテナ技術について詳細的に説明します。投稿をフォローしていただきありがとうございます。

フィードバックがありましたら、下記のコメント欄でお知らせください!😍