2011-07-28 58 views
0

我已經通過創建延伸Zend_Test_PHPUnit_DatabaseTestCaseZend_Test_PHPUnit_ControllerTestCase並將方法放入每個子類的類來實現http://www.davegardner.me.uk/blog/2011/03/04/mocking-iterator-with-phpunit/的mockiterator解決方案。如何在第三方庫中擴展兩個類的共同父項?

但是,我最終還是在這個過程中增加了一些調整,但是爲了防止發散行爲,必須在每個類中進行相同的更改是一件很痛苦的事情。

兩個Zend類都直接從PHPUnit_Framework_TestCase繼承是否有一種方法可以輕鬆地在PHPUnit和Zend類之間插入一個類,它不涉及直接修改Zend庫代碼?我想我在尋找一種簡單的方法做這樣的事情:

+-- PHPUnit_Framework_TestCase 
| 
+-- My_PHPUnit_Framework_TestCase 
    | 
    +-- Zend_Test_PHPUnit_ControllerTestCase 
    +-- Zend_Test_PHPUnit_DatabaseTestCase 

我想,作爲替代方案,我可以在我的圖書館複製兩個Zend類 - 但同樣,有可能會出現問題的時候上傳Zend框架,要求我的庫從新的Zend測試用例類重寫。

回答

2

在PHP中,你有線性單親繼承。不幸的是,這意味着你不能插入一箇中間的代理類而不修改Zend類的源代碼。

如果有必要(比如說,你需要成爲兩個不同DO類的孩子),但是也有辦法僞造多重繼承。

使用,神奇的方法,比如,你可以創建一個多代理:

class MultiProxy 
{ 
    private $poxies; 

    public function __construct(array $arr) 
    { 
     $this->proxies = $arr; 
    } 

    public function __get($name) 
    { 
     foreach($this->proxies as $proxy) 
     { 
      if(property_exists($proxy, $name)) 
      { 
       try 
       { 
        return $proxy->$name 
       } 
       catch(Exception e) 
       { 
        // swallow it. 
       } 
      } 
     } 
     trigger_error("$name not found on $this"); 
    } 

    public function __set($name, $val) 
    { 
     foreach($this->proxies as $proxy) 
     { 
      if(property_exists($proxy, $name)) 
      { 
       try 
       { 
        $proxy->$name = $val; 
       } 
       catch(Exception e) 
       { 
        // swallow it. 
       } 
      } 
     } 
     trigger_error("$name not found on $this"); 
    } 

    public function __call($name, $args) 
    { 
     foreach($this->proxies as $proxy) 
     { 
      $proxy = array($proxy, $name); 
      if(is_callable($proxy)) 
      { 
       try 
       { 
        call_user_func_array($proxy, $args); 
       } 
       catch(Exception e) 
       { 
        // swallow it. 
       } 
      } 
     } 
     trigger_error("$name not found on $this"); 
    } 

    public function __toString() 
    { 
     $ret = "[" . get_class($this) . '::{'; 
     foreach($this->proxies as $proxy) 
     { 
      $ret .= get_class($proxy) . ','; 
     } 
     return substr($ret, 0, -1) .'}]'; 
    } 
} 

// use: 
class Foo{ public $a = 'FOO'; } 
class Bar{ public function doSomething(){ echo 'YAY!'; } } 
class Baz{ public $a = 'BAZ'; public function doSomething(){ echo 'BAAAZ!'; } } 

$foo = new Foo(); 
$bar = new Bar(); // drink! 
$baz = new Baz(); 

$multi = new MultiProxy(array($foo, $bar, $baz)); 
$multi->a = 'MULTI!'; 
echo $multi->a == $foo->a? 1:0; 
$multi->doSomething();// YAY! 
1

做不掛羊頭賣狗肉:重構您的常用代碼函數或更好,但不是從任何派生的類。然後,只需在Zend_Test_PHPUnit_ControllerTestCase和Zend_Test_PHPUnit_DatabaseTestCase中使用這些函數或類(實例化,而不是基類)。

複雜的繼承是邪惡的。

+0

「_Complex inheritance is evil._」?爲什麼? – Tadeck

+0

@Tadeck封裝是面向對象的一大優勢。繼承破壞封裝。見http://en.wikipedia.org/wiki/Design_Patterns –

+0

好源(四人幫,而不是維基百科)。謝謝。 – Tadeck