Laravel 로 개발을 하다 보면 Facade, Singleton, Alias 라는 용어를 접할수 있게 되는데 Facade 를 공부하다보면 Alias 는 뭐지 궁금하기도하고 Singleton 을 공부하고나면 Facade 와 무슨 차이인지 궁금해질수도 있다. (Facade 도 하나의 request 생명주기 동안 static 하게 전역적으로 값을 관리할수 있기 때문)
오늘은 각 개념의 의미, 차이점, 그리고 언제 어떻게 사용하는 것이 좋은지 알아보려고 한다.
Facade란?
Facade는 복잡한 라이브러리의 기능을 간단한 인터페이스로 사용할 수 있게 해주는 디자인 패턴입니다. Laravel에서 Facade는 서비스 컨테이너에 바인딩된 객체에 대한 "정적" 인터페이스를 제공
Facade의 특징
- 서비스 컨테이너의 객체에 대한 프록시 역할
- 정적 메서드 호출처럼 보이지만 실제로는 동적 객체의 메서드를 호출
Facade 작동원리
아래는 Laravel 에서 제공해주는 Facade 추상 클래스
abstract class Facade
{
protected static $app;
protected static $resolvedInstance;
public static function __callStatic($method, $args)
{
$instance = static::getFacadeRoot();
return $instance->$method(...$args);
}
public static function getFacadeRoot()
{
return static::resolveFacadeInstance(static::getFacadeAccessor());
}
protected static function getFacadeAccessor()
{
throw new RuntimeException('Facade does not implement getFacadeAccessor method.');
}
protected static function resolveFacadeInstance($name)
{
if (isset(static::$resolvedInstance[$name])) {
return static::$resolvedInstance[$name];
}
if (static::$app) {
return static::$resolvedInstance[$name] = static::$app[$name];
}
}
}
Facade 는 다음과 같이 동작한다.
- __callStatic 매직 메소드가 정적 호출을 가로챔
- getFacadeRoot는 실제 객체 인스턴스를 가져옴
- getFacadeAccessor는 각 Facade 하위 클래스에서 구현되며, 서비스 컨테이너에 등록되어있는 key를 반환. (getFacadeAccessor를 구현하는 메소드에서 서비스 컨테이너에 등록되어 있는 key 를 명시하자)
- resolveFacadeInstance는 서비스 컨테이너에서 실제 객체를 해결하고 캐시.
- 마지막으로, 해결된 객체의 메소드가 호출되고 결과가 반환.
이 메커니즘을 통해 Facade는 정적 호출을 동적 객체의 메소드 호출로 전달하는 프록시 역할을 수행.
Singleton이란?
Singleton은 클래스의 인스턴스가 하나만 생성되도록 보장하는 디자인 패턴. Laravel의 서비스 컨테이너에서는 singleton 메서드를 통해 이를 구현.
Singleton의 특징
- 애플리케이션 전체에서 하나의 인스턴스만 공유
- 리소스를 효율적으로 사용
- 전역 상태를 관리하는 데 유용
// AppServiceProvider.php
public function register()
{
$this->app->singleton('HeavyService', function ($app) {
return new HeavyService($app['config'], $app['db']);
});
}
// 사용
$service = app('HeavyService');
Alias란?
Alias는 클래스에 다른 이름을 부여하는 PHP의 기능. Laravel에서는 주로 긴 네임스페이스를 가진 클래스를 짧은 이름으로 사용할 수 있게 해줌.
Alias의 특징
- class_alias() 함수를 사용하여 구현
- 주로 config/app.php의 aliases 배열에서 정의
- IDE 자동완성이 제대로 작동하지 않을 수 있음
// config/app.php
'aliases' => [
'Cache' => Illuminate\Support\Facades\Cache::class,
]
// 사용
Cache::get('key');
Facade 가 config/app.php 에 'aliases' 에 등록되어 있는걸 볼수 있는데 이 때문에 Facade 를 무조건 alias 로 등록해야 하는건가? 혹은 왜 해야하는건지 궁금했었다.
결론은 굳이 할 필요는 없다.
위에서 살펴봤듯이 Facade와 Alias는 비슷해 보이지만 목적과 구현 방식이 다르다.
- Facade는 서비스 컨테이너의 객체에 대한 프록시 역할을 하는 클래스.
- Alias는 기존 클래스에 대한 단순한 이름 변경.
실제 예시로 비교하기
이제 실제 코드를 통해 Facade와 Alias의 차이를 살펴보자.
1. 클래스 생성
<?php
namespace App\Services;
class ClassForAlias
{
public function check()
{
return 'classForAlias';
}
}
<?php
namespace App\Services;
class ClassForFacade
{
public function check()
{
return 'classForFacade';
}
}
2. Alias 등록
'CustomAlias' => App\Services\ClassForAlias::class,
3. 서비스 프로바이더에 바인딩 (Facade용)
$this->app->bind('custom-facade', function ($app) {
return new \App\Services\ClassForFacade();
});
4. Facade 생성
<?php
namespace App\Facades;
use Illuminate\Support\Facades\Facade;
class CustomFacade extends Facade
{
protected static function getFacadeAccessor()
{
return 'custom-facade';
}
}
5. 비교
// Alias 사용
$customAlias = \CustomAlias::check();
// Facade 사용
$customFacade = CustomFacade::check();
dd([
'(Alias)' => [
'check' => $customAlias, // classForAlias
],
'(Facade)' => [
'check' => $customFacade, // classForFacade
]
]);
Facade 를 좀더 편리하게 사용하기위해 alias 를 사용하는 것이지. 꼭 alias 를 사용할 필욘없다.
Facade 사용이 적합한 경우
간단하고 자주 사용되는 경우
Log::info('User logged in');
정적 메서드 스타일의 간결한 구문이 필요한 경우
Response::json(['status' => 'success']);
Singleton 사용이 적합한 경우
복잡한 의존성이 있는 서비스
$this->app->singleton('ComplexService', function ($app) {
return new ComplexService(
$app->make('Database'),
$app->make('ApiClient'),
$app->make('Logger')
);
});
명시적인 의존성 주입이 필요한 경우
class UserService
{
public function __construct(ComplexService $service)
{
$this->service = $service;
}
}
설정이 필요한 서비스
$this->app->singleton('ConfigurableService', function ($app) {
$service = new ConfigurableService();
$service->setConfig($app['config']['service']);
return $service;
});
Alias 사용이 적합한 경우
- 긴 네임스페이스를 간단하게 사용하고 싶을 때
- 프레임워크의 기본 클래스들에 쉽게 접근하고 싶을 때
'IT > 라라벨' 카테고리의 다른 글
[Laravel] Laravel 에서 middleware 는 어떻게 동작하는가 (0) | 2024.09.17 |
---|---|
[laravel] Laravel 의 중첩 트랜잭션 관리기법 (0) | 2024.07.01 |
[laravel] 유니코드 정규화 패키지 (0) | 2024.03.07 |
[laravel] 라라벨 여러 row 한번에 업데이트 하는 법 mass update (0) | 2024.01.10 |
[Laravel] passport 인증 실패 익셉션 발생시 Authoization header 를 날림 (0) | 2023.09.30 |