轉載請註明出處:http://blog.csdn.net/jh_zzzphp
這一塊比較複雜,我尚未徹底理解爲何要把 SQL 語句的組裝搞這麼複雜。mysql
從一個普通皮膚頁面開始 themes/default/index.php ,代碼以下:sql
<?php while ($this -> next()): ?>函數
< div class ="post">typecho
< h2 class ="entry_title">< a href ="<?php $this -> permalink() ?>"><?php $this ->title() ?></ a ></ h2 >post
< p class ="entry_data">fetch
< span ><?php _e(' 做者: ' ); ?><?php $this -> author(); ?></ span >this
< span ><?php _e(' 發佈時間: ' ); ?><?php $this -> date('F j, Y' ); ?></ span >spa
< span ><?php _e(' 分類: ' ); ?><?php $this -> category(',' ); ?></ span >.net
< a href ="<?php $this -> permalink() ?>#comments"><?php $this -> commentsNum('No Comments' , '1 Comment' , '%d Comments' ); ?></ a >
</ p >
<?php $this -> content(' 閱讀剩餘部分 ...' ); ?>
</ div >
<?php endwhile ; ?>
從上面咱們知道這個文件是在 Widget_Archive 執行時被 包含進來的,因此在這裏 $this 就是 Widget_Archive ,next() 函數具體實如今 Typecho_Widget 中,他只是從 $stack 中取出一行數據返回,而後移向下一行, $stack 中的數據是如何生成的呢?
在 Widget_Archive 的 execute 函數中,有這幾行:
$select = $this -> select()-> where ('table.contents.status = ?' , 'publish' )
-> where('table.contents.created < ?' , $this -> options-> gmtTime);
… 中間代碼略過 …
$select -> order('table.contents.created' , Typecho_Db:: SORT_DESC)
-> page($this -> _currentPage, $this -> parameter-> pageSize);
$this -> db-> fetchAll ($select , array ($this , 'push' ));
下面是 Widget_Abstract_Contents:: select() 函數的具體實現:
return $this -> db-> select ('table.contents.cid' , 'table.contents.title' ,'table.contents.slug' , 'table.contents.created' , 'table.contents.authorId' ,
'table.contents.modified' , 'table.contents.type' , 'table.contents.status' ,'table.contents.text' , 'table.contents.commentsNum' , 'table.contents.order' ,
'table.contents.template' , 'table.contents.password' , 'table.contents.allowComment' ,'table.contents.allowPing' , 'table.contents.allowFeed' ,
'table.contents.parent' )-> from ('table.contents' );
$this->db 是 Typecho_Db 對象,是 在 Widget_Abstract 初始化時賦值的:
$this -> db = Typecho_Db:: get();
這個值實際上是在 config.inc.php 中建立的,在安裝的時候根據用戶選擇生成的:
$db = new Typecho_Db('Mysql' , 'typecho_' );
… 中間略過
Typecho_Db:: set($db );
再看看 Typecho_Db 的 select() 函數,
return call_user_func_array(array ($this -> sql() , 'select' ), $args ? $args : array ('*' ));
$this->sql() 返回一個 Typecho_Db_Query 對象,因此上面這句是調用 Typecho_Db_Query 的 select 函數並將相應的參數傳給它, Typecho_Db_Query 會通過一系列的處理最終生成 SQL 語句,這裏再也不具體看了。
看看生成好的語句是怎麼執行的,在最前面提到有這句代碼:
$this -> db-> fetchAll($select , array ($this , 'push' ));
Typecho_Db 的 fetchAll 具體實現以下:
public function fetchAll($query , array $filter = NULL )
{
// 執行查詢
$resource = $this -> query ($query , self:: READ);
$result = array ();
/** 取出過濾器 */
if (! empty ($filter )) {
list ($object , $method ) = $filter ;
}
// 取出每一行
while ($rows = $this -> _adapter-> fetch ($resource )) {
// 判斷是否有過濾器
$result [] = $filter ? call_user_func (array (& $object , $method ), $rows ) : $rows ;
}
return $result ;
}
首先執行 query() , query() 函數會執行:
$resource = $this -> _adapter-> query($query , $handle , $op , $action );
而後將查詢的結果返回,根據上面提到的 config.inc.php ,這裏的 _adapter 是 Typecho_Db_Adapter_Mysql ,他其實就是執行了一個 mysql 查詢:
if ($resource = @ mysql_query($query instanceof Typecho_Db_Query ? $query -> __toString() :$query , $handle )) {
return $resource ;
}
這裏的 $query->__toString() 會返回通過 Typecho_Db_Query 處理後的 最終用來執行的 SQL 語句。
獲得查詢結果後,上面的 fetchAll 函數就循環調用回調函數將數據回調出去,前面的代碼中 Widget_Archive 在調用時指定的是 push ,在 push 函數中返回的每一行數據都被壓入 $stack ,這樣 $stack 中就有了一行行的數據了。