談php設計模式介紹——偽對象模式(3)_PHP教程
推薦:解析php字符串處理函數addcslashes 為字符串里面的部分字符添加反斜線轉義字符 addslashes 用指定的方式對字符串里面的字符進行轉義 bin2hex 將二進制數據轉換成十六進制表示 chr 返回一個字符的ASCII碼 chunk_split 按一定的字符長度將字符串分割成小塊 convert_cyr_string 將斯
重構已有程序
下面讓我們用偽對象來幫助重構一個已有程序。考慮一個簡單的腳本,它可以模擬你在無數的PHP程序中所期望的行為:例如一個當檢查到你未登錄時要求登錄的頁面;與此類似的還有表單處理頁面;它能在成功登錄后顯示不同內容并提供登出的功能。 讓我們寫一個這樣的頁面。首先,對還未登錄的用戶顯示一個登錄表單。
<html>
<body>
<form method=”post”>
Name:<input type=”text” name=”name”> Password:<input type=”password” name=”passwd”>
<input type=”submit” value=”Login”>
</form>
</body>
</html>
接著,顯示登錄成功后的內容:
<html>
<body>Welcome <?php echo $_SESSION[‘name’]; ?>
<br>Super secret member only content here.
<a href=”<?php echo SELF; ?>?clear”>Logout</a>
</body>
</html>
加入表單處理的功能,session(會話)開始,還有登出的功能,整體看起來應該類似這樣:
session_start();
define(‘SELF’,
‘http://’.$_SERVER[‘SERVER_NAME’].$_SERVER[‘PHP_SELF’]);
if (array_key_exists(‘name’, $_REQUEST)
&& array_key_exists(‘passwd’, $_REQUEST)
&& ‘admin’ == $_REQUEST[‘name’]
&& ‘secret’ == $_REQUEST[‘passwd’]) {
$_SESSION[‘name’] = ‘admin’;
header(‘Location: ‘.SELF);
}
if (array_key_exists(‘clear’, $_REQUEST)) {
unset($_SESSION[‘name’]);
}
if (array_key_exists(‘name’, $_SESSION)
&& $_SESSION[‘name’]) { ?>
<html>
<body>Welcome <?=$_SESSION[‘name’]?>
<br>Super secret member only content here.
<a href=”<?php echo SELF; ?>?clear”>Logout</a>
</body>
</html> <?php
} else { ?>
<html>
<body>
<form method=”post”>
Name:<input type=”text” name=”name”> Password:<input type=”password” name=”passwd”>
<input type=”submit” value=”Login”>
</form>
</body>
</html> <?php
}
重構這個程序的一個目的應該是使其成為一個“易于測試”的程序。基于這個目的,如果你還選擇一些PHP中的方便特性——如超級全局變量——你將失去測試上的簡潔性。
例如,如果你直接就用了$_SESSION,即意味著只有一種途徑可以測試這個代碼,就是改變$_SESSION。如果你忘了將$_SESSION改回先前已知的狀態,各種測試間就會互相干擾。
一個好的解決方法是封裝$_SESSION到另一個類中,傳遞所封裝類的實例到任何想要訪問$_SESSION的對象。如果你創建了一個已封裝對象的偽對象用于測試,你能夠完全控制對象對所調用方法的響應(就像ServerStub那樣)并且你能核實它是如何調用的(那正是創建偽對象的目的)。
具備了這個思想,讓我們看看如何封裝$_SESSION之類的全局變量。
class Session {
function Session() {
$this->init();
}
function init() {
if (!isset($_SESSION)) {
if (headers_sent()) {
trigger_error(
‘Session not started before creating session object’);
} else {
session_start();
}
}
}
function isValid($key) {
return array_key_exists($key, $_SESSION);
}
function get($key) {
return (array_key_exists($key, $_SESSION))
? $_SESSION[$key]
: null;
}
function set($key, $value) {
$_SESSION[$key] = $value;
}
function clear($key) {
unset($_SESSION[$key]);
}
}
類Session封裝了全局變量$_SESSION。對類SESSION的測試非常類似于對前期的已注冊的類的改良測試(參見第5章),但是卻無任何通過參數獲得或設置相應值的意圖。
你也許注意到了構造函數調用了Session::init()方法。為什么這個方法不是構造函數的一部分呢?這樣分開的好處是你能靜態調用它并確保session已經開始。下面是一個如何使用該類的例子。
Session::init();
$page =& new PageDirector(new Session);
大部分測試方面的文獻很推崇偽對象并建議你親自寫一個。如果你打算那樣做,開始測試時你就只需要充實那些你需要的方法就可以了。譬如,一個用于處理代碼的ServerStub的Session類很可能是這樣的:
class MyMockSessionUser1 {
function isValid($key) {
return (‘user_id’ == $key) ? true : false;
}
function get($key) {
if (‘user_id’ == $key) {
return 1;
}
}
}
幸運的是,你可以用SimpleTest來避免那些易范的錯誤。Mock::generate()方法允許你創建一個類來實例化或動態地配置你想要的結果。
注:偽對象技術
SimpleTest所使用的方法僅是偽對象的多種用法之一。偽對象的代碼傳遞是另一種。隨著PHP5的到來,你也許能看到偽對象以對象中的__call()方法來執行。
以下是如何用SimpleTest生成的偽對象來測試并重構MyMockSessionUser1類(如上例中)。
Mock::Generate(‘Session’);
class PageDirectorTestCase extends UnitTestCase {
function testSomethingWhichUsesSession() {
$session =& new MockSession($this);
$session->setReturnValue(‘isValid’, true);
$session->setReturnValue(‘get’, 1);
// ...
}
}
分享:怎樣把握技巧開發PHP網站1.使用 ip2long() 和 long2ip() 函數來把 IP 地址轉化成整型存儲到數據庫里。這種方法把存儲空間降到了接近四分之一(char(15) 的 15 個字節對整形的 4 個字節),計算一個特定的地址是不是在一個區段內頁更簡單了,而且加快了搜索和排序的速度(雖然有時僅
- 相關鏈接:
- 教程說明:
PHP教程-談php設計模式介紹——偽對象模式(3)。