工厂
介绍
什么是工厂?
像 服务 一样,工厂 是自动加载的扩展,它有助于保持代码简洁且优化,而无需在类之间传递对象实例。
工厂类似于 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\UserModel 和 Blog\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 |
组件的名称(如果与静态方法不同)。这可以用于将一个组件别名为另一个组件。 |
|
path |
字符串或 null |
命名空间/文件夹中查找类的相对路径。 |
|
instanceOf |
字符串或 null |
返回实例时要匹配的必需类名。 |
|
getShared |
boolean |
是否返回类的共享实例或加载一个新的实例。 |
|
preferApp |
boolean |
是否在 App 命名空间中具有相同基本名称的类会覆盖其他显式类请求。 |
|
注意
从 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