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