扩展,实现或特性以防止参考循环

时间:2014-08-14 23:57:46

标签: php extends traits implements

我有一个包含其他对象的对象,可以想象它们被赋予了包含对象。

$a = new Container();
$b = new Container();
$a->add($b);
$b->add($a);

因此,为了测试这种可能性,我添加了2个函数,确保不会发生闭环。

class Object{
  $contents = array();
  $parents = array();

  function add($content){
    if(is_a($content, "Container")){
      $content->_registerParent($this);
      $this->_checkLoop($content);
      $this->contents[] = $content;
    }
  }

  function _registerParent($parent){
    if(count($this->parents) >0){
      throw new Exception("Closed Reference Loop");
    }
    $this->parents[] = $parent;
  }

  function _checkLoop($child){
    if($child===$this){
      throw new Exception("Closed Reference Loop");
    }
    foreach($this->parents as $parent){
      $parent->_checkLoop($child)
    }
  }
}

这很好用,开销也很低。我希望将此功能扩展到其他类,并需要知道最好的方法。我是否应该使所有可以添加的类和包含其他容器的类扩展根容器对象?扩展可以工作,但我希望可以灵活地将它应用于可能已经扩展另一个类的类。

或者我应该将功能作为特征传递给类?从理论上讲,这听起来是最好的选择,但我对Traits和自动加载没有多少经验。

我会使用工具,但测试和跟踪不会因类而异。

1 个答案:

答案 0 :(得分:1)

当你意识到在你的情况下实现接口是不够的。扩展缺乏灵活性。所以最好的方法是使用Traits。

就个人而言,我会将Traits和Interfaces结合起来。它们易于使用,并且可以很好地扩展/实现其他功能。例如:

<强>性状

trait MyTestTrait
{
    public function registerParent($parent){
        if(count($this->parents) >0){
            throw new Exception("Closed Reference Loop");
        }
        $this->parents[] = $parent;
    }

    public function checkLoop($child){
        if($child===$this){
            throw new Exception("Closed Reference Loop");
        }
        foreach($this->parents as $parent){
            $parent->checkLoop($child)
        }
    }
}

<强>接口

interface MyTestInterface
{
    public function registerParent($parent);
    public function checkLoop($child);
}

课堂上的用法

class Object extends SomeAbstract implements MyTestInterface, AnotherInterface {
    use MyTestTrait;

    $contents = array();
    $parents = array();

    function add($content){
        if(is_a($content, "Container")){
            $content->registerParent($this);
            $this->checkLoop($content);
            $this->contents[] = $content;
        }
    }
}

由于接口,我们确信存在registerParent()和checkLoop()方法。由于特性,我们正在实施它们而不会影响课程扩展的能力。干杯!