《PHP设计模式介绍》第六章 伪对象模式(2)_PHP教程
推荐:《PHP设计模式介绍》第五章 注册模式我们通常认为避免使用全局变量是一种好的选择,因此,对象经常被作为参数从一段代码传递到另一段。但是传递实例的一个问题就是对象有时候不知道将要传递给谁——?经过一个函数后才被传
具备了这个思想,让我们看看如何封装$_SESSION之类的全局变量。
class Session { |
你也许注意到了构造函数调用了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); // ... } } |
更进一步说,你能随心所欲的设置何种方法被调用以及调用多少次。你甚至可以验证那些根本不该被调用的方法。
下面是一个扩展型的测试,它用来建立和验证那些复杂的设计。
class PageDirectorTestCase extends UnitTestCase { function testSomethingWhichUsesSession() { $session =& new MockSession($this); $session->setReturnValue(‘isValid’, true); $session->setReturnValue(‘get’, 1); $session->expectOnce(‘isValid’, array(‘user_id’)); $session->expectOnce(‘get’, array(‘user_id’)); $session->expectNever(‘set’); // the actual code which uses $session $session->tally(); } } |
使用伪对象的原因很多,方法也多样化。但在我们继续前,让我们把另外的一些类加入进来,使其来龙去脉更加清楚。
接下来的一部分是重构已有脚本,创建一个用于检查用户是否有相应权限的名为UserLogin的类。
class UserLogin { var $_valid=true; var $_id; var $_name; function UserLogin($name) { switch (strtolower($name)) { case ‘admin’: $this->_id = 1; $this->_name = ‘admin’; break; default: trigger_error(“Bad user name ‘$name’”); $this->_valid=false; } } function name() { if ($this->_valid) return $this->_name; } function Validate($user_name, $password) { if (‘admin’ == strtolower($user_name) && ‘secret’ == $password) { return true; } return false; } } |
最后一部分是创建响应。为了最终在浏览器中显示,我们必须处理那不断增长的HTML内容,如果必要的话我们也会讨论HTTP重定向。(你也可以执行其他的http头的操作——这样说是为了能构隐藏它——在一个成熟的做法中,但这里使用的是一段更简单的代码,是为了使例子容易理解与关注。)
class Response { var $_head=’’; var $_body=’’; function addHead($content) { $this->_head .= $content; } function addBody($content) { $this->_body .= $content; } function display() { echo $this->fetch(); } function fetch() { return ‘<html>’ .’<head>’.$this->_head.’</head>’ .’<body>’.$this->_body.’</body>’ .’</html>’; } function redirect($url, $exit=true) { header(‘Location: ‘.$url); if ($exit) exit; } } |
给出了这些模块后,也是时候将这些新开发的、已测试的组件聚合到一个页面中了。让我们写一个最终的类来协调这个页面的所以行为,取个合适的名字PageDirector。类PageDirector具有一个很简单的运用程序接口:你在实例化后可以用调用它的run()方法。
分享:《PHP设计模式介绍》第四章 单件模式几乎所有面向对象的程序中,总有一两个资源被创建出来,在程序应用中持续被共享使用。例如,这样的一个资源,在一个电子商务程序的数据库连接中使用:这个连接在应用程序启动时初始化,程序于是
- 相关链接:
- 教程说明:
PHP教程-《PHP设计模式介绍》第六章 伪对象模式(2)。