深入認識view()方法:
我們知道$this->load->view(視圖路徑,資料陣列)就能回傳一個視圖到使用者端。想必這個函式必需打印出視圖程式碼出來才行。究竟它是如何完成這樣的任務呢?為了能夠更靈活地使用這個方法且避免誤解而發生非預期性的錯誤,決定把這方法的流程跑一次。
單看CI_loader中的view()方法,內容僅是做個函式轉向:
public function view($view, $vars = array(), $return = FALSE )
{
return $this->_ci_load(array(
'_ci_view' => $view,
'_ci_vars' =>$this->_ci_prepare_view_vars($vars),
'_ci_return' => $return ) );
}
以上可以得知,view()有三個參數:$view, $vars, $return
其中,$view為必需,後2個參數為選用。
view()函式把主要的工作轉由$this->_ci_load()來完成;
_ci_load()的參數只需要一個關聯式陣列。
$view:視圖檔的路徑;
$vars:所夾帶的資料檔(需以array型態傳送),
$return:內容是否回傳。TRUE=回傳內容。FALSE=回傳 $this(即Loader)
正開始分析_ci_load() 的工作內容
protected .function _ci_load($_ci_data) //僅有一個參數
1、為資料$_ci_data先做默認設定,即以四個索引鍵名來定義變數:
$_ci_view=$_ci_data[‘_ci_view’] 或 FALSE;
$_ci_vars=$_ci_data[‘_ci_vars’] 或 FALSE;
$_ci_path=$_ci_data[‘_ci_path’] 或 FALSE;
$_ci_return=$_ci_data[‘_ci_return’] 或 FALSE;
註:以三元運算取值,若該值未設置則先設為FALSE
$file_exists= FALSE; //我們用不到它,函式以它判斷是否需中止函式
至此,共預設了五個變數的默認值。
2、為被請求檔案設定路徑 $_ci_path:(若無法完成將回傳錯誤訊息)
若$_ci_path是個字串且不為空字串時,則從這字串中取得檔名,
並將檔名存放在$_ci_file變數中。
若有$_ci_path就不再以$_ci_view 檔來製作 $_ci_path。
若要$_ci_path則以APP\views\$_ci_view做為 $ci_path。
(其中,$_ci_view透過判斷以確保含有’php’副檔名)
註:以上,取得$_ci_path且確認是個有檔案的路徑。
3、引入CI_controllor超級物件,目的是取其所有的物件變數:
$_ci_CI =& get_instance(); //此為CodeIgniter.php的調用CI物件函式。
利用get_object_vars($obj)這個函式取得CI中的所有變數;
由於上面函式會回傳關聯陣列,可利用其索引再作判斷,
沒有要將全部物件都引用,僅為louder.php中預先設定的變數賦值。
註:由於上面動作已經讓load物件的預設變數都指向物件了,因此,可以使用loader的var()方法來提那些變數,例如:$this->load->var(‘_ci_models’)
因此,由多個視圖所組成的頁面視圖都能享有這些變數。
4、緩存輸出的內容(Output Buffer)及發佈程序:
設置緩存的目的:1、提昇執行速度。2、利用「輸出類」來完成最終板型的「發佈程序」。「發佈程序」是用來計算出輸頁面的時間。
(一邊製作視圖一邊傳送視圖,會造成輸出頁面時間算不精準)
開啟出輸緩存區:ob_start()
其實,php已預設開啟這個輸出緩存,不曉得為啥還要再開它,難道是CI一開始會先送出緩存嗎?關於輸出緩存留到最後補充。
開啟輸出緩存後,為避免php版本不同而發生無法辨識縮碼的錯誤,因此,再引進視圖前會先判斷是否需要把內容中的「<?、<?=」這些縮碼還原成不使用縮碼的表示法,並確保「?>」的前面有空格及結尾分號。
註:上面是echo eval()完成取代及輸出,由於eval()不允許「進入/離開」php環境的指令(如:<?php...?>),卻允許先離開再進來php環境的指令,因此需要在引入檔前加上「?>」字串。
若判斷不需要取代縮碼時,則是直接:include($_ci_path);
此時視圖已經做好了,但還沒出輸到使用者端。
通常html語法不可以直接在php環境中出現,我們可以使用echo指令將html語法送到輸出暫存,或者先以「?>」離開php環境,好讓php環境外的語法直接被視為輸出內容而傳送至暫存。
不過,這裡發現一個php的特性,若是採用引入檔案的方式時,檔案內容中的html語法會直接被視為輸出而轉送到出輸暫存;內容中的php語法仍會照常執行。
把引入檔視為「直接將內容寫入當前腳本」並不貼切。因為php其實是轉去先執行了另一個腳本,而該腳本若有php語法全歸於php腳本(屬於php的語法全都寫在同一腳本);引入檔中的非php語法都會被視為是輸出。換句話說,一旦引入檔中出現了php不懂的內容都是輸出。
例如:在引入檔起始處打上「?>」會被當作是字串直接輸出。
5、後續收尾動作:
1、製作操作日誌:log_message('info', 'File loaded: '.$_ci_path);
2、依據第3參數($_ci_return)的設置決定回傳內容:
若$_ci_return=TRUE 則 $buffer = ob_get_contents();
return $buffer;
3、判斷是否要現在就送出緩存內容。
判斷式在「ob_get_level() > $this->_ci_ob_level + 1」時才會送出緩存;
而變數$_ci_ob_level並沒被賦值過(可以當它是0);
顯然view()肯定不採這個方案了;另一個替代方案是:
$_ci_CI->output->append_output(ob_get_contents());
@ob_end_clean();
return $this; //這裡的$this 是Loader
把輸出內容轉交給 Output 物件後,就直接清處緩存。
而output->append_output() 僅是把的視圖內容附加於$final_output變數中,
打算把所有視圖都收齊了再一起送出。
$this->final_output .= $output;
return $this; //這裡的$this 是Output
雖然在操作上只要完成 $this->load->view(); 動作就算是送出視圖了,不過,從程式的流程看來,這樣的動作仍只是賦值好相關的變數。顯然,輸出視圖的工作仍究是回到CodeIgniter.php這個檔案中執行。
CodeIgniter.php檔案中的到數第二個動作:
if ($EXT->call_hook('display_override') === FALSE)
{
$OUT->_display(); //這裡的$OUT就是Output 物件
}
$EXT代表的是Hooks物件(就直接稱它為勾子吧!),
若在config.php中使用預設不用勾子:$config['enable_hooks'] = FALSE;
因此上述的判斷式將必定符合,於是,執行Output物件的_dispaly()方法。
$OUT->_display();若沒有特殊設定的話,如同直接echo $final_output;
補充:緩取區的幾個較常用函式:
ob_start() |
開啟緩存。(有三個選用參數可用) |
ob_get_contents(void) |
取得緩存內容。(回傳字串) |
ob_end_flush(void) |
送出緩存。(無回傳值) |
ob_end_clean(void) |
拋棄緩存內容。(無回傳值) |
ob_get_level(void) |
回傳嵌套級別(整數)。若緩存取無回應則回傳0 |
ob_start([ 回調函式 [ ,緩存大小 [ ,旗標 ]]] ) : bool
這兒就不細說了,有需要再查手冊吧!(預設緩存大小最大為 4096 bytes )
沒開緩存的情況下,在php中使用了echo這類的輸出指令時,輸出內容將隨即被送到使用者端,若其底下的還有程式碼則繼續執行並繼續傳送。此外,在php語法區(<?php…?>)以外的內容也會被視為輸出內容而直接送到使用者端。
送到使用者端的內容會先放在瀏覽器的暫存器中(cache),暫存需累積到一定的大小才會擠到瀏覽器中顯示,或者當取得全部頁面內容時也會直接顯示。php預設會開啟輸出緩存,若不想要預設開啟輸出緩存的話,可以修改php.ini檔:implicit_flush=on //預設是OFF
開啟輸出緩存的情況下,接下來的輸出內容都會被另存到伺服器的緩存區裡而不是送給使用者,直到腳本跑完或是以指令送出緩存內容時,才會將緩存區裡的內容全送到使用者端。