ファサード (Facades)
導入 (Introduction)
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([
// ...
]);
});
ファサードを使用する場合 (When to Utilize Facades)
ファサードには多くの利点があります。これらは、手動で挿入または設定する必要がある長いクラス名を覚えなくても、Laravel の機能を使用できる簡潔で覚えやすい構文を提供します。さらに、PHP の動的メソッドを独自に使用しているため、テストが簡単です。
ただし、ファサードを使用する場合は注意が必要です。ファサードの主な危険は「スコープクリープ」クラスです。ファサードは非常に使いやすく、注入の必要がないため、クラスを成長させ続けて 1 つのクラスで多くのファサードを使用することも簡単です。依存関係の注入を使用すると、大規模なコンストラクターがクラスが大きくなりすぎていることを視覚的にフィードバックすることで、この可能性が軽減されます。したがって、ファサードを使用するときは、クラスの責任範囲が狭くならないように、クラスの規模に特に注意してください。クラスが大きくなりすぎる場合は、複数の小さなクラスに分割することを検討してください。
ファサードと依存関係の注入
依存注入の主な利点の 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');
}
ファサードとヘルパ関数
ファサードに加えて、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');
}
ファサードの仕組み (How Facades Work)
Laravel アプリケーションでは、ファサードはコンテナからオブジェクトへのアクセスを提供するクラスです。これを機能させる機械は、Facade クラスにあります。 Laravel のファサード、および作成するカスタム ファサードは、基本 Illuminate\Support\Facades\Facade クラスを拡張します。
Facade 基本クラスは、__callStatic() マジック メソッドを利用して、ファサードからコンテナーから解決されたオブジェクトへの呼び出しを延期します。以下の例では、Laravel キャッシュ システムへの呼び出しが行われます。このコードを一目見ると、静的 get メソッドが Cache クラスで呼び出されていると思われるかもしれません。
<?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)を実行します。
リアルタイムファサード (Real-Time Facades)
リアルタイム ファサードを使用すると、アプリケーション内の任意のクラスをファサードであるかのように扱うことができます。これがどのように使用できるかを説明するために、まずリアルタイム ファサードを使用しないコードを調べてみましょう。たとえば、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; // [tl! remove]
use Facades\App\Contracts\Publisher; // [tl! add]
use Illuminate\Database\Eloquent\Model;
class Podcast extends Model
{
/**
* Publish the podcast.
*/
public function publish(Publisher $publisher): void // [tl! remove]
public function publish(): void // [tl! add]
{
$this->update(['publishing' => now()]);
$publisher->publish($this); // [tl! remove]
Publisher::publish($this); // [tl! add]
}
}
リアルタイム ファサードが使用される場合、パブリッシャーの実装は、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();
}
}
ファサードクラスリファレンス (Facade Class Reference)
以下に、すべてのファサードとその基礎となるクラスが表示されます。これは、特定のファサード ルートの API ドキュメントをすばやく調べるのに便利なツールです。該当する場合、サービスコンテナのバインディング キーも含まれます。