应用主体

未匹配的标注

应用主体

应用主体是管理 Yii 应用系统的整体结构和生命周期的对象。每个 Yii 应用系统只能包含一个应用主体,应用主体在 入口脚本 中创建并能通过表达式 \Yii::$app 在全局范围内访问。

Info: 当我们说“一个应用”,它可能是一个应用主体对象,也可能是一个应用系统,是根据上下文来决定[译:中文为避免歧义,Application 翻译为应用主体]。

Yii 有两种应用主体: yii\web\Application(WEB 应用主体)和 yii\console\Application(控制台应用主体),顾名思义,前者主要处理 WEB 请求,后者处理控制台命令行请求,他们都继承父类 yii\base\Application

应用主体生命周期

Application Lifecycle

当运行 入口脚本 处理请求时, 应用主体会经历以下生命周期:

  1. 入口脚本加载应用主体配置数组。
  2. 入口脚本创建一个应用主体实例:
  • 调用 [[yii\base\Application::preInit()|preInit()]] 配置几个高级别应用主体属性, 比如 [[yii\base\Application::basePath|basePath]]。

  • 注册 [[yii\base\Application::errorHandler|error handler]] 错误处理方法。

  • 配置应用主体属性。

  • 调用 [[yii\base\Application::init()|init()]] 初始化,该函数会调用 [[yii\base\Application::bootstrap()|bootstrap()]] 运行引导启动组件,具体如下:

  1. 入口脚本调用 [[yii\base\Application::run()]] 运行应用主体:
  • 触发 [[yii\base\Application::EVENT_BEFORE_REQUEST|EVENT_BEFORE_REQUEST]] 事件。
  • 处理请求:解析请求 路由 和相关参数; 创建路由指定的模块、控制器和动作对应的类,并运行动作。
  • 触发 [[yii\base\Application::EVENT_AFTER_REQUEST|EVENT_AFTER_REQUEST]] 事件。
  • 发送响应到终端用户。
  1. 入口脚本接收应用主体传来的退出状态并完成请求的处理。

应用主体配置

如下所示,当入口脚本创建了一个应用主体, 它会加载一个 配置 文件并传给应用主体。

require __DIR__ . '/../vendor/autoload.php';
require __DIR__ . '/../vendor/yiisoft/yii2/Yii.php';

// 加载应用主体配置
$config = require __DIR__ . '/../config/web.php';

// 实例化应用主体、配置应用主体
(new yii\web\Application($config))->run();

类似其他 配置 文件, 应用主体配置文件标明如何设置应用对象初始属性。 由于应用主体配置比较复杂,一般保存在多个类似如上 config/web.php配置文件 当中。

应用主体属性

应用主体配置文件中有许多重要的属性要配置,这些属性指定应用主体的运行环境。 比如,应用主体需要知道如何加载 控制器 , 临时文件保存到哪儿等等。 以下我们简述这些属性。

必要属性

在一个应用中,至少要配置2个属性: [[yii\base\Application::id]] 和 [[yii\base\Application::basePath]]。

$config = [
    'id' => 'basic',
    'basePath' => dirname(__DIR__),
];

id(应用唯一标识)

[[yii\base\Application::id]] 属性用来区分其他应用的唯一标识ID。主要给程序使用。为了方便协作,最好使用数字作为应用主体ID,但不强制要求为数字。

basePath(应用根目录)

[[yii\base\Application::basePath]] 属性指定该应用的根目录。根目录包含应用系统所有受保护的源代码。在根目录下可以看到对应 MVC 设计模式的modelsviewscontrollers 等子目录。

可以使用路径或 路径别名 来在配置 basePath 属性。两种格式所对应的目录都必须存在,否则系统会抛出一个异常。系统会使用 realpath() 函数规范化配置的路径。

basePath 属性经常用于派生一些其他重要路径(如 runtime 路径),因此,系统预定义 @app 代表这个路径。派生路径可以通过这个别名组成(如 @app/runtime 代表 runtime 的路径)。

重要属性

本小节所描述的属性通常需要设置,因为不同的应用属性不同。

aliases(路径别名组)

[[yii\base\Application::aliases]] 属性允许你用一个数组定义多个别名。数组的key为别名名称,值为对应的路径。例如:

[
    'aliases' => [
        '@name1' => 'path/to/path1',
        '@name2' => 'path/to/path2',
    ],
]

使用这个属性来定义别名, 代替 [[Yii::setAlias()]] 方法来设置。

bootstrap(启动引导)

这个属性很实用,它允许你用数组指定启动阶段 [[yii\base\Application::bootstrap()]] 需要运行的组件。比如,如果你希望一个 模块 自定义 URL 规则,你可以将模块 ID 加入到 bootstrap 数组中。

属性中的每个组件需要指定以下一项:

  • 应用 组件 ID.
  • 模块 ID.
  • 类名.
  • 配置数组.
  • 创建并返回一个组件的无名称函数.

例如:

[
    'bootstrap' => [
        // 应用组件ID或模块ID
        'demo',

        // 类名
        'app\components\Profiler',

        // 配置数组
        [
            'class' => 'app\components\Profiler',
            'level' => 3,
        ],

        // 匿名函数
        function () {
            return new app\components\Profiler();
        }
    ],
]

Info: 如果模块 ID 和应用组件 ID 同名,优先使用应用组件 ID,如果你想用模块 ID,可以使用如下匿名函数返回模块 ID。

[
    function () {
        return Yii::$app->getModule('user');
    },
]

在启动阶段,每个组件都会实例化。如果组件类实现接口 [[yii\base\BootstrapInterface]],也会调用 [[yii\base\BootstrapInterface::bootstrap()]] 方法。

举一个实际的例子,基础应用程序模板 应用主体配置中,开发环境下会在启动阶段运行 debuggii 模块。

if (YII_ENV_DEV) {
    // configuration adjustments for 'dev' environment
    $config['bootstrap'][] = 'debug';
    $config['modules']['debug'] = 'yii\debug\Module';

    $config['bootstrap'][] = 'gii';
    $config['modules']['gii'] = 'yii\gii\Module';
}

启动太多的组件会降低系统性能,因为每次请求都需要重新运行启动组件,因此,谨慎配置启动组件。

因为,引导工作必须在处理每一次请求之前都进行一遍,因此,让该过程尽可能轻量化就显得非常重要,请尽可能地优化这一步骤。

请尽量不要注册太多引导组件。只有他需要在 HTTP 请求处理的全部生命周期中都作用时才需要使用它。 举一个用到它的范例:一个模块需要注册额外的 URL 解析规则,就应该把它列在应用的 bootstrap 属性 之中,这样该 URL 解析规则才能在解析请求之前生效。(译注:换言之,为了性能需要,除了 URL 解析等少量操作之外,绝大多数组件都应该按需加载,而不是都放在引导过程中。)

在生产环境中,可以开启字节码缓存,比如 APC,来进一步最小化加载和解析 PHP 文件所需的时间。

一些大型应用都包含有非常复杂的应用配置,它们会被分割到许多更小的配置文件中。此时,可以考虑将整个配置数组缓存起来,并在入口脚本创建应用实例之前直接从缓存中加载。

catchAll(处理指定请求)

[[yii\web\Application::catchAll]] 属性仅 [[yii\web\Application]] 网页应用支持。它指定一个要处理所有用户请求的 控制器方法,通常在维护模式下使用,同一个方法处理所有用户请求。

该配置为一个数组,第一项指定动作的路由,剩下的数组项( key-value 成对)指定传递给动作的参数,例如:

[
    'catchAll' => [
        'offline/notice',
        'param1' => 'value1',
        'param2' => 'value2',
    ],
]

Info: 当开启这个属性时,开发环境下的调试面板将不能工作。

components(组件配置)

[[yii\base\Application::components]] 是最重要的属性,它允许你注册多个在其他地方使用的 应用组件。例如:

[
    'components' => [
        'cache' => [
            'class' => 'yii\caching\FileCache',
        ],
        'user' => [
            'identityClass' => 'app\models\User',
            'enableAutoLogin' => true,
        ],
    ],
]

每一个应用组件指定一个 key-value 对的数组,key 代表组件 ID,value 代表组件类名或 配置

在应用中可以任意注册组件,并可以通过表达式 \Yii::$app->ComponentID 全局访问。

详情请阅读 应用组件 一节.

controllerMap(控制器ID配置映射)

[[yii\base\Application::controllerMap]] 属性允许你指定一个控制器 ID 到任意控制器类。 Yii 遵循一个默认的 规则 指定控制器 ID 到任意控制器类(如 post 对应app\controllers\PostController)。 通过配置这个属性,可以打破这个默认规则,在下面的例子中, account对应到app\controllers\UserControllerarticle 对应到 app\controllers\PostController

[
    'controllerMap' => [
        'account' => 'app\controllers\UserController',
        'article' => [
            'class' => 'app\controllers\PostController',
            'enableCsrfValidation' => false,
        ],
    ],
]

数组的键代表控制器ID, 数组的值代表对应的类名。

controllerNamespace(控制器类默认命名空间)

[[yii\base\Application::controllerNamespace]] 属性指定控制器类默认的命名空间,默认为app\controllers。 比如控制器ID为 post 默认对应 PostController(不带命名空间),类全名为 app\controllers\PostController

控制器类文件可能放在这个命名空间对应目录的子目录下,例如,控制器 ID admin/post 对应的控制器类全名为 app\controllers\admin\PostController

控制器类全面能被 自动加载, 这点是非常重要的,控制器类的实际命名空间对应这个属性, 否则,访问时你会收到“Page Not Found”。

如果你想打破上述的规则,可以配置 controllerMap 属性。

language(应用展示语言)

[[yii\base\Application::language]] 属性指定应用展示给终端用户的语言,默认为 en 标识英文。如果需要之前其他语言可以配置该属性。

该属性影响各种 国际化 ,包括信息翻译、日期格式、数字格式等。例如 [[yii\jui\DatePicker]] 小部件会根据该属性展示对应语言的日历以及日期格式。

推荐遵循 IETF language tag 来设置语言,例如 en 代表英文,en-US 代表英文(美国).

该属性的更多信息可参考 国际化 一节.

modules(模块配置)

[[yii\base\Application::modules]] 属性指定应用所包含的 模块

该属性使用数组包含多个模块类 配置,数组的键为模块ID,例:

[
    'modules' => [
        // "booking" 模块以及对应的类
        'booking' => 'app\modules\booking\BookingModule',

        // "comment" 模块以及对应的配置数组
        'comment' => [
            'class' => 'app\modules\comment\CommentModule',
            'db' => 'db',
        ],
    ],
]

更多详情请参考 模块 一节。

name(应用名称)

[[yii\base\Application::name]] 属性指定你可能想展示给终端用户的应用名称, 不同于需要唯一性的 [[yii\base\Application::id|id]] 属性, 该属性可以不唯一,该属性用于显示应用的用途。

如果其他地方的代码没有用到,可以不配置该属性。

params(参数数组)

[[yii\base\Application::params]] 属性为一个数组,指定可以全局访问的参数, 代替程序中硬编码的数字和字符, 应用中的参数定义到一个单独的文件并随时可以访问是一个好习惯。 例如用参数定义缩略图的长宽如下:

[
    'params' => [
        'thumbnail.size' => [128, 128],
    ],
]

然后简单的使用如下代码即可获取到你需要的长宽参数:

$size = \Yii::$app->params['thumbnail.size'];
$width = \Yii::$app->params['thumbnail.size'][0];

以后想修改缩略图长宽, 只需要修改该参数而不需要相关的代码。

sourceLanguage(应用源语言)

[[yii\base\Application::sourceLanguage]] 属性指定应用代码的语言,默认为 'en-US' 标识英文(美国),如果应用不是英文请修改该属性。

language 属性类似,配置该属性需遵循 IETF language tag. 例如 en 代表英文, en-US 代表英文(美国)。

该属性的更多信息可参考 国际化 一节.

timeZone(时区)

[[yii\base\Application::timeZone]] 属性提供一种方式修改 PHP 运行环境中的默认时区,配置该属性本质上就是调用 PHP 函数 date_default_timezone_set(),例如:

[
    'timeZone' => 'PRC',// 中国
]

有关设置时区含义的更多详细信息,请查看关于日期格式的部分

version(应用版本)

[[yii\base\Application::version]] 属性指定应用的版本,默认为 '1.0', 其他代码不使用的话可以不配置。

实用属性

本小节描述的属性不经常设置,通常使用系统默认值。 如果你想改变默认值,可以配置这些属性。

charset(字符集)

[[yii\base\Application::charset]] 属性指定应用使用的字符集,默认值为 'UTF-8', 绝大部分应用都在使用,除非已有的系统大量使用非unicode数据才需要更改该属性。

defaultRoute(默认路由)

[[yii\base\Application::defaultRoute|defaultRoute]] 属性指定未配置的请求的响应 路由 规则, 路由规则可能包含模块 ID,控制器 ID,动作 ID。 例如 helppost/createadmin/post/create,如果动作 ID 没有指定, 会使用 [[yii\base\Controller::defaultAction]] 中指定的默认值。

对于 [[yii\web\Application]] 网页应用, 默认值为 'site' 对应 SiteController 控制器,并使用默认的动作。 因此你不带路由的访问应用,默认会显示 app\controllers\SiteController::actionIndex() 的结果。

对于 [[yii\console\Application]] 控制台应用, 默认值为 'help' 对应 [[yii\console\controllers\HelpController::actionIndex()]]。 因此,如果执行的命令不带参数,默认会显示帮助信息。

extensions(扩展配置)

[[yii\base\Application::extensions]] 属性用数组列表指定应用安装和使用的 扩展, 默认使用 @vendor/yiisoft/extensions.php 文件返回的数组。 当你使用 Composer 安装扩展,extensions.php 会被自动生成和维护更新。 所以大多数情况下,不需要配置该属性。

特殊情况下你想自己手动维护扩展,可以参照如下配置该属性:

[
    'extensions' => [
        [
            'name' => 'extension name',
            'version' => 'version number',
            'bootstrap' => 'BootstrapClassName',  // 可选配,可为配置数组
            'alias' => [  // 可选配
                '@alias1' => 'to/path1',
                '@alias2' => 'to/path2',
            ],
        ],

        // ... 更多像上面的扩展 ...

    ],
]

如上所示,该属性包含一个扩展定义数组,每个扩展为一个包含 nameversion 项的数组。 如果扩展要在 引导启动 阶段运行, 需要配置 bootstrap 以及对应的引导启动类名或 configuration 数组。 扩展也可以定义 别名

layout(默认布局)

[[yii\base\Application::layout]] 属性指定渲染 视图 默认使用的布局名字, 默认值为 'main' 对应 布局路径下的 main.php 文件, 如果 布局路径视图路径 都是默认值, 默认布局文件可以使用路径别名 @app/views/layouts/main.php

如果不想设置默认布局文件,可以设置该属性为 false,这种做法比较罕见。

layoutPath(默认布局路径)

[[yii\base\Application::layoutPath]] 属性指定查找布局文件的路径,默认值为 视图路径 下的 layouts 子目录。 如果 视图路径 使用默认值, 默认的布局路径别名为@app/views/layouts

该属性需要配置成一个目录或 路径 别名

runtimePath(运行时临时文件路径)

[[yii\base\Application::runtimePath]] 属性指定临时文件如日志文件、缓存文件等保存路径, 默认值为带别名的 @app/runtime

可以配置该属性为一个目录或者路径 别名, 注意应用运行时有对该路径的写入权限, 以及终端用户不能访问该路径因为临时文件可能包含一些敏感信息。

为了简化访问该路径,Yii 预定义别名 @runtime 代表该路径。

viewPath(视图文件根目录)

[[yii\base\Application::viewPath]] 属性指定视图文件的根目录,默认值为带别名的 @app/views, 可以配置它为一个目录或者路径 别名.

vendorPath(composer 安装包路径)

[[yii\base\Application::vendorPath]] 属性指定 Composer 管理的供应商路径, 该路径包含应用使用的包括Yii框架在内的所有第三方库。 默认值为带别名的 @app/vendor

可以配置它为一个目录或者路径 别名, 当你修改时,务必修改对应的 Composer 配置。

为了简化访问该路径,Yii 预定义别名 @vendor 代表该路径。

enableCoreCommands(是否启用核心命令)

[[yii\console\Application::enableCoreCommands]] 属性仅 [[yii\console\Application]] 控制台应用支持,用来指定是否启用 Yii 中的核心命令,默认值为 true

应用事件

应用在处理请求过程中会触发事件,可以在配置文件配置事件处理代码, 如下所示:

[
    'on beforeRequest' => function ($event) {
        // ...
    },
]

on eventName 语法的用法在 Configurations 一节有详细描述.

另外,在应用主体实例化后,你可以在 引导启动 阶段附加事件处理代码, 例如:

\Yii::$app->on(\yii\base\Application::EVENT_BEFORE_REQUEST, function ($event) {
    // ...
});

EVENT_BEFORE_REQUEST(请求之前)

[[yii\base\Application::EVENT_BEFORE_REQUEST]] 事件在应用处理请求 before 之前,实际的事件名为 beforeRequest

在事件触发前,应用主体已经实例化并配置好了, 所以通过事件机制将你的代码嵌入到请求处理过程中非常不错。 例如在事件处理中根据某些参数动态设置 [[yii\base\Application::language]] 语言属性。

EVENT_AFTER_REQUEST(请求之后)

[[yii\base\Application::EVENT_AFTER_REQUEST]] 事件在应用处理请求 after 之后但在返回响应 before 之前触发, 实际的事件名为 afterRequest

该事件触发时,请求已经被处理完, 可以做一些请求后处理或自定义响应。

注意 [[yii\web\Response|response]] 组件在发送响应给终端用户时也会触发一些事件, 这些事件都在本事件 after 之后触发。

EVENT_BEFORE_ACTION(运行动作之前)

[[yii\base\Application::EVENT_BEFORE_ACTION]] 事件在每个 控制器动作 运行before之前会被触发, 实际的事件名为 beforeAction.

事件的参数为一个 [[yii\base\ActionEvent]] 实例, 事件处理中可以设置[[yii\base\ActionEvent::isValid]] 为 false 停止运行后续动作, 例如:

[
    'on beforeAction' => function ($event) {
        if (some condition) {
            $event->isValid = false;
        } else {
        }
    },
]

注意 模块控制器 都会触发 beforeAction 事件。 应用主体对象首先触发该事件,然后模块触发(如果存在模块),最后控制器触发。 任何一个事件处理中设置 [[yii\base\ActionEvent::isValid]] 设置为 false 会停止触发后面的事件。

EVENT_AFTER_ACTION(运行动作之后)

[[yii\base\Application::EVENT_AFTER_ACTION]] 事件在每个 控制器动作 运行 after 之后会被触发, 实际的事件名为 afterAction

该事件的参数为 [[yii\base\ActionEvent]] 实例, 通过 [[yii\base\ActionEvent::result]] 属性, 事件处理可以访问和修改动作的结果。例如:

[
    'on afterAction' => function ($event) {
        if (some condition) {
            // 修改 $event->result
        } else {
        }
    },
]

注意 模块控制器 都会触发 afterAction 事件。 这些对象的触发顺序和 beforeAction 相反,也就是说, 控制器最先触发,然后是模块(如果有模块),最后为应用主体。

💖喜欢本文档的,欢迎点赞、收藏、留言或转发,谢谢支持!
作者邮箱:zhuzixian520@126.com,github地址:github.com/zhuzixian520

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
zhuzixian520
讨论数量: 0
发起讨论 只看当前版本


暂无话题~