CI 的 View 没有像 Laravel 等一些流行框架同样设计的那么重,有本身的一套模版机制,CI 一直采用纯自然的 PHP 模板形式,纯自然的好处是不用再学习一套模板语言了,缺点是不能用到一些便利的设计模式,好比不能使用继承布局等等,固然你也能够加第三方的视图组件进来。php
下面咱们开始看源码,看源码,咱们先从视图的调用开始。html
CI 4 开始使用新的视图调用逻辑,不在是 load 形式,调用方式以下:bootstrap
echo view('name');
能够看到是直接调用了一个 view 函数,这个函数咱们既不须要提早 load , 在 construct 方法里也没看见 include 什么文件,同时,这个方法看起来又不属于控制器对象,那么它是从哪里来的呢?设计模式
回到以前写的“之二——入口以及初始化操做”一节,里面提到了,在 bootstrap.php 74 行(原始文件行号), require 了一下 BASEPATH.'Common.php' ,这个文件中定义了许多辅助方法。 view 就是其中一个,该方法位于 system/common.php 中的 88 行(原始文件行号)。下面把代码贴出来:数组
if (! function_exists('view')) { function view(string $name, array $data = [], array $options = []) { $renderer = Services::renderer(); $saveData = null; if (array_key_exists('saveData', $options) && $options['saveData'] === true) { $saveData = (bool)$options['saveData']; unset($options['saveData']); } return $renderer->setData($data, 'raw') ->render($name, $options, $saveData); } }
能够看到,这里调用了 Services 类的 renderer 静态方法。以后的 saveData 逻辑主要处理屡次调用 view 方法时是否共享视图变量以及最后把要传递给视图的数据变量经过 $renderer->setData 方法传递给 render ,最后又执行了 render 进行渲染视图。下面贴出的是 Services::renderer() 源码(system/config/services.php:362):缓存
public static function renderer($viewPath = APPPATH.'Views/', $config = null, $getShared = true) { if ($getShared) { return self::getSharedInstance('renderer', $viewPath, $config); } if (is_null($config)) { $config = new \Config\View(); } return new \CodeIgniter\View\View($config, $viewPath, self::locator(true), CI_DEBUG, self::logger(true)); }
能够看出, view 方法主要 new 了一个 CodeIgniterViewView 类,该类位于 /system/ViewView.php 下。app
小结一下,给个分析过程图,以方便理解:框架
接下来就是咱们的主角 View 了。函数
按着以上图中流程,咱们要看 View 类的三个关键方法,分别是 __construct 、 setData 、 render 。源码分析
public function __construct($config, string $viewPath = null, $loader = null, bool $debug = null, Logger $logger = null) { $this->config = $config; $this->viewPath = rtrim($viewPath, '/ ').'/'; $this->loader = is_null($loader) ? Services::locator() : $loader; $this->logger = is_null($logger) ? Services::logger() : $logger; $this->debug = is_null($debug) ? CI_DEBUG : $debug; $this->saveData = $config->saveData ?? null; }
能够看到在 services new 的时候,仅仅传递了配置信息以及视图路径,视图数据不在初始化之列。
public function setData(array $data=[], string $context=null): RendererInterface { if ( ! empty($context)) { $data = \esc($data, $context); } $this->data = array_merge($this->data, $data); return $this; }
此方法主要用途是往视图里压数据,实际上就是把新压的数据和对象中原有的数据(数据)合并一下。
做为视图逻辑,渲染视图确定是一个重中之重的过程。
如下是去掉注释和空行的源码截图(源码分析中涉及到的行号是截图中的行号):
142 行:由参数能够看出,调用 render 方法时才把具体的视图文件名传递进来,因视图数据经过 setData 方法放到了当前对象的 data 属性里,所以无需再次传递。
145-147,170-172 行,处理是否将本次压进来的视图数据共享给下次 render 过程。这个 $saveData 能够在 application/config/view.php 里配置,默认是 false 。
149 行:处理视图文件名后缀。
150-158 行,判断开始缓存设置的话,处理视图缓存。
159-168 行,尝试着经过自动加载机制找到视图文件。找不到,抛异常。
168 行,很重要(划重点),该方法是将压进来的数组形式的数据扩展开成 $key=$value 形式,由于视图是 include 进来的普通 php 所以,在视图中也就能够用 $key 的形式读取到变量的内容。
174-177 行,开启输出控制缓冲机制,并 include 进来视图,至关于同时执行了这个文件,这个文件中的普通 html 亦或是执行 php 后的输出,都会被输出缓冲接收到并赋值给了 $output 。
179-182 行,前边的缓存是处理读取过程,这里是处理写入过程。
183 行,最后返回渲染结果。
从源码上看, CI 使用了原始 PHP 做为模版机制使得视图逻辑很是简单。无非也就是把视图 include 进来,用输出缓冲把执行结果拿到便可。
此文能够转载,但转载前须要发邮件到imustgxd*sina.cn进行沟通,未沟通的均视做侵权。 转载同时需注明连接,并保留此段文字。