如何扩展第三方库中两个类的公共父级?

时间:2011-07-28 01:16:56

标签: php zend-framework

我通过创建扩展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 个答案:

答案 0 :(得分: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 :(得分:1)

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

复杂的继承是邪恶的。