퍼사드
소개
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. 의존성 주입
의존성 주입의 주요 이점 중 하나는 주입된 클래스의 구현을 교체할 수 있다는 것입니다. 이는 모의 또는 스텁을 주입하고 스텁에서 다양한 메서드가 호출되었는지 확인할 수 있으므로 테스트 중에 유용합니다.
일반적으로 진정한 정적 클래스 메서드를 모의 또는 스텁하는 것은 불가능합니다. 그러나 퍼사드는 동적 메서드를 사용하여 서비스 컨테이너에서 확인된 객체에 대한 메서드 호출을 프록시하므로 주입된 클래스 인스턴스를 테스트하는 것과 마찬가지로 실제로 퍼사드를 테스트할 수 있습니다. 예를 들어 다음 경로가 주어졌다고 가정합니다.
use Illuminate\Support\Facades\Cache; Route::get('/cache', function () { return Cache::get('key');});
Laravel의 퍼사드 테스트 메서드를 사용하면 Cache::get 메서드가 예상한 인수로 호출되었는지 확인하기 위해 다음 테스트를 작성할 수 있습니다.
use Illuminate\Support\Facades\Cache; test('기본 예제', function () { Cache::shouldReceive('get') ->with('key') ->andReturn('value'); $response = $this->get('/cache'); $response->assertSee('value');});
use Illuminate\Support\Facades\Cache; /** * 기본적인 기능 테스트 예제입니다. */public function test_basic_example(): void{ Cache::shouldReceive('get') ->with('key') ->andReturn('value'); $response = $this->get('/cache'); $response->assertSee('value');}
퍼사드 vs. 헬퍼 함수
퍼사드 외에도 라라벨은 뷰 생성, 이벤트 발생, 작업 디스패치, 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; /** * 기본적인 기능 테스트 예시입니다. */public function test_basic_example(): void{ Cache::shouldReceive('get') ->with('key') ->andReturn('value'); $response = $this->get('/cache'); $response->assertSee('value');}
퍼사드의 작동 방식
라라벨 애플리케이션에서 퍼사드는 컨테이너의 객체에 대한 접근을 제공하는 클래스입니다. 이를 가능하게 하는 메커니즘은 Facade 클래스에 있습니다. 라라벨의 퍼사드와 생성하는 모든 사용자 정의 퍼사드는 기본 Illuminate\Support\Facades\Facade 클래스를 확장합니다.
Facade 기본 클래스는 __callStatic() 매직 메서드를 사용하여 퍼사드에서 컨테이너에서 확인된 객체로 호출을 연기합니다. 아래 예시에서는 라라벨 캐시 시스템에 대한 호출이 이루어집니다. 이 코드를 보면 정적 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{ /** * 주어진 사용자의 프로필을 표시합니다. */ public function showProfile(string $id): View { $user = Cache::get('user:'.$id); return view('profile', ['user' => $user]); }}
파일의 맨 위 근처에서 Cache 퍼사드를 "가져오는(importing)" 것을 확인하세요. 이 퍼사드는 Illuminate\Contracts\Cache\Factory 인터페이스의 기본 구현에 액세스하기 위한 프록시 역할을 합니다. 퍼사드를 사용하여 수행하는 모든 호출은 라라벨 캐시 서비스의 기본 인스턴스로 전달됩니다.
Illuminate\Support\Facades\Cache 클래스를 살펴보면 정적 메서드 get이 없는 것을 알 수 있습니다.
class Cache extends Facade{ /** * 컴포넌트의 등록된 이름을 가져옵니다. */ protected static function getFacadeAccessor(): string { return 'cache'; }}
대신 Cache 퍼사드는 기본 Facade 클래스를 확장하고 getFacadeAccessor() 메서드를 정의합니다. 이 메서드의 역할은 서비스 컨테이너 바인딩의 이름을 반환하는 것입니다. 사용자가 Cache 퍼사드에서 정적 메서드를 참조하면 라라벨은 서비스 컨테이너에서 cache 바인딩을 확인하고 요청된 메서드(이 경우 get)를 해당 객체에 대해 실행합니다.
실시간 퍼사드
실시간 퍼사드를 사용하면 애플리케이션의 모든 클래스를 마치 퍼사드인 것처럼 취급할 수 있습니다. 이를 사용하는 방법을 설명하기 위해 먼저 실시간 퍼사드를 사용하지 않는 코드를 살펴보겠습니다. 예를 들어 Podcast 모델에 publish 메서드가 있다고 가정해 보겠습니다. 그러나 팟캐스트를 게시하려면 Publisher 인스턴스를 주입해야 합니다.
<?php namespace App\Models; use App\Contracts\Publisher;use Illuminate\Database\Eloquent\Model; class Podcast extends Model{ /** * 팟캐스트를 게시합니다. */ public function publish(Publisher $publisher): void { $this->update(['publishing' => now()]); $publisher->publish($this); }}
메서드에 퍼블리셔 구현을 주입하면 주입된 퍼블리셔를 모의(mock)할 수 있으므로 메서드를 쉽게 격리하여 테스트할 수 있습니다. 그러나 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{ /** * 팟캐스트를 게시합니다. */ public function publish(Publisher $publisher): void public function publish(): void { $this->update(['publishing' => now()]); $publisher->publish($this); Publisher::publish($this); }}
실시간 퍼사드가 사용되면 퍼블리셔 구현은 인터페이스 또는 클래스 이름 중 Facades 접두사 뒤에 나타나는 부분을 사용하여 서비스 컨테이너에서 확인됩니다. 테스트할 때 라라벨의 내장 퍼사드 테스트 도우미를 사용하여 이 메서드 호출을 모의(mock)할 수 있습니다.
<?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; /** * 테스트 예제. */ public function test_podcast_can_be_published(): void { $podcast = Podcast::factory()->create(); Publisher::shouldReceive('publish')->once()->with($podcast); $podcast->publish(); }}
Facade 클래스 참조
아래에서는 모든 facade와 그 기반 클래스를 확인할 수 있습니다. 이는 주어진 facade 루트에 대한 API 문서를 빠르게 탐색하는 데 유용한 도구입니다. 해당되는 경우 서비스 컨테이너 바인딩 키도 포함되어 있습니다.