资讯专栏INFORMATION COLUMN

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

LiangJ / 646人阅读

摘要:行处理视图文件名后缀。结语从源码上看,使用了原始作为模版机制使得视图逻辑非常简单。无非也就是把视图进来,用输出缓冲把执行结果拿到即可。此文可以转载,但转载前需要发邮件到进行沟通,未沟通的均视作侵权。

前言

CI 的 View 没有像 Laravel 等一些流行框架一样设计的那么重,有自己的一套模版机制,CI 一直采用纯天然的 PHP 模板形式,纯天然的好处是不用再学习一套模板语言了,缺点是不能用到一些便利的设计模式,比如不能使用继承布局等等,当然你也可以加第三方的视图组件进来。

下面我们开始看源码,看源码,我们先从视图的调用开始。

视图的调用

CI 4 开始使用新的视图调用逻辑,不在是 load 形式,调用方式如下:

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 ConfigView();
    }

    return new CodeIgniterViewView($config, $viewPath, self::locator(true), CI_DEBUG, self::logger(true));
}

可以看出, view 方法主要 new 了一个 CodeIgniterViewView 类,该类位于 /system/ViewView.php 下。

小结一下,给个分析过程图,以方便理解:

接下来就是我们的主角 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 方法

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

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

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进行沟通,未沟通的均视作侵权。 转载同时需注明链接,并保留此段文字。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/22978.html

相关文章

  • Codeigniter 4.0-dev 源码学习笔记之三——核心文件 Codeigniter.ph

    摘要:行,是否强制访问。行,尝试处理此次请求,详细见方法。至此,的执行主流程完毕。小结是的核心文件,它被调用后,完成了诸多的主流程操作。此文可以转载,但转载前需要发邮件到进行沟通,未沟通的均视作侵权。 前言 Codeigniter.php 是 CI 4 的核心所在,在这里接收并处理了 request 请求,安全检查,缓存处理, URL 解析以及路由匹配,执行过滤器,加载运行 Controll...

    alighters 评论0 收藏0
  • Codeigniter 4.0-dev 源码学习笔记之六——控制器

    摘要:控制器严格来说,这个是控制器父类的源码。在中,控制器仅负责接到返回的组装的页面字符串,并回核心中,由核心再处理后续事宜。此文可以转载,但转载前需要发邮件到进行沟通,未沟通的均视作侵权。 前言 其实一开始我是很纠结是否要写控制器的源码分析的,因为控制器的源码太少了,少到你不相信这是一个 MVC 里的一个重头。直觉里,大家都觉得控制器作为各个请求的入口,其后端应该有很多很多的代码支撑才可以...

    asce1885 评论0 收藏0
  • Codeigniter 4.0-dev 源码学习笔记之五——相对于 3.x 的变化

    摘要:支持命名空间是没有支持命名空间的。配置文件不再是简单数组了新的配置文件是以对象组织的,各个配置以对象的属性形式暴露出来。此文可以转载,但转载前需要发邮件到进行沟通,未沟通的均视作侵权。 前言 CI 为了追上大家的脚步,这次跨了一大步,尽量使用了更多的流行设计理念,甚至连 PHP 的支持版本都是从 7 开始起步的。我在之前阅读源码的同时也发现了很多变化的地方,在此把已经发现的列举出来,不...

    Youngdze 评论0 收藏0
  • Codeigniter 4.0-dev 源码学习笔记之一——前言以及 CI 4 预览

    摘要:版权声明可转载,但不论任何媒体都需要在转载前与本人沟通,并在转载时注明出处。的各个核心模块以模块名为目录名分别存储在这个目录下。下一篇文章会涉及到和。此文可以转载,但转载前需要发邮件到进行沟通,未沟通的均视作侵权。 写在前面: 为什么选择开发过程中的 CI 4 作为源码解读版本:(1)首先我选 CI 是因为它之前的稳定版都是相对比较轻量小巧的,而且可以认为是简单的。(2)为什么没有选...

    MSchumi 评论0 收藏0
  • Codeigniter 4.0-dev 源码学习笔记之二——入口以及初始化操作

    摘要:通过这个函数可以很方便的在程序运行期间执行很多常见操作。此文可以转载,但转载前需要发邮件到进行沟通,未沟通的均视作侵权。 index.php index.php 是整个框架的入口文件,也就是说所有的请求都要从它这里开始。因为 index.php 源码非常简洁,那么我们直接放一张源码截图,按着截图说一下源码。 showImg(https://segmentfault.com/img/re...

    _ivan 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<