Yii 2 应用结构全景解析:从入口脚本到 MVC 组件的完整架构指南
2026/9/24 13:56:11 网站建设 项目流程
  • 后端
  • Web框架

【免费下载链接】yii2

Yii 2: The Fast, Secure and Professional PHP Framework

项目地址:https://gitcode.com/gh_mirrors/yi/yii2
点击查看免费下载

Yii 2 框架基于经典的模型-视图-控制器(MVC)架构模式组织应用,但其完整应用结构远不止 MVC 三层:入口脚本(Entry Scripts)、应用(Applications)、应用组件(Application Components)、模块(Modules)、过滤器(Filters)与小部件(Widgets)共同构成了一个完整、可扩展的应用体系。本文以 structure-overview.md 为骨架,结合框架源码逐层拆解 Yii 2 的静态应用结构,帮助你建立对应用"全局地图"的清晰认知,并为后续阅读 MVC 各层、路由、缓存与 REST 开发文档打下基础。

Yii 应用的静态结构:入口脚本启动应用,应用聚合模块、应用组件与控制器,控制器再协调模型、视图、过滤器完成请求处理(图源:docs/guide/images/application-structure.png)

MVC 模式:应用组织的基石

Yii 应用按照 模型-视图-控制器(MVC) 架构模式进行组织,三者各司其职:

  • 模型(Models):代表数据、业务逻辑与规则。模型是应用处理数据的核心对象,通常通过继承yii\base\Model或其子类创建。
  • 视图(Views):模型在输出端的呈现形式。视图负责把模型数据渲染成用户可见的 HTML 或其他格式。
  • 控制器(Controllers):接收输入,并将输入转化为对模型和视图的命令。控制器是请求处理流程的"调度中心"。

三者的协作关系在框架源码中有明确体现:控制器在 actionView() 中通过Post::findOne($id)加载模型,再调用$this->render('view', ['model' => $model])将模型注入视图;在 actionCreate() 中则先$model->load(Yii::$app->request->post())接收用户输入、$model->save()保存数据,成功后重定向、失败则渲染表单视图。这一"控制器取数→模型处理→视图呈现"的闭环正是 MVC 在 Yii 2 中的标准落地形态。

设计取向:Yii 官方推荐"胖模型、瘦控制器"(Fat Models, Thin Controllers)。模型是业务数据、规则与逻辑的集中地,而控制器应当保持精简,每个 action 只包含少量协调性代码。

六大核心实体:MVC 之外的架构部件

除了 MVC 三要素,Yii 应用还包含以下六类核心实体,它们共同支撑起完整的应用骨架:

实体作用关键类 / 文档
入口脚本(Entry Scripts)用户可直接访问的 PHP 脚本,负责启动一次请求处理周期yii\web\Application、structure-entry-scripts.md
应用(Applications)全局可访问的对象,管理应用组件并协调它们完成请求yii\base\Application、structure-applications.md
应用组件(Application Components)注册在应用上的对象,为处理请求提供各类服务yii\base\Application::$components、structure-application-components.md
模块(Modules)自包含的软件单元,内部拥有完整的 MVC 结构;应用可由多个模块组成yii\base\Module、structure-modules.md
过滤器(Filters)在控制器处理每个请求前后被调用的代码yii\base\ActionFilter、structure-filters.md
小部件(Widgets)可嵌入视图的对象,可能包含控制器逻辑,可在不同视图中复用yii\base\Widget、structure-widgets.md

如上图所示,这些实体之间存在清晰的层级与包含关系:入口脚本 1:1 关联应用;应用可以聚合 0..n 个模块、0..n 个应用组件,且必须包含至少 1 个控制器;控制器包含过滤器、视图与模型;视图内部又可以嵌入小部件并注册资源包(Asset Bundles)。下面逐一深入。

入口脚本:请求周期的起点

入口脚本是应用引导(bootstrapping)过程的第一步。无论 Web 应用还是控制台应用,都只有一个入口脚本,最终用户通过请求入口脚本来实例化应用对象并把请求转交给它。

Web 应用入口脚本必须存放在 Web 可访问目录下,通常命名为index.php;控制台应用入口脚本通常存放在应用根目录下、命名为yii(无.php后缀)并设置为可执行,以便通过./yii <route> [arguments] [options]运行控制台命令。

入口脚本的核心工作可归纳为六步:

  1. 定义全局常量;
  2. 注册 Composer 自动加载器;
  3. 引入Yii类文件;
  4. 加载应用配置;
  5. 创建并配置应用实例;
  6. 调用yii\base\Application::run()处理传入请求。

Basic 项目模板的 Web 入口脚本完整代码如下:

<?php defined('YII_DEBUG') or define('YII_DEBUG', true); defined('YII_ENV') or define('YII_ENV', 'dev'); // register Composer autoloader require __DIR__ . '/../vendor/autoload.php'; // include Yii class file require __DIR__ . '/../vendor/yiisoft/yii2/Yii.php'; // load application configuration $config = require __DIR__ . '/../config/web.php'; // create, configure and run application (new yii\web\Application($config))->run();

控制台入口脚本与之类似,但以#!/usr/bin/env php开头、使用yii\console\Application,并通过exit($exitCode)把运行退出码返回给操作系统:

#!/usr/bin/env php <?php defined('YII_DEBUG') or define('YII_DEBUG', true); defined('YII_ENV') or define('YII_ENV', 'dev'); // register Composer autoloader require __DIR__ . '/vendor/autoload.php'; // include Yii class file require __DIR__ . '/vendor/yiisoft/yii2/Yii.php'; // load application configuration $config = require __DIR__ . '/config/console.php'; $application = new yii\console\Application($config); $exitCode = $application->run(); exit($exitCode);

全局常量:调试与环境的开关

入口脚本是定义全局常量的最佳位置。Yii 支持以下三个关键常量:

常量含义默认值
YII_DEBUG是否处于调试模式;开启后保留更多日志信息,异常时展示详细调用栈,仅建议开发环境开启false
YII_ENV应用运行环境(如dev/prod),详见 Configurations'prod'
YII_ENABLE_ERROR_HANDLER是否启用 Yii 内置的错误处理器true

定义常量时常用defined('YII_DEBUG') or define('YII_DEBUG', true);这种简洁写法,等价于if (!defined('YII_DEBUG')) { define('YII_DEBUG', true); }。常量定义必须放在入口脚本最开头,以便在引入其他 PHP 文件时生效。

应用(Application):全局协调者

每个 Yii 应用系统包含唯一一个应用对象,它在入口脚本中被创建,并可通过\Yii::$app表达式全局访问。Yii 提供两种应用类型:处理 Web 请求的 yii\web\Application 和处理控制台命令的 yii\console\Application。

应用配置:一切初始化的源头

入口脚本创建应用时,会加载一份配置并应用到应用对象上。由于应用配置通常非常复杂,一般保存在配置文件中(如web.php):

require __DIR__ . '/../vendor/autoload.php'; require __DIR__ . '/../vendor/yiisoft/yii2/Yii.php'; // load application configuration $config = require __DIR__ . '/../config/web.php'; // instantiate and configure the application (new yii\web\Application($config))->run();

必配属性:id 与 basePath

任何应用都至少需要配置两个属性:

  • id:应用的唯一标识,主要用于程序内部使用;推荐仅使用字母数字字符以保证最佳互操作性。
  • basePath:应用根目录,包含全部受保护源码(modelsviewscontrollers等 MVC 子目录)。可配置为目录路径或路径别名,对应目录必须存在,否则抛出异常,路径会经realpath()规范化。Yii 会基于它预定义@app别名,并由此推导出运行目录等其它重要路径(如@app/runtime)。

重要属性速览

除必配属性外,以下属性在不同应用间差异较大,通常需要显式配置:

属性作用典型配置
aliases以数组形式定义路径别名'aliases' => ['@name1' => 'path/to/path1']
bootstrap指定应在引导过程中运行的组件列表'bootstrap' => ['log', 'debug']
catchAll(Web 专用)让一个指定控制器动作接管所有请求,常用于维护模式'catchAll' => ['offline/notice', 'param1' => 'value1']
components注册应用组件,最重要的属性'components' => ['cache' => ['class' => 'yii\caching\FileCache']]
controllerMap将控制器 ID 映射到任意控制器类,突破命名约定限制'controllerMap' => ['account' => 'app\controllers\UserController']
controllerNamespace控制器类所在默认命名空间,默认app\controllers'controllerNamespace' => 'app\controllers'
language应用向用户展示内容所用的语言,默认en'language' => 'zh-CN'
modules应用包含的模块列表'modules' => ['booking' => 'app\modules\booking\BookingModule']
name应用名称,用于展示,无需唯一'name' => 'My App'
params全局可访问的应用参数数组'params' => ['thumbnail.size' => [128, 128]]
sourceLanguage应用代码书写语言,默认'en-US''sourceLanguage' => 'en-US'
timeZone设置 PHP 运行时默认时区(等价于date_default_timezone_set()'timeZone' => 'America/Los_Angeles'
version应用版本号,默认'1.0''version' => '2.0.0'

另有按约定即可、通常无需改动但可打破约定的"实用属性":charset(默认UTF-8)、defaultRoute(Web 默认site,控制台默认help)、extensions(默认取自@vendor/yiisoft/extensions.php)、layout(默认main)、layoutPath(默认@app/views/layouts)、runtimePath(默认@app/runtime,必须可写且需防止终端用户访问)、viewPath(默认@app/views)、vendorPath(默认@app/vendor)、以及控制台专用的enableCoreCommands(默认true)。

bootstrap 属性的底层实现

bootstrap属性值得特别关注。从 Application::bootstrap() 源码可以看到其完整执行逻辑:首先加载@vendor/yiisoft/extensions.php中声明的扩展别名并实例化扩展引导类,然后遍历$this->bootstrap列表——每个条目可以是应用组件 ID、模块 ID、类名、配置数组或匿名函数。条目解析后,若组件类实现了 BootstrapInterface,其bootstrap($app)方法会被调用;若使用匿名函数且返回值为假(如不返回实例),则该条目被跳过。

官方对bootstrap的使用有明确警告:放太多组件会拖慢应用性能,因为每个请求都要运行同一批组件,应谨慎使用。Basic 模板在开发环境下把debuggii模块加入 bootstrap 就是典型场景:

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

应用生命周期:一次请求的完整旅程

应用在响应一次请求时,会经历如下生命周期(对应 Application::run() 的实现流程):

  1. 入口脚本将应用配置作为数组加载;
  2. 入口脚本创建应用实例:先调用preInit()配置高优先级属性(如basePath),随后注册错误处理器、配置应用属性,再调用init()init()内部进一步调用bootstrap()运行引导组件;
  3. 入口脚本调用run()运行应用:
    • 触发EVENT_BEFORE_REQUEST事件;
    • 处理请求:把请求解析为路由及参数,按路由创建模块、控制器与动作对象并执行动作;
    • 触发EVENT_AFTER_REQUEST事件;
    • 向终端用户发送响应;
  4. 入口脚本接收退出状态码,完成请求处理。

与之配套,应用在生命周期中会触发四个可挂接的事件:EVENT_BEFORE_REQUESTEVENT_AFTER_REQUESTEVENT_BEFORE_ACTIONEVENT_AFTER_ACTION。前两者分别在应用处理请求前后触发;后两者在每次执行控制器动作前后触发,可通过 ActionEvent::isValid 置为false来终止动作执行(beforeAction场景),或通过ActionEvent::result读取/修改动作结果(afterAction场景)。事件按"应用 → 模块 → 控制器"顺序触发beforeAction,而afterAction按相反顺序触发。

应用组件:可插拔的服务仓库

应用本质上是服务定位器(Service Locator),承载着一组提供不同服务的应用组件。例如urlManager负责把 Web 请求路由到正确的控制器,db组件提供数据库服务。

每个应用组件都有唯一 ID,可通过\Yii::$app->componentID访问,例如\Yii::$app->db获取数据库连接、\Yii::$app->cache获取主缓存。组件在首次访问时才被实例化,后续访问返回同一实例(惰性加载)。应用组件可以是任意对象,通过配置components属性注册,支持类名、配置数组、匿名函数三种写法:

[ 'components' => [ // register "cache" component using a class name 'cache' => 'yii\caching\ApcCache', // register "db" component using a configuration array 'db' => [ 'class' => 'yii\db\Connection', 'dsn' => 'mysql:host=localhost;dbname=demo', 'username' => 'root', 'password' => '', ], // register "search" component using an anonymous function 'search' => function () { return new app\components\SolrService; }, ], ]

注意:应用组件如同全局变量,注册过多会让代码难以测试和维护。很多场景下创建局部组件按需使用即可。

核心应用组件清单

Yii 预定义了一组 ID 固定、带默认配置的核心应用组件,正因它们的存在,Yii 应用才能处理用户请求:

组件 ID职责
assetManageryii\web\AssetManager管理资源包与资源发布,见 Assets
dbyii\db\Connection数据库连接(配置时须同时指定类与dsn等必需属性),见 Database Access Objects
errorHandleryii\web\ErrorHandler处理 PHP 错误与异常,见 Handling Errors
formatteryii\i18n\Formatter向用户展示数据时的格式化(数字千分位、日期长格式等),见 Data Formatting
i18nyii\i18n\I18N消息翻译与格式化,见 Internationalization
logyii\log\Dispatcher管理日志目标,见 Logging
maileryii\swiftmailer\Mailer邮件撰写与发送,见 Mailing
responseyii\web\Response表示发送给用户的响应,见 Responses
requestyii\web\Request表示接收到的用户请求,见 Requests
sessionyii\web\Session会话信息(仅 Web 应用可用),见 Sessions and Cookies
urlManageryii\web\UrlManagerURL 解析与创建,见 Routing and URL Creation
useryii\web\User用户认证信息(仅 Web 应用可用),见 Authentication
viewyii\web\View视图渲染,见 Views

模块(Modules):自包含的迷你应用

模块是自包含的软件单元,内部包含模型、视图、控制器及其它支撑组件,常被视为"迷你应用"。与应用的差别在于:模块不能独立部署,必须寄居于应用之中

目录结构与模块类

模块组织为一个目录(即模块的basePath),内部结构与应用类似:

forum/ Module.php the module class file controllers/ containing controller class files DefaultController.php the default controller class file models/ containing model class files views/ containing controller view and layout files layouts/ containing layout view files default/ containing view files for DefaultController index.php the index view file

每个模块必须有唯一的模块类(继承yii\base\Module),位于模块basePath根目录下且可自动加载。模块被访问时创建唯一实例,用于在模块代码间共享数据与组件:

namespace app\modules\forum; class Module extends \yii\base\Module { public function init() { parent::init(); $this->params['foo'] = 'bar'; // ... other initialization code ... } }

init()初始化代码较多,可用\Yii::configure($this, require __DIR__ . '/config.php')从配置文件加载(配置内容与应用配置结构类似,可含componentsparams)。

在模块中组织 MVC

  • 控制器:按惯例放在模块类命名空间的controllers子命名空间下(如app\modules\forum\controllers\PostController),文件位于模块basePath/controllers目录。可通过配置 Module::controllerNamespace 自定义;命名空间外的控制器可用controllerMap接入(与应用级用法一致)。
  • 视图:放在模块basePath/views目录下,控制器渲染的视图位于views/ControllerID。模块可设置自己的layout(默认放在views/layouts),未配置则沿用应用的布局。
  • 控制台命令:模块可在控制台模式下暴露命令。做法是在模块init()中检测Yii::$app instanceof \yii\console\Application时把controllerNamespace指向命令命名空间(如app\modules\forum\commands),之后即可用yii <module_id>/<command>/<sub_command>调用。

使用、访问与嵌套

在应用配置中列出模块即可启用:

[ 'modules' => [ 'forum' => [ 'class' => 'app\modules\forum\Module', // ... other configurations for the module ... ], ], ]

模块内控制器的路由以模块 ID 开头:forum/post/index表示forum模块中post控制器的index动作;路由只含模块 ID 时由Module::defaultRoute(默认default)决定,因此路由forum表示该模块的default控制器。模块 URL 规则应在urlManager解析请求(parseRequest())之前、即引导阶段添加(init()中无效,因为模块初始化晚于路由处理),并建议用yii\web\GroupUrlRule包裹。

获取模块实例有三种方式:MyModuleClass::getInstance()(当前请求的模块实例)、\Yii::$app->getModule('forum')(已知模块 ID)、\Yii::$app->controller->module(当前控制器所属模块)。拿到实例后可访问其参数与组件,如$module->params['maxPostCount']

模块支持无限层级嵌套(子模块声明在父模块的modules属性中),嵌套模块内控制器的路由需包含所有祖先模块 ID,如forum/admin/dashboard/index。自 2.0.13 起模块支持服务定位器的树遍历,模块开发者应优先使用$module->get('db')而非Yii::$app->get('db'),这样模块使用者可以为模块指定独立的组件配置(例如为模块配置带module_表前缀的独立db组件)。

最佳实践:模块最适合大型应用中可按功能组划分的场景,每个功能组由专人/团队开发维护;用户管理、评论管理等通用功能也可做成模块以便跨项目复用。

过滤器(Filters):动作前后的钩子

过滤器是在控制器动作运行前后执行的对象。例如访问控制过滤器在动作前检查当前用户是否有权访问;内容压缩过滤器在动作后压缩响应内容再发送。过滤器由前置过滤(pre-filter)与后置过滤(post-filter)组成。

使用过滤器

过滤器本质上是特殊形态的行为(Behaviors),因此用法与行为一致——在控制器中重写behaviors()方法声明:

public function behaviors() { return [ [ 'class' => 'yii\filters\HttpCache', 'only' => ['index', 'view'], 'lastModified' => function ($action, $params) { $q = new \yii\db\Query(); return $q->from('user')->max('updated_at'); }, ], ]; }

默认情况下控制器声明的过滤器作用于该控制器所有动作,可用only限定、except排除。过滤器也可声明在模块或应用中,此时作用于其下全部控制器动作(注意此时only/except中应使用路由而非动作 ID)。

多个过滤器叠加时按如下顺序执行:前置阶段按"应用 → 模块 → 控制器"顺序应用,任一过滤器取消执行则其后过滤器(含后置)不再运行;动作通过前置过滤后执行;后置阶段按"控制器 → 模块 → 应用"的逆序应用。

创建自定义过滤器

继承yii\base\ActionFilter并重写beforeAction()和/或afterAction()即可。beforeAction()返回false将跳过后续过滤器并取消动作执行。下面的例子记录动作执行耗时:

namespace app\components; use Yii; use yii\base\ActionFilter; class ActionTimeFilter extends ActionFilter { private $_startTime; public function beforeAction($action) { $this->_startTime = microtime(true); return parent::beforeAction($action); } public function afterAction($action, $result) { $time = microtime(true) - $this->_startTime; Yii::debug("Action '{$action->uniqueId}' spent $time second."); return parent::afterAction($action, $result); } }

内置核心过滤器

Yii 在yii\filters命名空间下提供了丰富的内置过滤器,实现类可在 framework/filters/ 目录中查阅:

  • AccessControl:基于规则集合的简单访问控制,按顺序匹配第一条规则决定允许/拒绝;规则可用roles(如@表示已认证用户)、IP、动作等方法匹配。无规则匹配时默认拒绝访问
  • 认证方法过滤器yii\filters\auth命名空间):如HttpBasicAuthHttpBearerAuthQueryParamAuth等,常用于 RESTful API 认证(需身份类实现findIdentityByAccessToken())。
  • ContentNegotiator:支持响应格式协商与应用语言协商,通过GET参数和Accept头决定;也可作为引导组件在应用生命周期早期生效(见 structure-applications.md)。
  • HttpCache:利用Last-ModifiedETag头实现客户端缓存。
  • PageCache:服务端整页缓存,支持duration时长、dependency依赖(如基于DbDependency的 SQL 变更检测)与variations(如按语言缓存不同版本)。
  • RateLimiter:基于漏桶算法的限流器,主要用于 RESTful API。
  • VerbFilter:校验请求的 HTTP 方法是否允许,不允许时抛出 405 异常。
  • Cors:跨域资源共享过滤器,应放在认证/授权过滤器之前以保证 CORS 头始终发送;可通过cors属性按动作精细调优OriginAccess-Control-Request-MethodAccess-Control-Request-HeadersAccess-Control-Allow-CredentialsAccess-Control-Max-Age(默认 86400)等头。

小部件(Widgets):视图中的可复用积木

小部件是可嵌入视图的对象,可能包含控制器逻辑,能在不同视图中复用,是构建视图的"积木"。Yii 内置了大量实用小部件,实现类位于 framework/widgets/,例如:

  • ActiveFormActiveField:生成带模型绑定与验证的表单;
  • Breadcrumbs:面包屑导航;
  • LinkPager/ListView/GridView:分页与数据列表/表格展示;
  • Menu:菜单;
  • DetailView:单条记录的键值展示;
  • Block/ContentDecorator/FragmentCache:视图内容装饰与片段缓存。

小部件的使用方式(以表单为例,见 structure-views.md):

<?php $form = ActiveForm::begin(); ?> <?= $form->field($model, 'username') ?> <?= $form->field($model, 'password')->passwordInput() ?> <?= Html::submitButton('Login') ?> <?php ActiveForm::end(); ?>

小部件通常继承yii\base\Widget,通过init()初始化属性、run()渲染输出。自定义小部件时可调用$this->render()渲染关联视图(视图默认放在小部件类文件所在目录的views子目录下)。

一张图看懂整体架构

回顾开篇的静态结构图与以上各节,可以总结出 Yii 2 应用结构的两条主线:

  1. 启动链:入口脚本(index.php)→ 加载配置 → 创建应用实例 → 引导组件/模块 → 解析路由 → 创建控制器与动作 → 执行动作 → 发送响应。
  2. 组合链:应用聚合模块与应用组件;控制器包含过滤器、模型与视图;视图内嵌小部件并注册资源包(Asset Bundles)。过滤器贯穿"请求前/后",小部件复用视图逻辑,资源包统一管理 CSS/JS。

进阶阅读路线

本文是"结构"系列的总览,以下文档可帮助你把各个部件落到实际编码中:

  • MVC 三件套:Models(属性、场景、校验、批量赋值、数据导出)、Views(渲染、布局、嵌套布局、块)、Controllers(动作、路由、动作参数、控制器生命周期);
  • 运行时基础:Runtime Routing、Requests、Responses、Runtime Bootstrapping;
  • 组件机制:Components、Service Locator、Configurations、Behaviors;
  • 实战延伸:Widgets、Assets、Extensions、RESTful Web Services。

动手验证建议:在本地完成 Start Installation 后,打开 Basic 模板的web/index.php(对照本文入口脚本一节)、config/web.php(对照应用配置与bootstrap一节),再用 Gii 生成一个 CRUD 并跟踪其控制器、模型、视图与过滤器声明,即可把本文的静态结构图转化为切身的运行时体验。

  • 后端
  • Web框架

【免费下载链接】yii2

Yii 2: The Fast, Secure and Professional PHP Framework

项目地址:https://gitcode.com/gh_mirrors/yi/yii2
点击查看免费下载
上一篇:LEDE项目常见问题解决方案
下一篇:Leptonica 项目常见问题解决方案

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询