Codeigniter 4.0-dev 版源码学习笔记之七—— View 视图

前言

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 源码分析

按着以上图中流程,咱们要看 View 类的三个关键方法,分别是 __construct 、 setData 、 render 。源码分析

__construct 方法
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 的时候,仅仅传递了配置信息以及视图路径,视图数据不在初始化之列。

setData 方法
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;
}

此方法主要用途是往视图里压数据,实际上就是把新压的数据和对象中原有的数据(数据)合并一下。

render 方法

做为视图逻辑,渲染视图确定是一个重中之重的过程。

如下是去掉注释和空行的源码截图(源码分析中涉及到的行号是截图中的行号):

view类的render方法

  1. 142 行:由参数能够看出,调用 render 方法时才把具体的视图文件名传递进来,因视图数据经过 setData 方法放到了当前对象的 data 属性里,所以无需再次传递。

  2. 145-147,170-172 行,处理是否将本次压进来的视图数据共享给下次 render 过程。这个 $saveData 能够在 application/config/view.php 里配置,默认是 false 。

  3. 149 行:处理视图文件名后缀。

  4. 150-158 行,判断开始缓存设置的话,处理视图缓存。

  5. 159-168 行,尝试着经过自动加载机制找到视图文件。找不到,抛异常。

  6. 168 行,很重要(划重点),该方法是将压进来的数组形式的数据扩展开成 $key=$value 形式,由于视图是 include 进来的普通 php 所以,在视图中也就能够用 $key 的形式读取到变量的内容。

  7. 174-177 行,开启输出控制缓冲机制,并 include 进来视图,至关于同时执行了这个文件,这个文件中的普通 html 亦或是执行 php 后的输出,都会被输出缓冲接收到并赋值给了 $output 。

  8. 179-182 行,前边的缓存是处理读取过程,这里是处理写入过程。

  9. 183 行,最后返回渲染结果。

结语

从源码上看, CI 使用了原始 PHP 做为模版机制使得视图逻辑很是简单。无非也就是把视图 include 进来,用输出缓冲把执行结果拿到便可。

此文能够转载,但转载前须要发邮件到imustgxd*sina.cn进行沟通,未沟通的均视做侵权。 转载同时需注明连接,并保留此段文字。

相关文章
相关标签/搜索