1

这是我在方法链接时发现的一个有趣的怪癖,我很难绕过它。我确定有解决方案或其他方式。这很难解释,但我会尽力而为。

例子:

您拥有三个属于类的函数,以及如下 2 个受保护的属性。

class Chain {

  protected $_str  = '';
  protected $_part = 0;

  public function __toString() {
    return implode(' ', $this->_str);
  }

  public function AAA () {
    $this->_str[$this->_part] = 'AAA';
    $this->_part++;
    return $this;
  }

  public function BBB () {
    $this->_str[$this->_part] = 'BBB';
    $this->_part++;
    return $this;
  }

  public function wrap ($str) {
    $part = $this->_part - 1;
    $this->_str[$part] = "({$str})";
    return $this;
  }

}

现在,当链接这些方法,特别是使用 wrap 方法时,先前链中的字符串会无意中附加。例子:

$chain = new Chain();
$chain->AAA()->BBB()->wrap($chain->AAA());
echo $chain;

您期望字符串的样子是AAA BBB (AAA).

但是,实际返回的是AAA BBB (AAA BBB AAA).

Why is it that wrap() takes all the previous methods called within the chain instead of only the method that's actually wrapped by it? What is the best way around this assuming there is one?

4

3 回答 3

2

$chain->AAA()->BBB() is doing the first two 'AAA' and 'BBB' - obvious.
Then the $chain->AAA() which comes inside wrap($chain->AAA()) does the 3rd 'AAA'.
and last, the wrap method takes all the three and wraps them with () and concatenated to the first 'AAA' and 'BBB' using this line: $this->_str[$part] = "({$str})";
which resolves to: AAA BBB (AAA BBB AAA).

UPDATE:
I believe that what you're trying to do, is to avoid the side-effect of returning this from methods AAA() and BBB() - will be achieved with the following changes:

<?php
class Chain {

  protected $_str  = '';
  protected $_part = 0;

  public function __toString() {
    return implode(' ', $this->_str);
  }

  public function AAA () {
    $this->_str[$this->_part] = 'AAA';
    $this->_part++;
    return "AAA";
  }

  public function BBB () {
    $this->_str[$this->_part] = 'BBB';
    $this->_part++;
    return "BBB";
  }

  public function wrap ($str) {
    $part = $this->_part - 1;
    $this->_str[$part] = "({$str})";
    return $str;
  }

}

$chain = new Chain();
$chain->AAA();
$chain->BBB();
$chain->wrap($chain->AAA());
echo $chain->__toString();

?>
于 2012-07-15T03:41:20.470 回答
1

I'd call it kind of a 'race condition'. It seems PHP first interprets the $chain->AAA()->BBB().

Then $chain->_part is 2 and $chain->_str is 'AAA BBB'.

Then, to be able to call wrap, the argument, so $chain->AAA() is run.

Then $chain->_part is 3 and $chain->_str is 'AAA BBB AAA'.

Finally wrap is called, warpping up the 'AAA BBB AAA'. I would seperate the wrap()-call and reset $chain->_part back to zero in between.

于 2012-07-15T03:43:09.397 回答
0

The calling queue is:

1. $chain->AAA() //this is first method not in wrap() method, you have now AAA
2. $chain->BBB() //then next method, you have now AAA BBB
3. $chain->AAA() //again AAA() method inside wrap method, so you have AAA BBB AAA

inside the wrap() you are putting chain(which is AAA BBB AAA after 3rd step) string in () so you have AAA BBB AAA string at the end of _part array.

于 2012-07-15T03:50:17.923 回答