代码之家  ›  专栏  ›  技术社区  ›  Tyson of the Northwest

扩展、实现或跟踪以防止引用循环

  •  2
  • Tyson of the Northwest  · 技术社区  · 12 年前

    我有一个包含其他对象的对象,这些对象可以想象为包含对象。

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

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

    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)
        }
      }
    }
    

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

    或者我应该将功能作为特征传递给类?理论上,这听起来是最好的选择,但我没有太多关于特质和自动加载它们的经验。

    我会使用implement,但测试和跟踪不会随类而变化。

    1 回复  |  直到 12 年前
        1
  •  1
  •   Arius    12 年前

    正如您所认识到的,实现接口在您的情况下是不够的。扩展缺乏灵活性。所以最好的方法是使用特质。

    就我个人而言,我会结合特质和界面。它们易于使用,并且可以很好地扩展/实现其他功能。例子:

    特质

    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()方法都存在。由于这个特性,我们在不影响类扩展能力的情况下实现了它们。干杯

    推荐文章