工厂

介绍

什么是工厂?

服务 一样,工厂 是自动加载的扩展,它有助于保持代码简洁且优化,而无需在类之间传递对象实例。

工厂类似于 CodeIgniter 3 中的 $this->load,在以下方面:

  • 加载类

  • 共享加载的类实例

简单来说,工厂提供了一种通用方法来创建类实例并从任何地方访问它。这是一种在整个应用程序中重用对象状态并减少内存负载(避免加载多个实例)的好方法。

任何类都可以由工厂加载,但最好的例子是那些用于处理或传输公共数据的类。框架本身在内部使用工厂,例如,确保在使用 Config 类时加载正确的配置。

与服务的区别

工厂需要一个具体的类名来实例化,并且没有创建实例的代码。

因此,工厂不适合创建需要许多依赖项的复杂实例,并且您无法更改要返回的实例的类。

另一方面,服务有创建实例的代码,因此它可以创建需要其他服务或类实例的复杂实例。当您获取服务时,服务需要一个服务名称,而不是一个类名,因此返回的实例可以在不更改客户端代码的情况下更改。

加载类

加载类

以 **模型** 为例。您可以使用工厂类的魔术静态方法 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]);

便捷函数

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

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');

定义要加载的类名

版本 4.4.0 中新增。

您可以使用 Factories::define() 方法在加载类之前定义要加载的类名。

use CodeIgniter\Config\Factories;

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

第一个参数是组件。第二个参数是类别名(Factories 魔术静态方法的第一个参数),第三个参数是要加载的真实完整限定类名。

之后,如果您使用 Factories 加载 Myth\Auth\Models\UserModel,则将返回 App\Models\UserModel 实例。

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

工厂参数

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

同时传递的任何其他参数都将转发到类构造函数,从而可以轻松地即时配置您的类实例。例如,假设您的应用程序使用单独的数据库进行身份验证,并且您希望确保任何尝试访问用户记录的操作始终通过该连接进行。

<?php

use CodeIgniter\Config\Factories;

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

现在,无论何时从 Factories 加载 UserModel,它实际上都会返回使用备用数据库连接的类实例。

工厂选项

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

类型

描述

默认值

component

字符串或 null

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

null(默认为组件名称)

path

字符串或 null

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

null(默认为组件名称,但将第一个字符大写)

instanceOf

字符串或 null

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

null(不进行过滤)

getShared

boolean

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

true

preferApp

boolean

是否在 App 命名空间中具有相同基本名称的类会覆盖其他显式类请求。

true

注意

从 v4.4.0 开始,preferApp 仅在您请求 没有命名空间的类名 时有效。

工厂行为

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

  • 一个配置类 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

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

配置缓存

版本 4.4.0 中新增。

为了提高性能,已实现配置缓存。

先决条件

重要

在未满足先决条件的情况下使用此功能将阻止 CodeIgniter 正确运行。在这种情况下不要使用此功能。

  • 要使用此功能,在工厂中实例化的所有配置对象的属性在实例化后不得修改。换句话说,配置类必须是不可变或只读类。

  • 默认情况下,每个缓存的配置类都必须实现 __set_state() 方法。

工作原理

  • 如果工厂中配置实例的状态发生变化,则在关闭之前将所有工厂中的配置实例保存到缓存文件中。

  • 如果缓存可用,则在 CodeIgniter 初始化之前恢复缓存的 Config 实例。

简而言之,工厂持有的所有 Config 实例在关闭之前立即被缓存,并且缓存的实例被永久使用。

如何更新 Config 值

一旦存储,缓存的版本永远不会过期。更改现有的 Config 文件(或更改其环境变量)不会更新缓存或 Config 值。

因此,如果您想更新 Config 值,请更新 Config 文件或其环境变量,并且您必须手动删除缓存文件。

您可以使用 spark cache:clear 命令

php spark cache:clear

或者简单地删除 writable/cache/FactoriesCache_config 文件。

如何启用 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