> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# 파사드

> Laravel의 파사드 구조와 사용법, 실시간 파사드, 테스트 방법, 의존성 주입과의 구분 사용을 설명합니다.

## 파사드란

파사드는 애플리케이션의 [서비스 컨테이너](/ko/service-container)에서 사용 가능한 클래스에 대한 "정적" 인터페이스를 제공합니다. Laravel에는 거의 모든 기능에 접근할 수 있는 많은 파사드가 함께 포함되어 있습니다.

Laravel의 파사드는 서비스 컨테이너 내의 실체 클래스에 대한 "정적 프록시"로 기능하며, 기존의 정적 메서드보다 테스트하기 쉽고 유연성을 유지하면서 간결하고 표현력이 풍부한 문법을 제공합니다.

모든 Laravel 파사드는 `Illuminate\Support\Facades` 네임스페이스에 정의되어 있습니다.

```php theme={null}
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Route;

Route::get('/cache', function () {
    return Cache::get('key');
});
```

<Info>
  파사드의 구조를 완벽하게 이해하지 못해도 문제 없습니다. 우선 사용법을 익히고 Laravel 학습을 계속해 나갑시다.
</Info>

## 파사드의 구조

Laravel 애플리케이션에서 파사드는 컨테이너에서 객체로의 접근을 제공하는 클래스입니다. 이 구조는 `Facade` 클래스에 의해 실현되고 있습니다. Laravel의 모든 파사드, 그리고 커스텀 파사드는 기저 클래스 `Illuminate\Support\Facades\Facade`를 상속합니다.

`Facade` 기저 클래스는 `__callStatic()` 매직 메서드를 사용해 파사드로의 호출을 컨테이너에서 해결된 객체로 위임합니다.

```mermaid theme={null}
flowchart LR
    A["Cache::get('key')"] --> B["Facade::__callStatic()"]
    B --> C["getFacadeAccessor()<br>→ 'cache'"]
    C --> D["서비스 컨테이너<br>make('cache')"]
    D --> E["실 클래스의 인스턴스<br>CacheManager"]
    E --> F["get('key')<br>를 실행"]
```

```php theme={null}
<?php

namespace App\Http\Controllers;

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` 파사드를 임포트하고 있습니다. 이 파사드는 `Illuminate\Contracts\Cache\Factory` 인터페이스 구현으로의 접근을 프록시합니다. 파사드를 사용한 호출은 모두 Laravel의 캐시 서비스의 내부 인스턴스로 전달됩니다.

`Illuminate\Support\Facades\Cache` 클래스를 보면 정적 메서드 `get`은 존재하지 않습니다.

```php theme={null}
class Cache extends Facade
{
    /**
     * 컴포넌트의 등록명을 가져온다
     */
    protected static function getFacadeAccessor(): string
    {
        return 'cache';
    }
}
```

`Cache` 파사드는 기저 `Facade` 클래스를 상속하고, `getFacadeAccessor()` 메서드를 정의하고 있습니다. 이 메서드는 서비스 컨테이너의 바인딩 이름을 반환합니다. 사용자가 `Cache` 파사드의 정적 메서드를 호출하면 Laravel은 서비스 컨테이너에서 `cache` 바인딩을 해결하고, 그 객체에 대해 요청된 메서드(이 경우 `get`)를 실행합니다.

## 파사드를 사용하는 상황·사용하지 않는 상황

### 파사드의 장점

파사드에는 많은 장점이 있습니다. 수동으로 주입·설정해야 하는 긴 클래스명을 외우지 않고도 Laravel의 기능을 사용할 수 있는 간결하고 기억하기 쉬운 문법을 제공합니다. 또한 PHP의 다이내믹 메서드의 독자적인 사용법을 통해 테스트가 용이합니다.

### 스코프 크리프에 주의한다

파사드를 사용할 때의 주된 위험은 클래스의 "스코프 크리프"입니다. 파사드는 사용하기 쉽고 주입을 필요로 하지 않으므로 클래스가 비대화되어 많은 파사드를 계속해서 사용하게 되기 쉽습니다. 의존성 주입을 사용하면 큰 생성자가 시각적인 피드백을 줍니다. 파사드를 사용하는 경우에는 클래스 크기에 주의하며 책임 범위를 좁게 유지합시다.

<Warning>
  클래스가 너무 커졌다고 느끼면 여러 개의 작은 클래스로 분할하는 것을 검토해 주세요.
</Warning>

### 파사드 vs. 의존성 주입

의존성 주입의 주요 장점 중 하나는 주입된 클래스의 구현을 교체할 수 있다는 것입니다. 이는 테스트 시에 유용합니다. 모의 객체나 스텁을 주입해 스텁에 대해 다양한 메서드가 호출되었음을 어서션할 수 있습니다.

진정으로 정적인 클래스 메서드는 일반적으로 모의 객체나 스텁으로 만들 수 없지만, 파사드는 다이내믹 메서드를 사용해 서비스 컨테이너에서 해결된 객체로의 메서드 호출을 프록시하기 때문에, 주입된 클래스 인스턴스를 테스트하는 것과 같은 방법으로 파사드를 테스트할 수 있습니다.

```php theme={null}
use Illuminate\Support\Facades\Cache;

Route::get('/cache', function () {
    return Cache::get('key');
});
```

이 라우트에 대해 다음 테스트를 작성해 `Cache::get`이 기대하는 인수로 호출되었음을 검증할 수 있습니다.

```php theme={null}
use Illuminate\Support\Facades\Cache;

test('basic example', function () {
    Cache::shouldReceive('get')
        ->with('key')
        ->andReturn('value');

    $response = $this->get('/cache');

    $response->assertSee('value');
});
```

### 파사드 vs. 헬퍼 함수

파사드에 더해 Laravel은 뷰 생성, 이벤트 발생, 잡 디스패치, HTTP 응답 전송 등 일반적인 작업을 실행할 수 있는 "헬퍼" 함수를 제공합니다. 많은 헬퍼 함수는 대응하는 파사드와 같은 기능을 실행합니다.

```php theme={null}
// 파사드를 사용한 호출
return Illuminate\Support\Facades\View::make('profile');

// 헬퍼 함수를 사용한 동등한 호출
return view('profile');
```

파사드와 헬퍼 함수 사이에는 실질적인 차이가 없습니다. 헬퍼 함수를 사용하고 있는 경우에도 대응하는 파사드와 같은 방법으로 테스트할 수 있습니다.

```php theme={null}
use Illuminate\Support\Facades\Cache;

test('cache helper test', function () {
    Cache::shouldReceive('get')
        ->with('key')
        ->andReturn('value');

    $response = $this->get('/cache');

    $response->assertSee('value');
});
```

## 실시간 파사드

실시간 파사드를 사용하면 애플리케이션 내의 임의의 클래스를 파사드로 다룰 수 있습니다. 사용법을 설명하기 위해 먼저 실시간 파사드를 사용하지 않는 코드를 보겠습니다.

예를 들어 `Podcast` 모델에 `publish` 메서드가 있다고 가정합니다. 다만 팟캐스트를 공개하려면 `Publisher` 인스턴스를 주입해야 합니다.

```php theme={null}
<?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);
    }
}
```

실시간 파사드를 사용하면 같은 테스트 용이성을 유지하면서 `Publisher` 인스턴스를 명시적으로 전달할 필요가 없어집니다. 실시간 파사드를 생성하려면 임포트할 클래스의 네임스페이스에 `Facades`라는 프리픽스를 붙입니다.

```php theme={null}
<?php

namespace App\Models;

use Facades\App\Contracts\Publisher;
use Illuminate\Database\Eloquent\Model;

class Podcast extends Model
{
    /**
     * 팟캐스트를 공개한다
     */
    public function publish(): void
    {
        $this->update(['publishing' => now()]);

        Publisher::publish($this);
    }
}
```

실시간 파사드가 사용되면 `Facades` 프리픽스 뒤에 나타나는 인터페이스 또는 클래스명 부분을 사용해 서비스 컨테이너에서 퍼블리셔의 구현이 해결됩니다.

```php theme={null}
<?php

use App\Models\Podcast;
use Facades\App\Contracts\Publisher;
use Illuminate\Foundation\Testing\RefreshDatabase;

pest()->use(RefreshDatabase::class);

test('podcast can be published', function () {
    $podcast = Podcast::factory()->create();

    Publisher::shouldReceive('publish')->once()->with($podcast);

    $podcast->publish();
});
```

<Tip>
  실시간 파사드는 테스트 시의 모의 객체 생성을 쉽게 하면서, 인수로 전달할 필요를 없애고 싶은 경우에 편리합니다.
</Tip>

## 파사드의 테스트

파사드를 테스트하려면 `shouldReceive` 메서드를 사용합니다. 이를 통해 Mockery의 모의 객체 인스턴스가 반환됩니다. 파사드는 실제로 서비스 컨테이너에 의해 해결·관리되기 때문에 일반적인 정적 클래스보다 훨씬 테스트하기 쉽습니다.

```php theme={null}
use Illuminate\Support\Facades\Cache;

test('사용자 프로필을 표시한다', function () {
    Cache::shouldReceive('get')
        ->once()
        ->with('user:1')
        ->andReturn(['name' => 'Taylor']);

    $response = $this->get('/users/1');

    $response->assertSee('Taylor');
});
```

자주 사용하는 모의 메서드는 다음과 같습니다.

| 메서드                       | 설명                 |
| ------------------------- | ------------------ |
| `shouldReceive('method')` | 메서드가 호출될 것을 기대한다   |
| `once()`                  | 한 번만 호출될 것을 기대한다   |
| `times(n)`                | n번 호출될 것을 기대한다     |
| `with(args)`              | 특정 인수로 호출될 것을 기대한다 |
| `andReturn(value)`        | 지정한 값을 반환한다        |
| `andReturnNull()`         | null을 반환한다         |

## 주요 파사드 목록

자주 사용하는 파사드와 그 실체 클래스, 서비스 컨테이너의 바인딩 이름 대응표입니다.

| 파사드            | 클래스                                       | 바인딩          |
| -------------- | ----------------------------------------- | ------------ |
| `App`          | `Illuminate\Foundation\Application`       | `app`        |
| `Auth`         | `Illuminate\Auth\AuthManager`             | `auth`       |
| `Cache`        | `Illuminate\Cache\CacheManager`           | `cache`      |
| `Config`       | `Illuminate\Config\Repository`            | `config`     |
| `Cookie`       | `Illuminate\Cookie\CookieJar`             | `cookie`     |
| `Crypt`        | `Illuminate\Encryption\Encrypter`         | `encrypter`  |
| `DB`           | `Illuminate\Database\DatabaseManager`     | `db`         |
| `Event`        | `Illuminate\Events\Dispatcher`            | `events`     |
| `File`         | `Illuminate\Filesystem\Filesystem`        | `files`      |
| `Gate`         | `Illuminate\Contracts\Auth\Access\Gate`   | —            |
| `Hash`         | `Illuminate\Contracts\Hashing\Hasher`     | `hash`       |
| `Http`         | `Illuminate\Http\Client\Factory`          | —            |
| `Log`          | `Illuminate\Log\LogManager`               | `log`        |
| `Mail`         | `Illuminate\Mail\Mailer`                  | `mailer`     |
| `Notification` | `Illuminate\Notifications\ChannelManager` | —            |
| `Queue`        | `Illuminate\Queue\QueueManager`           | `queue`      |
| `RateLimiter`  | `Illuminate\Cache\RateLimiter`            | —            |
| `Redirect`     | `Illuminate\Routing\Redirector`           | `redirect`   |
| `Request`      | `Illuminate\Http\Request`                 | `request`    |
| `Route`        | `Illuminate\Routing\Router`               | `router`     |
| `Schema`       | `Illuminate\Database\Schema\Builder`      | —            |
| `Session`      | `Illuminate\Session\SessionManager`       | `session`    |
| `Storage`      | `Illuminate\Filesystem\FilesystemManager` | `filesystem` |
| `URL`          | `Illuminate\Routing\UrlGenerator`         | `url`        |
| `Validator`    | `Illuminate\Validation\Factory`           | `validator`  |
| `View`         | `Illuminate\View\Factory`                 | `view`       |

## 다음 단계

<Card title="Contracts(계약)" icon="file-contract" href="/ko/contracts">
  파사드와 짝을 이루는 Contracts의 개념과 구분 사용을 배웁니다.
</Card>


## Related topics

- [모킹](/ko/mocking.md)
- [Laravel 패키지 개발](/ko/advanced/package-development.md)
- [서비스 컨테이너](/ko/service-container.md)
- [Redis](/ko/redis.md)
- [로깅](/ko/logging.md)
