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進行溝通,未溝通的均視做侵權。 轉載同時需註明連接,並保留此段文字。

相關文章
相關標籤/搜索