【问题标题】:Parent Object in phpphp中的父对象
【发布时间】:2011-01-26 06:35:27
【问题描述】:

有没有办法遍历一个对象来获取父对象的数据? 对于“父对象”,我不是指父类,而是字面上的对象。 这是一个例子,在 javascripty 世界中:-) :

$parent->test = "hello world!";

$parent->child = new B();

如果我可以访问子对象中父级的所有数据,那就太好了:

class B{

//I know this doesn't exists, but it's what I wanted do do
    function B(){
        $this->parent = $this->parent();
        echo $this->parent->test; //it would ouput "hello world"
    }
}

目前我的解决方案是将父对象传递给子对象(作为参考)或使父对象成为全局对象。 你有更好的解决方案吗?

谢谢!

【问题讨论】:

  • 这只是两个相互引用的对象。你可以称他们为父母和孩子。
  • 为什么需要孩子引用它的父母?父母中是否有孩子也需要访问的东西?如果是这样,你最好将它可能需要的任何东西传递给孩子,而不是试图从父母那里得到它。
  • 我在父级中有一个“隐私对象”,然后在子级中需要一些变量,并且将它们全部传递下去会很乏味...
  • $child = new B($parent->privacy);会工作? B()的实例需要是$parent的类属性吗?
  • 是的,但这还不够:我需要 $child = new B($parent->user, $parent->privacy, $parent->url);然后为方便起见,我切换到 $child = new B($parent);

标签: php oop class


【解决方案1】:

没有。

您可以使用 $this 从超类访问变量:

<?php
class A {
    public function __construct()
    {
        $this->foo = 'hello';
    }
}

class B extends A {
    public function printFoo()
    {
        echo $this->foo;
    }
}

$b = new B();
$b->printFoo();
?>

【讨论】:

  • 这不是问题所在。他不想访问超类。
  • 我认为这个答案很好(“No.”)。 Sjoerd 还提供了另一种解决方案。
【解决方案2】:

将父母传递给孩子是更好的解决方案。虽然这是一种有点不受欢迎的共生关系。

B() 是否应该知道它所属的对象?很可能不会。这些只是通过组合松散地相关。

为什么 B() 必须是其父级的属性?你需要在 B() 中有这个实现还是应该是父级的一部分?

【讨论】:

  • 经过一个月的 javascript,遍历对象是正常的,我发现 php 在这种情况下太“静态”了。考虑一个 mvc 框架,其中一些属性是在途中而不是默认情况下定义的,最后主控制器类调用一个触发子对象创建的方法。如果我使用 Sjoerd 的“扩展”方法,我将无法访问在途中创建的属性,而只能访问在类顶部定义的属性。
  • 所以你需要传递一个包含你正在构建的信息的对象?也许您应该重新考虑这种设计以减少耦合 - 依赖注入容器在这里会有所帮助吗?
【解决方案3】:

我很确定,PHP 没有这样的东西。

我认为,您将父对象传递给子对象的解决方案是最好的解决方案。您应该考虑仅在孩子的构造函数中设置您的 Parent 属性,以防止多个父母拥有同一个孩子。

【讨论】:

    【解决方案4】:

    没有办法调用

    $parent->test = "hello world!";
    $parent->child = new B();
    

    并自动在 B 中引用 $parent。


    一般来说,有四种方式来构建你的类:

    1.通过注入聚合父对象,例如

    class B
    {
         private $parent;
    
         public function __construct($parent) 
         {
             $this->parent = $parent;
         }
    
         public function setParent($parent) 
         {
             $this->parent = $parent;
         }
    
         public function accessParent() 
         {
            $this->parent->someMethodInParent();
         }
    }
    

    当对象在创建时必须有父对象时,使用构造函数注入。这是一个 has-a 关系,它创建了一个非常松散的耦合。 B 中没有硬编码的依赖项,因此您可以轻松地换出 Parent 实例,例如在 UnitTesting 时使用 Mock。使用依赖注入将使您的代码更易于维护。

    在您的 UseCase 中,您将在创建 B 时将 $parent 传递给 B:

    $parent->child = new B($parent);
    

    2。使用合成

    class B
    {
         private $parent;
    
         public function __construct() 
         {
             $this->parent = new Parent;
         }
    
         public function accessParent() 
         {
            $this->parent->someMethodInParent();
         }
    }
    

    这也是一个 has-a 关系,但是将 Parent 类耦合到 B。它也不是现有的 Parent 实例,而是一个新的实例。从措辞来看,我觉得有一个由孩子创建的父母有点奇怪。当依赖项是一个不被认为存在于根类之外的类,而是它所代表的整个事物的一部分时,请使用它。

    对于您的用例,没有办法做$parent-&gt;child = new B(); 并且在使用这种方法时知道什么是父级,除非 $parent 是一个单例。如果是这样,您可以获得 Singleton 实例,例如Parent::getInstance() 来实现你想要的,但请注意,单例模式并不是每个人都喜欢的模式,例如很难测试。

    3.使用继承

    class B extends Parent 
    {
        public function accessParent() 
        {
            $this->someMethodInParent();
        }
    }
    

    这样你就创建了一个 is-a 关系。父类(但不是特定实例)中的所有公共和受保护方法和属性都将在 B 中可用,您可以通过 B 实例的 $this 关键字访问它们。

    对于您的 UseCase,这种方法不起作用,因为您根本不需要 Parent 的实例,但是 B 在创建 Parent 时会封装它的所有内容

    $b = new B;
    

    4.使用全局关键字

    class B extends Parent 
    {
        private $parent;
    
        public function __construct() 
        {
            global $parent;
            $this->parent = $parent;
        }
    
        public function accessParent() 
        {
            $this->parent->someMethodInParent();
        }
    }
    

    global 关键字将全局变量导入当前作用域。通常,you should avoid using the global keyword 在 OO 上下文中,但使用上述其他三种方法之一,最好是第一种。虽然它是一种语言功能,但它并不受欢迎——尽管它是最接近第一个的东西,例如

    $parent->child = new B();
    

    无论如何,希望对您有所帮助。

    【讨论】:

    • 这太奇怪了
    • 感谢戈登让这篇文章保持最新状态。不错。
    【解决方案5】:

    也许它在某些情况下很有用:它不会在构造函数的早期将父对象带到 ChildClass 中,而是稍后一步。它具有拦截不存在方法的能力:

    class ParentClass
    {
        const CHILD_PROPERTY_NAME = 'child';
        public $data = 'Some data';
    
        public function
        __set($property_name, $property_value)
        {
            if ($property_name == self::CHILD_PROPERTY_NAME)
            {
                $property_value->set_parent_object($this);
            }
        }
    }
    
    
    class ChildClass
    {
        private $parent_object = null;
    
        public function
        set_parent_object($object)
        {
            $this->parent_object = $object;
            echo $this->parent_object->data;
        }
    
    }
    
    
    $p = new ParentClass();
    $p->child = new ChildClass();
    

    这将输出Some data

    【讨论】:

      【解决方案6】:

      您可以在创建子对象时创建对象子对象的集合。您通过父级创建它,这样它们不能相互引用,但是您可以通过父级和子级访问父级和子级...

      class ChildObject
      {
          public $name;
      }
      
      class ParentObject
      { 
          public $children = array(); 
      
          public function new_child($text = 'my name is data')
          {
              $child = new ChildObject;   // create a new child
              $child->name = $text;       // assign the name 
              $this->children[] = $child; // store it as part of this object
              return $child;              // return the new instance of Child
          }
      
          public function print_everything ()
          {
              foreach($this->children as $child) {
                  echo $child->name;
              }
          }
      }
      
      $parent = new ParentObject;
      $child1 = $parent->new_child();     // this is a ChildObject not a ParentObject
      $child2 = $parent->new_child('i am not data');
      
      echo $child1->name;                 // 'my name is data' 
      echo $child2->name;                 // 'i am not data'
      
      $child1->name = 'something else';
      echo $child1->name;                 // 'something else'
      
      $parent->print_everything();        // 'something else' and 'i am not data'
      

      因此,如果您想访问父方法或属性,则应将其放在父项中,而不是子项中。请记住,父类也是其自身类的“实例”。

      【讨论】:

        猜你喜欢
        • 2023-03-22
        • 2011-06-05
        • 2017-05-07
        • 2011-06-29
        • 1970-01-01
        • 1970-01-01
        • 2013-04-28
        • 2011-03-19
        • 1970-01-01
        相关资源
        最近更新 更多