返璞歸真:PHP中面向過程的裝飾模式實現

作者: 老王  來源: 老王的技術手冊  發布時間: 2010-12-05 14:37  閱讀: 915 次  推薦: 0   原文鏈接   [收藏]  

  本文可以看做是Web框架審美觀一文的延續,在那篇文章里,我闡述了如何用面向對象實現裝飾模式,不過鑒于PHP的本質就是面向過程的,讓我對純粹的OOP有些拿不定主意,于是本文便走向另一個極端,準備闡述一下如何用面向過程實現裝飾模式。

  廢話少說,直接貼代碼(代碼僅在PHP5.3以上版本有效,用到了header_remove函數),大概涉及以下幾個文件:

 
bootstrap.php:

01 function execute_action($name = null)
02 {
03 static $action;
04 static $wrappers;
05
06 if ($name !== null) {
07 $action = $name;
08 }
09
10 if ($wrappers === null) {
11 $config = include 'config.php';
12 $wrappers = $config[$action];
13 }
14
15 if (list($wrapper, $param) = each($wrappers)) {
16 extract($param);
17 array_shift($wrappers);
18
19 return include $wrapper . '_wrapper.php';
20 }
21
22 ob_start();
23
24 include $action . '_action.php';
25
26 return ob_get_clean();
27 }
28
29 echo execute_action('foo');

  說明:這里的static變量是面向過程裝飾模式的實現關鍵,它會控制程序依次執行所有的裝飾器和動作。

 
config.php:

01 return array(
02 'foo' => array(
03 'bar' => array('param_a' => '[a]', 'param_b' => '[b]'),
04 // other wrappers
05 ),
06 // other actions
07 );

  說明:配置文件使用的是直接return的方式,在include的時候可以接收到參數,里面可以針對動作設置裝飾器,并且可以設置裝飾器的參數。

 
bar_wrapper.php:

01 $result = execute_action();
02
03 header_remove('Location');
04
05 return $result . $param_a . $param_b;

  說明:在裝飾器里可以修改響應頭,還可以修改響應內容,注意結果是return的,不是echo的。

 
foo_action.php:

01 header('Location: http://www.baidu.com/');
02 // exit; or return;
03
04 echo 'hello, world.';

  說明:在動作里沒有任何特殊性,就是頁面控制器風格,這樣可以兼容最一般的PHP編程風格。

  把以上文件保存到根目錄,然后瀏覽bootstrap.php就可以看到效果:hello, world.[a][b]。全部代碼都是面向過程的,和面向對象不沾邊,對PHP這樣的瞬態執行的語言來說,這樣可以實現效率最大化。再看細節,雖然我們在動作文件里設定了跳轉,但是在裝飾器文件里可以刪除這個響應頭,從而達到透明修改的裝飾目的,裝飾器對動作的修改沒有任何侵入性設計。以此為基礎,可以實現一個相當靈活的Web框架(VC of MVC),既能保證效率,又可以兼顧擴展性。不過這樣的設計也有一些弱點,比如說可測試性會有點麻煩,另外,沒有了OOP,顯得有些土氣(如果你這樣認為的話)。

  注意:由于在操作action和wrapper的時候,使用的是include方式,所以可能會帶來變量污染的問題,一般來說,只要稍加注意不會出大問題,不過如果有完美主義傾向,可以使用PHP5.3新加入的閉包特色來規避這類問題:function() use(...) { include ... };,但效率會略微降低一點。

  補充:肯定會有人鄙視這樣的面向過程風格的代碼,其實大可不必,我記得以前有好事者曾經問過CPP之父一個尖銳的問題:和Ruby這樣百分百面向對象的語言相比,CPP是不是顯得不夠好?CPP之父回答道:我不認為百分百面向對象是優點!對于PHP來說,我也認為百分百面向對象不可取,當然百分百面向過程也不可取,在我看來更合理的方式是:如果按MVC算的話,M應該是面向對象的,而VC則應該是面向過程的,這樣可以達到一個合理的平衡點。

0
0
 
標簽:PHP
 
 

文章列表

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()