0

代码示例是我正在处理的一个简单示例。我在 php 中有 2 个类。

class Wrap {

    public function wrapA($arg){
        return 'A'.$arg.'A';
    }

    public function wrapB($arg){
        return 'B'.$arg.'B';
    }

}

class Child extends Wrap {

    public $OUT;

    public function wrapA($arg){
        $this->OUT .= parent::wrapA($arg);
    }

    public function wrapB($arg){
        $this->OUT .= parent::wrapB($arg);
    }

    public function __destruct(){
        echo $this->OUT;
    }

}

$X = new Child();

$X->wrapA(
    $X->wrapB('CC')
);

这里的输出是“ BCCBAA ”。但我试图实现的是“ ABCCBA ”。“Wrap”类必须是这种形式。

…如果我有以下方法调用:

$X->wrapB( $X->wrapA('1') );

$X->wrapA( $X->wrapB('aa') .$X->wrapA('bbb') .$X->wrapB( $X->wrapA('cccc') ) );

…我想要以下输出:BA1ABABaaBAbbbABAcccABA

还有其他方法吗?

我还希望 Wrap-Class 单独工作(没有 Child)……这就是方法具有返回值的原因。

但是在 Child-Class 中,我想将返回值写在一个变量中。

提前谢谢!

4

2 回答 2

3

那是因为$X->wrapB('CC')不返回任何东西,并且在$X->wrapA()被调用时被强制转换为空字符串,因此A什么都没有。

但是,因为您附加BCCB$X->OUT,所以当您调用 时$X->wrapA(),它会附加AA到那个,导致BCCBAA.

又看了一遍问题,觉得应该换个方式解决;这是需要考虑的事情:

class Wrap
{
    // The wrapping itself can be declared as a static method
    protected static function wrapWithChar($arg, $ch)
    {
        return $ch . $arg . $ch;
    }
}

class Child extends Wrap
{
    protected $OUT;

    // we allow the internal state to be set upon construction
    public function __construct($s = '')
    {
        $this->OUT = $s;
    }

    // no arguments required here, this gets applied on the internal state
    public function wrapA()
    {
        $this->OUT = self::wrapWithChar($this->OUT, 'A');
        // return instance to allow chaining
        return $this;
    }

    public function wrapB()
    {
        $this->OUT = self::wrapWithChar($this->OUT, 'B');
        return $this;
    }

    public function __toString()
    {
        return $this->OUT;
    }

    public function __destruct(){
        echo $this->OUT;
    }

}

// initialize with 'CC'    
$X = new Child('CC');

// wrap B around it; becomes 'BCCB'
$X->wrapB();
// wrap A around that; becomes 'ABCCBA'
$X->wrapA();

// example of chaining
$Y = new Child('ZZ');
// wrap B then A around it; becomes 'ABZZBA'
$Y->wrapB()->wrapA();

旧答案

为了使Child看起来Wrap可以执行,您可以使用__toString()魔术方法(使用instanceof会更明确,但也需要更多工作):

class Child extends Wrap
{
    public $OUT;

    public function wrapA($arg)
    {
        $this->OUT = parent::wrapA($arg);
        return $this;
    }

    public function wrapB($arg)
    {
        $this->OUT = parent::wrapB($arg);
        return $this;
    }

    public function __toString()
    {
        return $this->OUT;
    }

    public function __destruct(){
        echo $this->OUT;
    }
}

每个wrapX()方法现在都返回实例本身,并__toString()在需要包装时被调用。

以上将产生正确的结果。

于 2012-10-16T09:43:03.380 回答
1

我将此添加到我的收藏夹中,作为一个有趣的谜题来解决。

然后醒了再看问题发现没那么复杂。老实说,我认为此时您不应该使用子类化,因为从技术上讲,它Child在逻辑上不是该类的子Wrap类,它本质上似乎是一个想要存储 wrap 结果输出的人。

所以.. 这是我的修改,适用于您的原始界面。希望它对你有好处;)。

它使用了一些非常神奇的魔法方法。

<?php
class Wrap {
    public function wrapA($arg){
        return 'A'.$arg.'A';
    }

    public function wrapB($arg){
        return 'B'.$arg.'B';
    }
}

class WrapReader{
    protected $wrapper;
    protected $currentResult;

    public function __construct(Wrap $wrapper)
    {
        $this->wrapper = $wrapper;
    }

    public function __call($method,$argument)
    {
        $argument = $argument[0];
        if(!method_exists($this->wrapper,$method))
            throw new MethodNotFoundException('Method: '.$method.'() does not exist in class: '.get_class($this->wrapper));
        $this->currentResult = $this->wrapper->$method($argument);
        return $this->currentResult;
    }

    public function __destruct(){
        echo $this;
    }

    public function __toString()
    {
        return $this->currentResult;
    }
}
class MethodNotFoundException extends Exception{}

用法:

$reader = new WrapReader(new Wrap());

echo $reader->wrapB( $reader->wrapA('1') ); 
echo $reader->wrapA( $reader->wrapB('aa') .$reader->wrapA('bbb') .$reader->wrapB( $reader->wrapA('cccc') ) );
echo '<br>';

Outputs BA1ABABaaBAbbbABAccccABA

这是您在原始问题中发布的内容。

于 2012-10-17T09:18:49.703 回答