工厂

简介

什么是工厂?

服务 一样, 工厂 是自动加载的扩展,可以帮助保持代码简洁且高效,而不需要在类之间传递对象实例。

工厂在以下几点上类似于 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');

或者你也可以请求一个特定的类:

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

如果你只有 Blog\Models\UserModel,将返回实例。 但如果你同时有 App\Models\UserModelBlog\Models\UserModel, 将返回 App\Models\UserModel 的实例。

如果你想获取 Blog\Models\UserModel,你需要禁用 preferApp 选项:

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

参见 工厂选项 了解详细信息。

下次你在代码中的任何地方请求相同的类,工厂都会确保像以前一样返回该实例:

<?php

use CodeIgniter\Config\Factories;

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

        // ...
    }
}

在子目录中加载类

如果你想在子目录中加载类,可以使用 / 作为分隔符。 以下代码加载 app/Libraries/Sub/SubLib.php:

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

便利函数

为工厂提供了两个快捷函数。这些函数始终可用。

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() 返回一个新的模型类实例。唯一必需的参数是类名称:

<?php

$user = model('UserModel');

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

工厂参数

工厂 的第二个参数是一个选项值数组(如下所述)。 这些指令将覆盖为每个组件配置的默认选项。

同时传递的任何更多参数将转发到类构造函数,使你可以即时配置类实例。例如,假设你的应用使用单独的数据库进行身份验证,并且你希望确保尝试访问用户记录的任何尝试都通过该连接:

<?php

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

现在从 工厂 加载的 UserModel 每次实际上都会返回使用备用数据库连接的类实例。

工厂选项

默认行为可能不适用于每个组件。例如,假设你的组件名称及其路径不匹配,或者你需要将实例限制为某种类型的类。 每个组件都接受一组选项来指导发现和实例化。

类型

描述

默认值

component

string 或 null

组件名称(如果与静态方法不同)。这可以用于将一个组件别名到另一个。

null (默认为组件名称)

path

string 或 null

命名空间/文件夹内要查找类的相对路径。

null (默认为组件名称,但将首字母大写)

instanceOf

string 或 null

要匹配返回实例上的必需类名称。

null (无过滤)

getShared

boolean

是否返回类的共享实例或者加载一个新实例。

true

preferApp

boolean

是否优先使用 App 命名空间中具有相同基本名称的类而不是其他明确的类请求。

true

工厂行为

可以通过三种方式(按优先级降序排列)应用选项:

  • 配置类 Config\Factory,其中包含与组件名称匹配的属性。

  • 静态方法 Factories::setOptions()

  • 在调用时直接传递参数。

配置

要设置默认组件选项,请在 app/Config/Factory.php 中创建一个新的 Config 文件, 以数组属性的形式提供与组件名称匹配的选项。

示例:过滤器工厂

例如,如果你要通过工厂创建 过滤器,组件名称将是 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

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

参数选项

Factories 的魔术静态调用以选项值数组作为第二个参数。这些指令将覆盖为每个组件配置的存储选项,并可在调用时用于获得你所需的内容。输入应为以每个覆盖值为键的选项名称数组。

例如,默认情况下 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