ファサード
はじめに
Laravel のドキュメント全体を通して、"ファサード" を介して Laravel の機能と対話するコード例が表示されます。ファサードは、アプリケーションのサービスコンテナで利用可能なクラスへの "静的" インターフェースを提供します。Laravel には、Laravel のほぼすべての機能へのアクセスを提供する多くのファサードが付属しています。
Laravel ファサードは、サービスコンテナ内の基底クラスへの "静的プロキシ" として機能し、従来の静的メソッドよりもテスト性と柔軟性を維持しながら、簡潔で表現力豊かな構文の利点を提供します。ファサードの仕組みを完全に理解していなくても問題ありません。流れに乗って Laravel について学び続けてください。
Laravel のすべてのファサードは、`Illuminate\Support\Facades` 名前空間で定義されています。そのため、次のようにファサードに簡単にアクセスできます
use Illuminate\Support\Facades\Cache;use Illuminate\Support\Facades\Route; Route::get('/cache', function () { return Cache::get('key');});
Laravel のドキュメント全体を通して、多くの例では、ファサードを使用してフレームワークのさまざまな機能を示します。
ヘルパー関数
ファサードを補完するために、Laravel は、一般的な Laravel 機能との対話をさらに容易にするさまざまなグローバル "ヘルパー関数" を提供しています。よく使用するヘルパー関数には、`view`、`response`、`url`、`config` などがあります。Laravel が提供する各ヘルパー関数は、対応する機能とともに文書化されています。ただし、完全なリストは専用のヘルパーのドキュメントにあります。
たとえば、`Illuminate\Support\Facades\Response` ファサードを使用して JSON レスポンスを生成する代わりに、単に `response` 関数を使用できます。ヘルパー関数はグローバルに利用できるため、クラスをインポートしなくても使用できます
use Illuminate\Support\Facades\Response; Route::get('/users', function () { return Response::json([ // ... ]);}); Route::get('/users', function () { return response()->json([ // ... ]);});
ファサードを使用するタイミング
ファサードには多くの利点があります。手動で注入または設定する必要がある長いクラス名を覚えることなく、Laravel の機能を使用できる簡潔で覚えやすい構文を提供します。さらに、PHP の動的メソッドの独自の使用方法により、テストが容易です。
ただし、ファサードを使用する際には注意が必要です。ファサードの主な危険性は、クラスの "スコープクリープ" です。ファサードは非常に使いやすく、注入を必要としないため、クラスが成長し続け、単一のクラスで多くのファサードを使用してしまう可能性があります。依存性注入を使用すると、大きなコンストラクタによってクラスが大きくなりすぎているという視覚的なフィードバックが得られるため、この可能性が軽減されます。そのため、ファサードを使用する場合は、クラスのサイズに特に注意して、責任の範囲を狭くしてください。クラスが大きくなりすぎている場合は、複数の小さなクラスに分割することを検討してください。
ファサード vs. 依存性注入
依存性注入の主な利点の 1 つは、注入されたクラスの実装を交換できることです。モックまたはスタブを注入し、スタブでさまざまなメソッドが呼び出されたことをアサートできるため、これはテスト中に役立ちます。
通常、真に静的なクラスメソッドをモックまたはスタブすることはできません。ただし、ファサードは動的メソッドを使用してサービスコンテナから解決されたオブジェクトへのメソッド呼び出しをプロキシするため、注入されたクラスインスタンスをテストするのと同じようにファサードをテストできます。たとえば、次のルートが与えられた場合
use Illuminate\Support\Facades\Cache; Route::get('/cache', function () { return Cache::get('key');});
Laravel のファサードテストメソッドを使用して、`Cache::get` メソッドが予期した引数で呼び出されたことを確認するために、次のテストを書くことができます
use Illuminate\Support\Facades\Cache; test('basic example', function () { Cache::shouldReceive('get') ->with('key') ->andReturn('value'); $response = $this->get('/cache'); $response->assertSee('value');});
use Illuminate\Support\Facades\Cache; /** * A basic functional test example. */public function test_basic_example(): void{ Cache::shouldReceive('get') ->with('key') ->andReturn('value'); $response = $this->get('/cache'); $response->assertSee('value');}
ファサード vs. ヘルパー関数
ファサードに加えて、Laravel には、ビューの生成、イベントの発生、ジョブのディスパッチ、HTTP レスポンスの送信などの一般的なタスクを実行できるさまざまな "ヘルパー" 関数が含まれています。これらのヘルパー関数の多くは、対応するファサードと同じ機能を実行します。たとえば、このファサード呼び出しとヘルパー呼び出しは同等です
return Illuminate\Support\Facades\View::make('profile'); return view('profile');
ファサードとヘルパー関数の間に実際的な違いはまったくありません。ヘルパー関数を使用する場合でも、対応するファサードとまったく同じようにテストできます。たとえば、次のルートが与えられた場合
Route::get('/cache', function () { return cache('key');});
`cache` ヘルパーは、`Cache` ファサードの基になるクラスで `get` メソッドを呼び出します。そのため、ヘルパー関数を使用している場合でも、メソッドが予期した引数で呼び出されたことを確認するために、次のテストを書くことができます
use Illuminate\Support\Facades\Cache; /** * A basic functional test example. */public function test_basic_example(): void{ Cache::shouldReceive('get') ->with('key') ->andReturn('value'); $response = $this->get('/cache'); $response->assertSee('value');}
ファサードの仕組み
Laravel アプリケーションでは、ファサードはコンテナからオブジェクトへのアクセスを提供するクラスです。これを機能させる仕組みは `Facade` クラスにあります。Laravel のファサード、および作成するカスタムファサードは、基本の `Illuminate\Support\Facades\Facade` クラスを拡張します。
`Facade` 基底クラスは `__callStatic()` マジックメソッドを使用して、ファサードからの呼び出しをコンテナから解決されたオブジェクトに延期します。以下の例では、Laravel キャッシュシステムへの呼び出しが行われています。このコードを一目見ただけでは、`Cache` クラスで静的 `get` メソッドが呼び出されていると想定するかもしれません
<?php namespace App\Http\Controllers; use App\Http\Controllers\Controller;use Illuminate\Support\Facades\Cache;use Illuminate\View\View; class UserController extends Controller{ /** * Show the profile for the given user. */ public function showProfile(string $id): View { $user = Cache::get('user:'.$id); return view('profile', ['user' => $user]); }}
ファイルの先頭付近で `Cache` ファサードを "インポート" していることに注意してください。このファサードは、`Illuminate\Contracts\Cache\Factory` インターフェースの基になる実装にアクセスするためのプロキシとして機能します。ファサードを使用して行う呼び出しはすべて、Laravel のキャッシュサービスの基になるインスタンスに渡されます。
その `Illuminate\Support\Facades\Cache` クラスを見ると、静的メソッド `get` がないことがわかります
class Cache extends Facade{ /** * Get the registered name of the component. */ protected static function getFacadeAccessor(): string { return 'cache'; }}
代わりに、`Cache` ファサードは基底 `Facade` クラスを拡張し、`getFacadeAccessor()` メソッドを定義します。このメソッドのジョブは、サービスコンテナバインディングの名前を返すことです。ユーザーが `Cache` ファサードの静的メソッドを参照すると、Laravel はサービスコンテナから `cache` バインディングを解決し、そのオブジェクトに対して要求されたメソッド(この場合は `get`)を実行します。
リアルタイムファサード
リアルタイムファサードを使用すると、アプリケーション内の任意のクラスをファサードであるかのように扱うことができます。これがどのように使用できるかを示すために、まずリアルタイムファサードを使用しないコードをいくつか見てみましょう。たとえば、`Podcast` モデルに `publish` メソッドがあるとします。ただし、ポッドキャストを公開するには、`Publisher` インスタンスを注入する必要があります
<?php namespace App\Models; use App\Contracts\Publisher;use Illuminate\Database\Eloquent\Model; class Podcast extends Model{ /** * Publish the podcast. */ public function publish(Publisher $publisher): void { $this->update(['publishing' => now()]); $publisher->publish($this); }}
メソッドにパブリッシャー実装を注入することで、注入されたパブリッシャーをモックできるため、メソッドを簡単に単独でテストできます。ただし、`publish` メソッドを呼び出すたびに、常にパブリッシャーインスタンスを渡す必要があります。リアルタイムファサードを使用すると、`Publisher` インスタンスを明示的に渡す必要なく、同じテスト容易性を維持できます。リアルタイムファサードを生成するには、インポートされたクラスの名前空間に `Facades` というプレフィックスを付けます
<?php namespace App\Models; use App\Contracts\Publisher; use Facades\App\Contracts\Publisher; use Illuminate\Database\Eloquent\Model; class Podcast extends Model{ /** * Publish the podcast. */ public function publish(Publisher $publisher): void public function publish(): void { $this->update(['publishing' => now()]); $publisher->publish($this); Publisher::publish($this); }}
リアルタイムファサードが使用されると、`Facades` プレフィックスの後に表示されるインターフェースまたはクラス名の一部を使用して、パブリッシャー実装がサービスコンテナから解決されます。テストを行うときは、Laravel の組み込みファサードテストヘルパーを使用して、このメソッド呼び出しをモックできます
<?php use App\Models\Podcast;use Facades\App\Contracts\Publisher;use Illuminate\Foundation\Testing\RefreshDatabase; uses(RefreshDatabase::class); test('podcast can be published', function () { $podcast = Podcast::factory()->create(); Publisher::shouldReceive('publish')->once()->with($podcast); $podcast->publish();});
<?php namespace Tests\Feature; use App\Models\Podcast;use Facades\App\Contracts\Publisher;use Illuminate\Foundation\Testing\RefreshDatabase;use Tests\TestCase; class PodcastTest extends TestCase{ use RefreshDatabase; /** * A test example. */ public function test_podcast_can_be_published(): void { $podcast = Podcast::factory()->create(); Publisher::shouldReceive('publish')->once()->with($podcast); $podcast->publish(); }}
ファサードクラスリファレンス
以下に、すべてのファサードとその基になるクラスを示します。これは、特定のファサードルートの API ドキュメントをすばやく掘り下げるための便利なツールです。該当する場合、サービスコンテナバインディングキーも含まれています。