며칠 전 불안정한 테스트를 수정하던 중 공장 내에서 고유하고 유효한 값이 필요하다는 사실이 밝혀졌습니다. Laravel은 일반적으로 fake() 도우미를 통해 액세스하는 FakerPHP를 래핑합니다. FakerPHP에는 valid() 및 Unique()와 같은 수정자가 포함되어 있지만 한 번에 하나씩만 사용할 수 있으므로 fake()->unique()->valid()를 수행할 수 없습니다. 필요합니다. 이로 인해 우리 자신만의 수정자를 만들고 싶다면 어떨까 하는 생각이 들었습니다. 예를 들어, UniqueAndValid() 또는 기타 수정자입니다. 어떻게 프레임워크를 확장할 수 있나요?
생각의 기차를 버리겠습니다.
과도하게 엔지니어링된 솔루션을 시작하기 전에 항상 더 간단한 옵션이 있는지 확인하고 내가 다루고 있는 내용을 이해하고 싶습니다. 이제 fake() 도우미를 살펴보겠습니다.
function fake($locale = null) { if (app()->bound('config')) { $locale ??= app('config')->get('app.faker_locale'); } $locale ??= 'en_US'; $abstract = \Faker\Generator::class.':'.$locale; if (! app()->bound($abstract)) { app()->singleton($abstract, fn () => \Faker\Factory::create($locale)); } return app()->make($abstract); }
코드를 읽어보면 Laravel이 싱글톤을 컨테이너에 바인딩하는 것을 볼 수 있습니다. 그러나 추상을 살펴보면 인터페이스를 구현하지 않는 일반 클래스이며 개체는 팩토리를 통해 생성됩니다. 이것은 상황을 복잡하게 만듭니다. 왜요?
솔루션 ?? "1번 항목에 설명된 대로 새 발전기를 반환하는 자체 공장을 만드는 것을 방해하는 것이 무엇입니까?"라고 생각할 수도 있습니다. 글쎄요, 우리는 그렇게 할 수 있지만 그렇게 하지 않을 것입니다! 우리는 여러 가지 이유로 프레임워크를 사용하는데 그 중 하나가 업데이트입니다. FakerPHP가 새로운 공급자를 추가하거나 대규모 업그레이드를 하면 어떻게 되나요? Laravel은 코드를 조정할 것이며, 변경 사항을 적용하지 않은 사람들은 아무 것도 눈치 채지 못할 것입니다. 그러나 우리는 제외될 것이며 코드가 깨질 수도 있습니다(아마도). 그렇습니다. 우리는 그렇게까지 가고 싶지 않습니다.
이제 기본 옵션을 살펴봤으므로 디자인 패턴과 같은 고급 옵션을 생각해 볼 수 있습니다. 정확한 구현이 필요하지 않으며 문제에 익숙한 것이 필요합니다. 이것이 바로 제가 항상 그들을 아는 것이 좋다고 말하는 이유입니다. 이 경우 기존 기능을 유지하면서 새로운 기능을 추가하여 Generator 클래스를 "장식"할 수 있습니다. 좋은 것 같나요? 방법을 살펴보겠습니다!
먼저 새 클래스인 FakerGenerator를 만들어 보겠습니다.
function fake($locale = null) { if (app()->bound('config')) { $locale ??= app('config')->get('app.faker_locale'); } $locale ??= 'en_US'; $abstract = \Faker\Generator::class.':'.$locale; if (! app()->bound($abstract)) { app()->singleton($abstract, fn () => \Faker\Factory::create($locale)); } return app()->make($abstract); }
이것이 우리의 "데코레이터"가 될 것입니다. 기본 생성기를 종속성으로 예상하고 고유한 수정자(uniqueAndValid())를 도입하는 간단한 클래스입니다. 또한 Laravel의 ForwardsCalls 특성을 사용하여 기본 개체에 대한 호출을 프록시할 수 있습니다.
이 특성에는 두 개의 메소드(forwardCallTo 및forwardDecoratedCallTo)가 있습니다. 데코레이팅된 개체에 메서드를 연결하려면 후자를 사용하세요. 우리의 경우 항상 한 통의 전화만 받습니다.
맞춤 수정자인 UniqueAndValidGenerator도 구현해야 하지만 이것이 기사의 요점은 아닙니다. 구현에 관심이 있다면 이 클래스는 기본적으로 FakerPHP와 함께 제공되는 ValidGenerator와 UniqueGenerator가 혼합된 클래스이므로 여기에서 찾을 수 있습니다.
이제 AppServiceProvider에서 프레임워크를 확장해 보겠습니다.
<?php namespace App\Support; use Closure; use Faker\Generator; use Illuminate\Support\Traits\ForwardsCalls; class FakerGenerator { use ForwardsCalls; public function __construct(private readonly Generator $generator) { } public function uniqueAndValid(Closure $validator = null): UniqueAndValidGenerator { return new UniqueAndValidGenerator($this->generator, $validator); } public function __call($method, $parameters): mixed { return $this->forwardCallTo($this->generator, $method, $parameters); } }
extend() 메소드는 주어진 이름과 일치하는 추상이 컨테이너에 바인딩되었는지 확인합니다. 그렇다면 클로저 결과로 해당 값을 재정의합니다. 다음을 살펴보세요.
<?php namespace App\Providers; use Closure; use Faker\Generator; use App\Support\FakerGenerator; use Illuminate\Support\ServiceProvider; class AppServiceProvider extends ServiceProvider { public function register(): void { $this->app->extend( $this->fakerAbstractName(), fn (Generator $base) => new FakerGenerator($base) ); } private function fakerAbstractName(): string { // This is important, it matches the name bound by the fake() helper return Generator::class . ':' . app('config')->get('app.faker_locale'); } }
이것이 바로 우리가 fake() 도우미가 컨테이너에 바인딩하는 것과 동일한 이름을 생성하는 fakerAbstractName() 메서드를 정의한 이유입니다.
위 코드를 놓치신 분들은 다시 확인하시고 댓글 남겨두었습니다.
이제 fake()를 호출할 때마다 FakerGenerator의 인스턴스가 반환되고 우리가 도입한 맞춤 수정자에 액세스할 수 있습니다. FakerGenerator 클래스에 존재하지 않는 호출을 호출할 때마다 __call()이 트리거되고 이를 전달CallTo() 메서드를 사용하여 기본 생성기로 프록시합니다.
그렇습니다! 마침내 fake()->uniqueAndValid()->randomElement()를 수행할 수 있게 되었는데 정말 매력적이네요!
결론을 내리기 전에 이것이 순수한 데코레이터 패턴이 아니라는 점을 지적하고 싶습니다. 그러나 패턴은 신성한 텍스트가 아닙니다. 필요에 맞게 조정하고 문제를 해결하세요.
Frameworks는 매우 유용하며 Laravel에는 많은 기능이 내장되어 있습니다. 그러나 프로젝트의 모든 극단적인 경우를 다룰 수는 없으며 때로는 막다른 골목에 부딪힐 수도 있습니다. 그런 일이 발생하면 언제든지 프레임워크를 확장할 수 있습니다. 우리는 이것이 얼마나 간단한지 살펴보았습니다. 이 Faker 예시를 넘어 적용되는 주요 아이디어를 이해하셨기를 바랍니다.
항상 단순하게 시작하고 문제에 대한 가장 간단한 해결책을 찾으세요. 필요할 때 복잡성이 발생하므로 기본 상속이 트릭을 수행하는 경우 데코레이터나 다른 것을 구현할 필요가 없습니다. 프레임워크를 확장할 때 손실이 이득보다 더 커지는 너무 멀리 가지 않도록 하십시오. 프레임워크의 일부를 스스로 유지 관리하고 싶지는 않을 것입니다.
위 내용은 Laravel Under The Hood - 프레임워크 확장의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!