팩토리(Factories)

소개

팩토리란 무엇인가요?

서비스(Services)와 마찬가지로, 팩토리(Factories)는 클래스 간에 객체 인스턴스를 직접 전달할 필요 없이 코드를 간결하고 최적화된 상태로 유지할 수 있게 돕는 오토로딩의 확장 기능입니다.

팩토리는 다음과 같은 점에서 CodeIgniter 3의 $this->load와 비슷합니다.

  • 클래스 로드

  • 로드된 클래스 인스턴스 공유

가장 단순하게 말하자면, 팩토리는 클래스 인스턴스를 생성하고 어디에서나 접근할 수 있는 공통된 방법을 제공합니다. 이는 객체 상태를 재사용하고 앱 전체에서 여러 인스턴스를 로드하여 발생하는 메모리 부하를 줄이는 훌륭한 방법입니다.

어떤 클래스든 팩토리를 통해 로드할 수 있지만, 공통 데이터를 작업하거나 전송하는 데 사용되는 클래스들이 가장 좋은 예입니다. 프레임워크 자체도 내부적으로 팩토리를 사용합니다. 예를 들어 Config 클래스를 사용할 때 올바른 설정이 로드되도록 보장하기 위해 사용됩니다.

서비스(Services)와의 차이점

팩토리는 인스턴스화를 위해 구체적인 클래스 이름이 필요하며, 인스턴스를 생성하기 위한 별도의 코드를 가지고 있지 않습니다.

따라서 팩토리는 많은 의존성이 필요한 복잡한 인스턴스를 생성하는 데 적합하지 않으며, 반환될 인스턴스의 클래스를 동적으로 변경할 수 없습니다.

반면, 서비스는 인스턴스를 생성하는 코드를 포함하고 있어 다른 서비스나 클래스 인스턴스가 필요한 복잡한 인스턴스를 생성할 수 있습니다. 서비스를 가져올 때는 클래스 이름이 아닌 서비스 이름이 필요하므로, 클라이언트 코드를 수정하지 않고도 반환되는 인스턴스를 변경할 수 있습니다.

클래스 로딩

클래스 로드하기

모델(Models)을 예로 들어보겠습니다. 팩토리 클래스의 매직 정적 메서드인 Factories::models()를 사용하여 모델 전용 팩토리에 접근할 수 있습니다.

이 정적 메서드 이름을 컴포넌트(component)라고 부릅니다.

네임스페이스 없이 클래스 이름 전달하기

네임스페이스 없이 클래스 이름을 전달하면, 팩토리는 먼저 App 네임스페이스에서 매직 정적 메서드 이름에 대응하는 경로를 찾습니다. 예를 들어 Factories::models()app/Models 디렉토리를 검색합니다.

짧은 클래스 이름 전달하기

다음 코드에서 App\Models\UserModel이 존재한다면 해당 인스턴스가 반환됩니다.

<?php

use CodeIgniter\Config\Factories;

$users = Factories::models('UserModel');

만약 App\Models\UserModel이 없다면 모든 네임스페이스에서 Models\UserModel을 검색합니다.

코드의 다른 곳에서 동일한 클래스를 다시 요청하면, 팩토리는 이전과 동일한 인스턴스를 반환하도록 보장합니다.

<?php

use CodeIgniter\Config\Factories;

class SomeOtherClass
{
    public function someFunction()
    {
        $users = Factories::models('UserModel');

        // ...
    }
}
하위 디렉토리를 포함한 짧은 클래스 이름 전달

하위 디렉토리에 있는 클래스를 로드하려면 /를 구분자로 사용합니다. 다음 코드는 app/Libraries/Sub/SubLib.php가 존재할 경우 이를 로드합니다.

use CodeIgniter\Config\Factories;

$lib = Factories::libraries('Sub/SubLib');

전체 경로 네임스페이스(Fully Qualified Classname) 전달

전체 경로 네임스페이스를 사용하여 요청할 수도 있습니다.

use CodeIgniter\Config\Factories;

$users = Factories::models('Blog\Models\UserModel');
// Or
$users = Factories::models(\Blog\Models\UserModel::class);

BlogModelsUserModel이 존재하면 해당 인스턴스를 반환합니다.

참고

v4.4.0 이전에는 전체 네임스페이스로 요청했을 때, BlogModelsUserModel만 있다면 해당 인스턴스가 반환되었지만, AppModelsUserModel과 BlogModelsUserModel이 둘 다 있다면 AppModelsUserModel의 인스턴스가 반환되었습니다.

이 경우 BlogModelsUserModel을 가져오려면 preferApp 옵션을 비활성화해야 했습니다.

use CodeIgniter\Config\Factories;

$users = Factories::models('Blog\Models\UserModel', ['preferApp' => false]);

편의 함수

팩토리를 위한 두 가지 단축 함수가 제공됩니다. 이 함수들은 언제나 사용 가능합니다.

config()

첫 번째는 config()로, Config 클래스의 새 인스턴스를 반환합니다. 유일한 필수 매개변수는 클래스 이름입니다:

<?php

$appConfig = config('App');

// The code above is the same as the code below.
$appConfig = \CodeIgniter\Config\Factories::config('App');

model()

두 번째 함수인 model()은 Model 클래스의 새 인스턴스를 반환합니다. 유일한 필수 매개변수는 클래스 이름입니다:

<?php

$user = model('UserModel');

// The code above is the same as the code below.
$user = \CodeIgniter\Config\Factories::models('UserModel');

로드할 클래스 이름 정의

Added in version 4.4.0.

Factories::define() 메서드를 사용하면 클래스를 로드하기 전에 로드할 클래스 이름을 정의할 수 있습니다:

use CodeIgniter\Config\Factories;

Factories::define('models', 'Myth\Auth\Models\UserModel', 'App\Models\UserModel');

첫 번째 매개변수는 컴포넌트입니다. 두 번째 매개변수는 클래스 별칭(팩토리 매직 정적 메서드의 첫 번째 매개변수)이고, 세 번째 매개변수는 로드할 실제 전체 경로 클래스 이름입니다.

After that, if you load Myth\Auth\Models\UserModel with Factories, the App\Models\UserModel instance will be returned:

$users = model('Myth\Auth\Models\UserModel');

팩토리 매개변수

Factories는 두 번째 매개변수로 옵션 값의 배열을 받습니다(아래 설명 참조). 이 지시문은 각 컴포넌트에 대해 구성된 기본 옵션을 재정의합니다.

동시에 전달된 추가 매개변수는 클래스 생성자로 전달되므로, 클래스 인스턴스를 즉석에서 구성하기 쉽습니다. 예를 들어, 앱이 인증을 위해 별도의 데이터베이스를 사용하고 사용자 레코드 접근이 항상 해당 연결을 통해 이루어지도록 하려는 경우:

<?php

use CodeIgniter\Config\Factories;

$conn  = db_connect('auth');
$users = Factories::models('UserModel', [], $conn);

이제 Factories에서 UserModel을 로드할 때마다 실제로는 대체 데이터베이스 연결을 사용하는 클래스 인스턴스가 반환됩니다.

Factories Options

기본 동작이 모든 컴포넌트에 적합하지 않을 수 있습니다. 예를 들어 컴포넌트 이름과 경로가 일치하지 않거나 인스턴스를 특정 클래스 유형으로 제한해야 하는 경우입니다. 각 컴포넌트는 검색 및 인스턴스화를 지시하기 위한 옵션 집합을 받습니다.

유형

설명

기본값

component

문자열 또는 null

컴포넌트 이름(정적 메서드와 다를 경우)입니다. 한 컴포넌트를 다른 컴포넌트의 별칭으로 사용할 때 활용할 수 있습니다.

null (component 이름으로 기본값 설정)

경로

문자열 또는 null

네임스페이스/폴더 내에서 클래스를 찾을 상대 경로입니다.

null (기본값은 컴포넌트 이름이지만 첫 번째 문자를 대문자로 만듦)

instanceOf

문자열 또는 null

반환된 인스턴스와 일치해야 하는 필수 클래스 이름입니다.

null (필터링 없음)

getShared

boolean

클래스의 공유 인스턴스를 반환할지 또는 새 인스턴스를 로드할지 여부입니다.

true

preferApp

boolean

App 네임스페이스에서 동일한 기본 이름을 가진 클래스가 다른 명시적 클래스 요청을 재정의할지 여부입니다.

true

참고

v4.4.0부터 preferApp네임스페이스 없이 클래스 이름을 요청할 때만 작동합니다.

Factories Behavior

옵션은 다음 세 가지 방법 중 하나로 적용할 수 있습니다(우선순위 오름차순):

  • 컴포넌트 이름과 일치하는 속성을 가진 설정 클래스 Config\Factory입니다.

  • 정적 메서드 Factories::setOptions()입니다.

  • 호출 시 매개변수로 옵션을 직접 전달합니다.

구성

기본 컴포넌트 옵션을 설정하려면 app/Config/Factory.php에 컴포넌트 이름과 일치하는 배열 속성으로 옵션을 제공하는 새 Config 파일을 생성하세요.

예: 필터 팩토리

예를 들어 팩토리로 필터(Filters)를 생성하려면 컴포넌트 이름은 filters가 됩니다. 각 필터가 CodeIgniter의 FilterInterface를 구현하는 클래스의 인스턴스인지 확인하려면 app/Config/Factory.php 파일이 다음과 같을 수 있습니다:

<?php

namespace Config;

use CodeIgniter\Config\Factory as BaseFactory;
use CodeIgniter\Filters\FilterInterface;

class Factory extends BaseFactory
{
    public $filters = [
        'instanceOf' => FilterInterface::class,
    ];
}

이제 Factories::filters('SomeFilter')와 같은 코드로 필터를 생성할 수 있으며, 반환된 인스턴스는 반드시 CodeIgniter 필터가 됩니다.

이는 우연히 네임스페이스에 관련 없는 Filters 경로를 가진 서드파티 모듈과의 충돌을 방지합니다.

Example: Library Factories

Factories::library('SomeLib')app/Libraries 디렉토리의 라이브러리 클래스를 로드하려면, 경로 Libraries가 기본 경로 Library와 다릅니다.

이 경우 app/Config/Factory.php 파일은 다음과 같습니다:

<?php

namespace Config;

use CodeIgniter\Config\Factory as BaseFactory;

class Factory extends BaseFactory
{
    public $library = [
        'path' => 'Libraries',
    ];
}

이제 Factories::library() 메서드로 라이브러리를 로드할 수 있습니다:

use CodeIgniter\Config\Factories;

$someLib = Factories::library('SomeLib');

setOptions 메서드

Factories 클래스에는 런타임 옵션 구성을 허용하는 정적 메서드가 있습니다. setOptions() 메서드에 원하는 옵션 배열을 제공하면 기본값과 병합되어 다음 호출을 위해 저장됩니다:

<?php

use CodeIgniter\Config\Factories;
use CodeIgniter\Filters\FilterInterface;

Factories::setOptions('filters', [
    'instanceOf' => FilterInterface::class,
    'prefersApp' => false,
]);

매개변수 옵션

Factories의 매직 정적 호출은 두 번째 매개변수로 옵션 값의 배열을 받습니다. 이 지시문은 각 컴포넌트에 대해 구성된 저장된 옵션을 재정의하며, 정확히 필요한 것을 얻기 위해 호출 시 사용할 수 있습니다. 입력은 각 재정의 값의 키로 옵션 이름이 있는 배열이어야 합니다.

예를 들어 기본적으로 Factories는 컴포넌트의 공유 인스턴스를 찾으려 한다고 가정합니다. 매직 정적 호출에 두 번째 매개변수를 추가하면 해당 단일 호출이 새 인스턴스 또는 공유 인스턴스를 반환할지 제어할 수 있습니다:

use CodeIgniter\Config\Factories;

$users = Factories::models('UserModel', ['getShared' => true]);  // Default; will always be the same instance
$other = Factories::models('UserModel', ['getShared' => false]); // Will always create a new instance

Config Caching

Added in version 4.4.0.

중요

이 섹션을 주의 깊게 읽고 이 기능의 작동 방식을 이해하지 않는 한 이 기능을 사용하지 마십시오. 그렇지 않으면 애플리케이션이 제대로 작동하지 않을 수 있습니다.

성능 향상을 위해 설정 캐싱(Config Caching)이 구현되었습니다.

전제 조건

중요

전제 조건이 충족되지 않은 상태에서 이 기능을 사용하면 CodeIgniter가 정상적으로 작동하지 않을 수 있습니다. 그런 경우에는 이 기능을 사용하지 마십시오.

  • 이 기능을 사용하려면 팩토리에서 인스턴스화된 모든 설정(Config) 객체의 속성이 인스턴스화 후에 수정되지 않아야 합니다. 다시 말해, 설정 클래스는 불변(immutable)이거나 읽기 전용(readonly) 클래스여야 합니다.

  • 기본적으로 캐시되는 모든 설정 클래스는 __set_state() 메서드를 구현해야 합니다.

작동 방식

중요

한번 캐시되면 설정 파일이나 .env가 변경되더라도 캐시를 삭제하기 전까지 설정 값은 절대로 변경되지 않습니다.

  • 종료(shutdown) 전, 팩토리에 있는 설정 인스턴스의 상태가 변경되었다면 모든 설정 인스턴스를 캐시 파일에 저장합니다.

  • 캐시가 있는 경우 CodeIgniter 초기화 전에 캐시된 설정 인스턴스들을 복원합니다.

간단히 말해, 팩토리가 보유한 모든 설정 인스턴스는 종료 직전에 캐시되며, 캐시된 인스턴스들은 영구적으로 사용됩니다.

설정 값 업데이트 방법

저장된 캐시 버전은 절대 만료되지 않습니다. 기존 설정 파일을 변경하거나 관련 환경 변수를 변경해도 캐시나 설정 값은 업데이트되지 않습니다.

따라서 설정 값을 업데이트하고 싶다면 설정 파일이나 환경 변수를 수정한 후, 수동으로 캐시 파일을 삭제해야 합니다.

spark cache:clear 명령을 사용할 수 있습니다.

php spark cache:clear

또는 단순히 writable/cache/FactoriesCache_config 파일을 삭제하십시오.

참고

v4.5.0부터 spark optimize 명령은 캐시를 지웁니다.

설정 캐싱 활성화 방법

Added in version 4.5.0.

app/Config/Optimize.php에서 다음 속성을 true로 설정하십시오:

public bool $configCacheEnabled = true;

또는 spark optimize 명령으로 활성화할 수 있습니다.

참고

이 속성은 환경 변수에 의해 오버라이드될 수 없습니다.

경고

워커 모드(Worker Mode)에서 앱을 실행할 때는 이 옵션을 사용하지 마십시오.