Yii 1.x 中布局通过控制器 $layout 属性启用,必须继承 CController 并设为 '//layouts/name' 格式路径;布局文件用 echo $content 插入子视图内容,render() 才生效,renderPartial() 则跳过布局。

Yii 1.x 中统一布局靠 $layout 属性 + render() 自动注入,不是靠手动 include 或模板继承语法;改错位置、漏设属性、路径写错是 90% 的问题根源。
控制器里怎么启用 layout 文件
Yii 1.x 的布局生效前提是控制器继承自 CController(或你自定义的基类),且设置了 $layout 属性。它必须是字符串,且以两个斜杠开头表示从 protected/views/layouts/ 下查找:
-
$layout = '//layouts/main';→ 对应protected/views/layouts/main.php -
$layout = 'column2';→ 错误!这会去找protected/views/当前控制器名/column2.php,不是 layout 目录 - 设为
false或空字符串可临时禁用布局 - 在 action 内部动态覆盖:
$this->layout = '//layouts/admin';
layout 文件里怎么显示子视图内容
布局文件本身是普通 PHP 文件,$content 变量是框架自动注入的子视图渲染结果,直接 echo 即可:
<html> <body> <header>我的站点</header> <main><?php echo $content; ?></main> <footer>© 2026</footer> </body> </html>
注意:$content 是已执行过的 PHP 输出(比如 index.php 里 echo 'hello'; 的结果),不是原始字符串;不能用 ob_get_contents() 二次捕获,也不该尝试再 require 子视图。
为什么 render() 没走 layout
常见失效原因有三个:
- 控制器没继承
CController,比如直接 extendsController但没确认这个Controller是否正确继承了CController -
$layout值写成相对路径,如'layouts/main'(缺了开头的//) - 调用了
renderPartial()而非render()—— 后者跳过 layout,只输出视图片段 - 在
beforeAction()或init()中提前exit或抛出异常,导致 layout 渲染流程中断
如何让不同模块用不同 layout
模块级 layout 需在模块类中设置 $layout,而不是控制器里。例如模块 admin 的主 layout:
class AdminModule extends CWebModule
{
public $layout = '//layouts/admin';
}
此时该模块下所有控制器若未显式覆盖 $layout,就会默认使用这个。但注意:模块 layout 的路径仍从 protected/views/layouts/ 解析,不支持模块专属 layouts 目录(除非重写 CWebApplication::getLayoutFile())。
layout 机制本身不处理 CSS/JS 注入或区块复用,那些得靠 Yii::app()->clientScript 或自定义 widget;最易被忽略的是:子视图里 $this->widget() 或 $this->beginWidget() 的生命周期和 $content 输出时机强相关,别在 layout 里试图修改 $content 字符串——它已经是执行完毕的 HTML 流了。


















