есть ли способ пересечь объект, чтобы получить данные родительского объекта? С «родительским объектом» я не имею в виду родительский класс, но буквально объект. Вот пример, в мире 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" } }
На данный момент мое решение – передать родительский объект дочернему элементу (в качестве ссылки) или сделать родительский глобальным. У вас есть лучшее решение?
Благодаря!
Невозможно вызвать
$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(); } }
,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 нет закодированных зависимостей, поэтому вы можете легко заменить экземпляр родителя, например, с помощью 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(); } }
,class B { private $parent; public function __construct() { $this->parent = new Parent; } public function accessParent() { $this->parent->someMethodInParent(); } }
Это также отношение has-a , но сопрягает класс Parent с B. Это также не существующий родительский экземпляр, а новый экземпляр. Из формулировки я считаю несколько странным иметь родителя, созданного ребенком. Используйте это, когда зависимость – это класс, который не считается существующим вне корневого класса, но является частью всего, что он представляет.
Для вашего UseCase нет способа сделать $parent->child = new B();
и знать, что такое родитель при использовании этого подхода, если только $ parent не является Singleton. Если это так, вы можете получить экземпляр Singleton, например Parent::getInstance()
чтобы достичь того, чего вы хотите, но обратите внимание, что Singletons не являются любимым шаблоном каждого пользователя, например, трудно тестировать.
3. Использовать наследование
class B extends Parent { public function accessParent() { $this->someMethodInParent(); } }
Таким образом вы создаете отношения is-a . Все общедоступные и защищенные методы и свойства класса Parent (но не определенного экземпляра) будут доступны в B, и вы можете получить к ним доступ через ключевое слово $this
экземпляра экземпляра B.
Для вашего UseCase этот подход не работает, так как вам не обязательно иметь экземпляр родителя вообще, но B будет инкапсулировать все из родителя, когда он будет создан
$b = new B;
4. Используйте глобальное ключевое слово
class B extends Parent { private $parent; public function __construct() { global $parent; $this->parent = $parent; } public function accessParent() { $this->parent->someMethodInParent(); } }
,class B extends Parent { private $parent; public function __construct() { global $parent; $this->parent = $parent; } public function accessParent() { $this->parent->someMethodInParent(); } }
global
ключевое слово импортирует глобальные переменные в текущую область. В общем, вам следует избегать использования ключевого слова global в контексте OO, но используйте один из трех других методов выше, предпочтительно первый. Хотя это языковая функция, она нахмурилась – хотя это будет следующая ближайшая вещь к первой, например
$parent->child = new B();
В любом случае, надеюсь, что это поможет.
Передача родителя ребенку – лучшее решение. Хотя это несколько нежелательные симбиотические отношения.
Должен ли B () иметь какое-либо знание объекта, это атрибут? Скорее всего, нет. Они связаны только по композиции.
Почему B () должен быть атрибутом его родителя? Вам нужно иметь эту реализацию в B () или она должна быть частью родителя?
Возможно, это может быть полезно в некоторых случаях: он не доводит родительский объект до 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
Нет.
Вы можете получить доступ к переменным из суперкласса, используя $ 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(); ?>
Я уверен, что PHP не имеет ничего подобного.
Думаю, ваше решение о передаче родительского объекта ребенку – лучшее решение. Вы должны подумать о том, чтобы установить родительское свойство только в конструкторе дочернего элемента, чтобы у нескольких родителей не было одного и того же ребенка.