ファクトリー

はじめに

ファクトリーとは?

サービスと同様に、**ファクトリー**はオートローディングの拡張機能であり、クラス間でオブジェクトインスタンスを渡すことなく、コードを簡潔かつ最適に保つのに役立ちます。

ファクトリーは、以下の点で CodeIgniter 3 の $this->load に似ています。

  • クラスを読み込む

  • 読み込まれたクラスインスタンスを共有する

最も単純な場合、ファクトリーはクラスインスタンスを作成し、どこからでもアクセスするための共通の方法を提供します。これは、オブジェクトの状態を再利用し、アプリケーション全体に複数のインスタンスを読み込んでおくことによるメモリ負荷を削減するのに最適な方法です。

ファクトリーではどのクラスでも読み込むことができますが、最適な例は、共通データを操作または送信するために使用されるクラスです。フレームワーク自体は内部的にファクトリーを使用しています。たとえば、Config クラスを使用するときに正しい設定が読み込まれるようにするためです。

サービスとの違い

ファクトリーは、インスタンス化するために具体的なクラス名を必要とし、インスタンスを作成するためのコードを持ちません。

そのため、ファクトリーは、多くの依存関係を必要とする複雑なインスタンスを作成するのには適しておらず、返されるインスタンスのクラスを変更することはできません。

一方、サービスはインスタンスを作成するためのコードを持っているため、他のサービスやクラスインスタンスを必要とする複雑なインスタンスを作成できます。サービスを取得する場合、サービスはクラス名ではなくサービス名を必要とするため、クライアントコードを変更せずに返されるインスタンスを変更できます。

クラスの読み込み

クラスの読み込み

例として**モデル**を見てみましょう。 `Factories` クラスのマジック静的メソッドである Factories::models() を使用することで、モデル専用のファクトリーにアクセスできます。

静的メソッド名は*コンポーネント*と呼ばれます。

名前空間のないクラス名の受け渡し

名前空間のないクラス名を渡すと、ファクトリーはまず 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');

完全修飾クラス名の受け渡し

完全修飾クラス名を要求することもできます。

use CodeIgniter\Config\Factories;

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

Blog\Models\UserModel が存在する場合、そのインスタンスが返されます。

注意

v4.4.0 より前では、完全修飾クラス名を要求した場合、Blog\Models\UserModel のみが存在する場合、そのインスタンスが返されていました。ただし、App\Models\UserModelBlog\Models\UserModel の両方がある場合、App\Models\UserModel のインスタンスが返されていました。

Blog\Models\UserModel を取得するには、オプション preferApp を無効にする必要がありました。

use CodeIgniter\Config\Factories;

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

便利な関数

ファクトリー用の2つのショートカット関数が提供されています。これらの関数は常に使用できます。

config()

1つ目は、config() で、設定クラスの新しいインスタンスを返します。必要なパラメータはクラス名のみです。

<?php

$appConfig = config('App');

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

model()

2つ目の関数 model() は、モデルクラスの新しいインスタンスを返します。必要なパラメータはクラス名のみです。

<?php

$user = model('UserModel');

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

読み込むクラス名の定義

バージョン 4.4.0 での新機能。

Factories::define() メソッドを使用してクラスを読み込む前に、読み込むクラス名を定義できます。

use CodeIgniter\Config\Factories;

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

最初のパラメータはコンポーネントです。2つ目のパラメータはクラスエイリアス(ファクトリーのマジック静的メソッドの最初のパラメータ)、3つ目のパラメータは読み込む真の完全修飾クラス名です。

その後、ファクトリーで Myth\Auth\Models\UserModel を読み込むと、App\Models\UserModel インスタンスが返されます。

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

ファクトリーパラメータ

Factories は、2番目のパラメータとしてオプション値の配列(下記参照)を取ります。これらのディレクティブは、各コンポーネントに設定されているデフォルトオプションをオーバーライドします。

同時に渡されるその他のパラメータは、クラスコンストラクタに転送され、クラスインスタンスをオンザフライで簡単に設定できます。たとえば、アプリケーションが認証に別のデータベースを使用していて、ユーザーレコードにアクセスしようとする試みが常にその接続を経由するようにしたいとします。

<?php

use CodeIgniter\Config\Factories;

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

これで、UserModelFactories からロードされるたびに、実際には代替データベース接続を使用するクラスインスタンスが返されます。

ファクトリオプション

デフォルトの動作は、すべてのコンポーネントで機能するとは限りません。たとえば、コンポーネント名とそのパスが一致しない場合や、インスタンスを特定の種類のクラスに制限する必要がある場合があります。各コンポーネントは、検出とインスタンス化を指示するための一連のオプションを受け取ります。

キー

タイプ

説明

デフォルト

component

文字列またはnull

コンポーネントの名前(静的メソッドと異なる場合)。これは、あるコンポーネントを別のコンポーネントにエイリアスするために使用できます。

null (デフォルトはコンポーネント名)

path

文字列またはnull

クラスを探す名前空間/フォルダ内の相対パス。

null (デフォルトはコンポーネント名ですが、最初の文字は大文字になります)

instanceOf

文字列またはnull

返されたインスタンスで一致する必要がある必須のクラス名。

null (フィルタリングなし)

getShared

ブール値

クラスの共有インスタンスを返すか、新しいインスタンスをロードするか。

true

preferApp

ブール値

App名前空間内の同じベース名を持つクラスが、他の明示的なクラス要求をオーバーライドするかどうか。

true

注意

v4.4.0以降、preferApp は、名前空間のないクラス名を要求した場合にのみ機能します。

ファクトリの動作

オプションは、次の3つの方法のいずれかで適用できます(優先順位の昇順でリストされています)

  • コンポーネントの名前と一致するプロパティを持つ設定クラス Config\Factory

  • 静的メソッド Factories::setOptions()

  • パラメータを使用して、呼び出し時にオプションを直接渡します。

設定

デフォルトのコンポーネントオプションを設定するには、コンポーネントの名前と一致する配列プロパティとしてオプションを提供する**app/Config/Factory.php**に新しい設定ファイルを作成します。

例:フィルターファクトリ

たとえば、ファクトリによって**フィルター**を作成する場合、コンポーネント名は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パスを持つサードパーティモジュールの競合を防ぎます。

例:ライブラリファクトリ

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のマジック静的呼び出しは、2番目のパラメータとしてオプション値の配列を取ります。 これらのディレクティブは、各コンポーネントに設定されている保存済みオプションをオーバーライドし、呼び出し時に使用して必要なものを正確に取得できます。入力は、オプション名を各オーバーライド値のキーとする配列である必要があります。

たとえば、デフォルトでは、Factoriesは、コンポーネントの共有インスタンスを見つけたいと想定しています。 マジック静的呼び出しに2番目のパラメータを追加することにより、その単一の呼び出しが新しいインスタンスを返すか、共有インスタンスを返すかを制御できます。

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

設定キャッシュ

バージョン 4.4.0 での新機能。

パフォーマンスを向上させるために、設定キャッシュが実装されました。

前提条件

重要

前提条件が満たされていない場合にこの機能を使用すると、CodeIgniterが正しく動作しなくなります。そのような場合は、この機能を使用しないでください。

  • この機能を使用するには、ファクトリでインスタンス化されたすべての設定オブジェクトのプロパティを、インスタンス化後に変更しないでください。言い換えれば、設定クラスは不変または読み取り専用のクラスである必要があります。

  • デフォルトでは、キャッシュされるすべての設定クラスは、__set_state()メソッドを実装する必要があります。

仕組み

  • ファクトリの設定インスタンスの状態が変化した場合、シャットダウンする前に、ファクトリ内のすべて設定インスタンスをキャッシュファイルに保存します。

  • キャッシュが利用可能な場合、CodeIgniterの初期化前にキャッシュされた設定インスタンスを復元します。

簡単に言うと、ファクトリによって保持されているすべて設定インスタンスは、シャットダウンの直前にキャッシュされ、キャッシュされたインスタンスは永続的に使用されます。

設定値を更新する方法

保存されると、キャッシュされたバージョンは期限切れになりません。既存の設定ファイルを変更する(またはその環境変数を変更する)だけでは、キャッシュも設定値も更新されません。

設定値を更新する場合は、設定ファイルまたは環境変数を更新し、キャッシュファイルをmanuallyに削除する必要があります。

spark cache:clearコマンドを使用できます。

php spark cache:clear

または、単に**writable/cache/FactoriesCache_config**ファイルを削除します。

設定キャッシュを有効にする方法

**public/index.php**の次のコードのコメントを解除します。

--- a/public/index.php
+++ b/public/index.php
@@ -49,8 +49,8 @@ if (! defined('ENVIRONMENT')) {
 }

 // Load Config Cache
-// $factoriesCache = new \CodeIgniter\Cache\FactoriesCache();
-// $factoriesCache->load('config');
+$factoriesCache = new \CodeIgniter\Cache\FactoriesCache();
+$factoriesCache->load('config');
 // ^^^ Uncomment these lines if you want to use Config Caching.

 /*
@@ -79,7 +79,7 @@ $app->setContext($context);
 $app->run();

 // Save Config Cache
-// $factoriesCache->save('config');
+$factoriesCache->save('config');
 // ^^^ Uncomment this line if you want to use Config Caching.

 // Exits the application, setting the exit code for CLI-based applications