一步步編寫PHP的Framework(十一)

來源:互聯網
上載者:User

 

之前講了怎麼讓實現跳轉和請求的轉寄,當然,也只是很簡單的說了一下,更深的內容需要你自己去讀一下具體架構的實現。

現在跳轉和轉寄有了,對於模型的編寫可以後面再來,那我就先說一下怎麼講資料從控制器傳遞到視圖,之前我們的實現方式非常醜陋:

1 $viewPath = dirname(__FILE__) . '/../views/index.php';
2 if(file_exists($viewPath)) {
3     include $viewPath;
4 } else {
5     echo 'view does not exists';
6 }

現在我準備用更優雅一點的方式將資料傳遞到視圖,現在先說一下怎麼調用:

01 <?php
02 class TestController extends Controller {
03     public function test() {
04         $this->_assign(array(
05             'arr' => array(
06                 'test','test2'
07             ),
08             'str' => 'it is a str'
09         ));
10         $this->_display('test');
11     }
12 }

 

這就是今天我寫之後的調用方式,如果你學過smarty,那麼你會發現這和smarty很相似,的確,我寫toper的時候也是受了smarty的影響,最開始的想法是視圖這一塊就使用smarty,後面想了一下,既然號稱是自己的架構,那麼視圖這一塊兒肯定也要全部自己寫,雖然如此,但是我後面還是保留了assign,display這種寫法,並且只要設定檔修改,完全可以將視圖切換到smarty而不使用架構本身的實現。

好像扯得有點遠了,首先說一下,為了代碼的簡單,我將assign和display的實現簡化,大家理解思路就好,真實的架構的實現要複雜一些。

首先assign,它的功能是為變數賦值,這裡我假設傳遞的參數都是關聯陣列,也就是常說的HashTable,它不應該直接調用View的介面,這介面實現怎麼賦值:

1 protected  function _assign(Array $arr) {
2         View::assign($arr);
3     }

 

為了處理視圖這一塊的資料存放區和展示,我定義了View.php這個檔案,View::assign這個方法是它的一個靜態方法,當然,實現的功能大家都懂的。。。

            具體View.php中怎麼實現的呢?

1 private static $_data = array();
2     public static function assign($arr) {
3         foreach($arr as $key => $val) {
4             if(!is_int($key)) {
5                 //過濾掉如array('test','test2')這種資料
6                 self::$_data[$key] = $val;
7             }
8         }
9     }

由於assign是靜態方法,資料又需要儲存到這個類,所以需要定義一個靜態成員變數$_data,這個變數儲存控制器傳遞的資料。因為之前在控制器的assign中已經進行了類型提示,所以可以保證在View中的assign傳遞的形參都是數組,現在只需要一個foreach然後依次儲存即可,那為什麼不直接使用self::$_data = $arr呢,這樣只有一句話呢?

首先,數組中的資料有些可能是不對的,比如array('test','test2')我就不懂資料test和test2到底代表了什麼,這樣的資料應該在assign中就被剔除掉,如果你要求比較嚴苛,也可以直接給使用者提示警告。

其次,有可能使用者多次調用assign,如果直接使用引用,那麼第二次調用assign就會把第一次的資料弄丟,這樣是不可容忍的。

好,賦值搞定,然後就是怎麼顯示的問題了,在控制器中,還是直接調用介面,而不負責內部實現,但是在調用介面之前需要進行一定的格式化:

01 protected function _display($str) {
02         if(is_string($str)) {
03             $str = str_replace(array(
04                 '.','#'
05             ),array(
06                 '/','.'
07             ),$str);
08             View::display(MODULES_PATH . View::VIEW_BASE_PATH . $str . '.php');
09         }
10     }

為了視覺上的美觀和其他一些XXX的原因,我們可以將表示路徑的/在作為實參傳遞的時候變成.,這樣假設要調用test/test2.php,那麼只需要傳遞test.test2.php即可。當然,這樣也存在一個問題,有時候需要使用.,就像剛才這個例子,實際上test.test2.php會被解析為test/test2/php,這樣實際上是有問題的,那麼怎麼解決呢,我使用一個#代表.,這樣剛才這個傳遞的時候就變成了test.test2#php。這樣還有一個問題,.php基本上每個頁面都有,那為什麼還要傳遞進去呢,直接架構幫你加上就好了嘛,所以使用者只需要輸入test.test2就好,這樣從邏輯上也容易理解,test模組下面的test2這個視圖檔案。如果你用過thinkphp,你會發現這和它的寫法很類似,實際上我在最開始寫的時候就是邊看thinkphp源碼邊寫的,所以很多東西都借鑒了它的思想。我個人比較討厭使用#,所以我基本上在視圖檔案中沒有使用過#,因為我覺得你自己不會這麼無聊,去寫類似於test.view.php這樣的無意義的檔案名稱,直接test.php就好了,這樣的名字架構又幫你解決了一部分,所以基本上不存在這個問題了。

這兒還出現了一個常量View::VIEW_BASE_PATH,這個常量代表的含義是視圖根目錄的路徑,這樣傳遞進去的實際上是一個實際的絕對路徑。

由於display是展示這個視圖檔案,那麼肯定會使用include某一個檔案,具體的實現如下:

1 public static function display($file) {
2         if(file_exists($file)) {
3             extract(self::$_data);
4             include $file;
5         } else {
6             throw new ViewException(ViewException::NOT_EXISTS_TEMPLATE);
7         }
8     }

extract就是講數組打散,更多的請查詢PHP手冊。

這裡由於可能這個視圖檔案不存在,所以需要判定一下,如果視圖檔案不存在,則直接拋出異常,注意,異常是使用了ViewException,這個類又是新定義的,傳遞的參數表示這個異常是因為視圖模板不存在而引起的。

那我麼來看看具體這個異常類的實現:

01 <?php
02 class ViewException extends BaseException {
03     const NOT_EXISTS_TEMPLATE = 1;
04     public function __construct($code = 0) {
05         switch($code) {
06             case ViewException::NOT_EXISTS_TEMPLATE:
07                 $msg = 'the template file is not exists';
08                 break;
09             default :
10                 $msg = 'unknown exception';
11                 break;
12         }
13         parent::__construct($msg,$code);
14     }
15 }

這個類它繼承了BaseException,由於BaseException實現了debug模式開與關不同情況下展示內容不同,ViewException也具有這個特性,當debug關閉,拋出異常的時候,也只會跳轉到錯誤頁,不會直接展示異常,這樣的處理更易維護。



相關文章

Cloud Intelligence Leading the Digital Future

Alibaba Cloud ACtivate Online Conference, Nov. 20th & 21st, 2019 (UTC+08)

Register Now >

Starter Package

SSD Cloud server and data transfer for only $2.50 a month

Get Started >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。