Родительский объект в php - PullRequest
12 голосов
/ 11 марта 2010

Есть ли способ пройти объект, чтобы получить данные родительского объекта? Под «родительским объектом» я имею в виду не родительский класс, а буквально объект. Вот пример, в мире javascripty :-):

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

$parent->child = new B();

Было бы здорово, если бы я мог получить доступ ко всем данным из parent в дочернем объекте:

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

Пока мое решение - передать родительский объект дочернему объекту (в качестве ссылки) или сделать родительский объект глобальным. Есть ли у вас лучшее решение?

Спасибо!

Ответы [ 6 ]

22 голосов
/ 11 марта 2010

Нет способа вызвать

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

и автоматически имеет ссылку на $ parent в B.


Как правило, существует четыре способа структурирования ваших классов:

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, например, с помощью Mock при UnitTesting. Использование Dependency Injection сделает ваш код более понятным.

В вашем UseCase вы передаете $parent B при создании 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, а новый экземпляр. Из формулировки я нахожу несколько странным иметь родителя, созданного ребенком. Используйте это, когда зависимость - это класс, который не считается существующим вне корневого класса, но является частью всего, что он представляет.

Для вашего UseCase нет способа сделать $parent->child = new B(); и знать, кто является родителем при использовании этого подхода, если только $ parent не является Singleton. Если это так, вы можете получить экземпляр Singleton, например, Parent::getInstance() для достижения того, чего вы хотите, но учтите, что синглтоны - не любимая модель, например, трудно проверить.

3. Использовать наследование

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

Таким образом, вы создаете отношения is-a . Все открытые и защищенные методы и свойства из класса Parent (но не для конкретного экземпляра) будут доступны в B, и вы можете получить к ним доступ через ключевое слово $this экземпляра B.

Для вашего 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 импортирует глобальные переменные в текущую область. В целом, вам следует избегать использования глобального ключевого слова в контексте ОО, но используйте один из трех вышеупомянутых методов, предпочтительно первый. Несмотря на то, что это языковая функция, она не одобряется - хотя это следующая вещь, ближайшая к первой, например,

$parent->child = new B();

В любом случае, надеюсь, это поможет.

3 голосов
/ 11 марта 2010

Передача родителя ребенку - лучшее решение.Хотя это несколько нежелательные симбиотические отношения.

Должен ли B () знать об объекте, атрибутом которого он является?Более чем вероятно, нет.Они только слабо связаны посредством композиции.

Почему B () должен быть атрибутом своего родителя?Вам нужно иметь эту реализацию в B () или она должна быть частью родительского?

2 голосов
/ 02 октября 2011

Может быть, это может быть полезно в некоторых случаях: он не переносит родительский объект в 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

1 голос
/ 11 марта 2010

Я почти уверен, что в PHP нет чего-то подобного.

Я думаю, что ваше решение передать родительский объект ребенку - лучшее решение. Вам следует установить свойство Parent только в конструкторе дочернего элемента, чтобы у нескольких родителей не было одного и того же дочернего элемента.

0 голосов
/ 08 апреля 2019

вы можете создать массив массивов дочерних объектов, когда вы создаете дочерние элементы, которые вы создаете через родителя, таким образом, они не могут ссылаться друг на друга, но вы можете получить доступ как к родителям, так и к дочерним элементам через родителя и через дочерние элементы ...

class B {
public data;

}
class A { 
public children= array(); 

public function new_child($text='my name is data') {
$child=new B;
$this->children[]=$child;
$this->data=$text;
return $child;
}

public function print_everything () {
foreach($this->children as $child) echo $child->data;
}
}

$parent = new A;
$child = $p->new_child()
$child2 = $p->new_child('im no data')

echo $child->data  // should print 'my name is data' 
echo $child2->data // should print 'im no data'
$child->data = 'somthingelse'
echo $child->data // should print 'somthingelse'

$p->print_everything(); // should print : 'somthingelse' & 'im no data'

поэтому, если вы хотите получить доступ к родительской функции или данным, вы должны поместить эту функцию в родительский объект, а не в дочерний. помните, что родитель также является «экземпляром» своего собственного класса.

0 голосов
/ 11 марта 2010

номер

Вы можете получить доступ к переменным из суперкласса, используя $ 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();
?>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...