如何扩展第三方库中两个类的共同父类


How to extend the common parent of two classes in a third party library?

我已经从http://www.davegardner.me.uk/blog/2011/03/04/mocking-iterator-with-phpunit/实现了mockiterator解决方案,通过创建扩展Zend_Test_PHPUnit_DatabaseTestCaseZend_Test_PHPUnit_ControllerTestCase的类,并将方法放入每个子类。

然而,我也最终在这个过程中添加了一些调整,但是必须在每个类中进行相同的更改以防止发散行为是一种痛苦。

两个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测试用例类重写我的库。

在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!

不要欺骗:将您的公共代码重构为函数,或者最好是一个不从任何东西派生的类。然后仅仅在Zend_Test_PHPUnit_ControllerTestCase和Zend_Test_PHPUnit_DatabaseTestCase中使用这些函数或类(实例化,而不是作为基类)。

复杂继承是邪恶的