Getting an attribute from the perent object

I have a set of nested objects/classes. Essentially each object is a registry of its child classes, plus some unique attribute


Class A{
  public A_Attribute1= 'some value';
  public A_Attribute2= 'some value';
  public GenAttribute= 'attribute general';
  protected content=array(); // all classB instances
}
Class B extends class A{
  public B_Attribute1= 'some value';
  public B_Attribute2= 'some value';
  public GenAttribute= 'different attribute general';
  protected content=array(); // all classC instances
}

Class C extends class B{
  public C_Attribute1= 'some value';
  public C_Attribute2= 'some value';
  public GenAttribute= 'Still different attribute general';
  protected content=array(); // all classD instances
}

Class D extends class C {
  public D_Attribute1= 'some value';
  public D_Attribute2= 'some value';
  public GenAttribute= 'uniqu attribute general';
  protected content=array(); // some data
}

Is there direct way to get attributes from the parent instance?

$a=new a();
and $a->content has 10 instances of class B, each of which have 5 or so instances of class C…

from inside of one of the Class C objects, can you retrieve “B_Attribute2” of the parent object(instance) of the class B object that holds it?

If they’re public, they can be accessed from anywhere.

Can you explain exactly where you need it?

Well what I meant was that i would like to be able to have a function to GET the value in the PARENT. :confused:

so AS IF you could use function with $this->:: parent to get the value of the propierty ‘B_Attribute2’ of the INSTANCE of the object that holds it…

Note I know that the :: parent can get a static property of a class parent, but what I am thinking of is more of a regular property within INSTANCE that contains an INSTANCE of a child class. I hope that makes my question clearer.

http://www.php.net/manual/en/keyword.parent.php

FYI, your class/object design is pretty bad.

I fear my question is not being understood due to the fact that I dont know if what I am asking is even possible in OOP. Thats what I get for being lazy.

Yes, you can access a class function or STATIC variable with :: parent. This I know. What I am trying to do is access a property of an INSTANCE that contain other instances from within one of the instances it contains. Think inception.

This is a NON WORKING example of what I have been toying with



class Root{
		public	 	$registry	=	array();
		protected	$births		=	'Level1';
		protected	$myName		=	'Root';
		function addEl($name){
			$this->registry[$name]				=	new $this->births();
			$this->registry[$name]->myName		=	$name;
		}
		function 	myNameIs(){
			echo 'I am ',self::getName(),'.<br>';
		}
		function getName(){
			return $this->myName;
		}
		protected function 	getRegistry(){
			return self::$registry;
		}
}
class Level1 extends Root{
		protected	$births		=	'Level2';
		function 	hoosYaDaddy(){
			$dad	=  	parent:: getName(); // this doesnt actually return waht I want as it just access getName() int the parent and uses  the curren object properties  as variables.
			echo 'a child of ',$dad,'.<br>';
		}
		function parentAccess(){
			$ret	=	parent::getRegistry();
			return     $ret ;
		}

}
class Level2 extends Level1{
		protected			$births		=	'Level3';

}
class Level3 extends Level2{
		function addEl($name){
			$this->regsitry[$name]	=	'data';
		}

}
$b='Root';
$a= new $b();
$a->addEl('first');
$a->addEl('second');
$a->addEl('third');
$a->registry['second']->addEl('primary');
$a->registry['second']->addEl('secondary');
$a->registry['second']->addEl('tertiary');
$a->registry['second']->addEl('Quator');
$a->myNameIs();
$a->registry['second']->myNameIs();
$a->registry['second']->hoosYaDaddy();


The Idea is that hoosYaDaddy() would access ‘myName’ in the parent object , NOT in itself.

You could store the parent during creation:

    $this-&gt;registry[$name]-&gt;daddy        =   $this-&gt;myName;

    function     hoosYaDaddy(){
        $dad    =     $this-&gt;daddy; 
        echo 'a child of ',$dad,'.&lt;br&gt;';
    }

$a->registry[‘second’]->registry[‘secondary’]->myNameIs();
$a->registry[‘second’]->registry[‘secondary’]->hoosYaDaddy();

Those tests seem to return correctly.

This kind of stuff hurts my head and just feels like you’re trying to create something pointlessly complicated.

You could store the parent during creation

Thats the way I have handled in the past…

$a->registry[‘second’]->registry[‘secondary’]->myNameIs();

It’s exactly this chaining I am trying to avoid. The goal would be able to reach the parent from a function inside the child ( which also would mean I could potentially climb up all the way to the root element by recursively accessing this function)

Keep in mind my example is essentially abstract ( not to be confused with abstract classes) … I am just trying to represent navigation through containers.

parent:: is not STATIC!!!

But you see, the problem is, your class/objects are poorly designed.
It will not work like you expect it to work.

“What I am trying to do is access a property of an INSTANCE that contain other instances from within one of the instances it contains.” This is the incarnation of bad programming. An Instance contained within another instance should have no awareness of it being contained within an instance. It becomes a nightmare to maintaine, code for, debug…all sorts of problems. Not to mention you get crazy amount of recursive looping.

Here is a basic example of how I might do it…without full understanding of what you are doing.


<?php

class Tree
{
  protected $name, $index = array();
  
  public function __construct ( $name ) {
    $this->name = $name;
  }
  
  public function register ( $obj ) {
    $this->index[] = $obj;
    return $this;
  }
  
  public function __toString ()
  {
    $out = 'Tree: ' . $this->name . "\
";
    foreach ( $index as $child ) {
      $out .= '  ' . $child->__toString() . "\
";
    }
    
    return $out;
  }
}

class Leaf
{
  protected $name;

  public function __construct ( $name ) {
    $this->name = $name;
  }
  
  public function __toString () { return 'Leaf: ' . $this->name; }
}

$r = new Tree( 'SubRoot' );
$r->register( new Leaf( 'SubChild1' ) )
  ->register( new Leaf( 'SubChild2' ) )
  ->register( new Leaf( 'SubChild3' ) );

$t = new Tree( 'Root' );
$t->register( new Leaf( 'Child1' ) )
  ->register( $r )
  ->register( new Leaf( 'Child2' ) )
  ->register( new Leaf( 'Child3' ) );
  

$t->__toString();

After looking it over a bit, I am assuming of course, that you are wanting this concerning html:


<ul>
  <li><a href="">Link1</a></li>
  <li><a href="">Link2</a>
    <ul>
      <li><a href="">Link1</a></li>
      <li><a href="">Link2</a></li>
      <li><a href="">Link3</a></li>
      <li><a href="">Link4</a></li>
      <li><a href="">Link5</a></li>
    </ul>
  </li>
  </li>
  <li><a href="">Link3</a></li>
  <li><a href="">Link4</a>
    <ul>
      <li><a href="">Link1</a></li>
      <li><a href="">Link2</a></li>
      <li><a href="">Link3</a></li>
      <li><a href="">Link4</a></li>
      <li><a href="">Link5</a></li>
    </ul>
  </li>
  </li>
  <li><a href="">Link5</a></li>
</ul>

Untested of course but this code should be able to output the above:
Navigation holds Link(s), Link holds Navigation.


class Navigation
{
  protected $links = array();
  
  public function addLink ( Link $link ) {
    $this->links[] = $link;
  }
  
  public function __toString()
  {
    $out = '<ul>';
    
    foreach ( $links as $link ) {
      $out .= '<li>' . $link->__toString() . '</li>';
    }
    
    return "$out</ul>";
  }
}

class Link
{
  protected $name, $nav;
  
  public function __construct ( $name ) {
    $this->name = $name;
  }
  
  public function addSubNav ( Navigation $nav ) {
    $this->nav = $nav;
  }
  
  public function __toString ()
  {
    $out = '<a href="#">' . $this->name . '</a>';
    if ( isset( $this->nav ) )
      $out .= $this->nav->__toString();
    
    return $out;
  }
}

Logic I really do appreciate all your input.

But you see, the problem is, your class/objects are poorly designed.
It will not work like you expect it to work.

Am really experimenting with something so yeah its going to seem like horrendous code. ( am not dealing with HTML output exact, but nested information storage… think of it as Russian dolls… DOLL (Level X) belongs to DOLL (level X-1), not any other and can have any number of DOLL(Level X+1)s… but not any other type. This would be simple (in an awkward way enough if I merely wanted to know the LEVEL of the object for knowing the levels sake). For that I could assign a variable to to the class of parentLevel+1. But what I want is the child objects to have acess to the information (attributes) of the parent OBJECT ( even if they have been changed)

when I use parent:: it doesnt let me get OBJECT values, just CLASS static constants.
If I try t access a method , via parent::foo(), any $this->whatever within the foo is interpreted as the $this->whatever in the child not the parent 's.

  • The goal of my experiment is to STORE each node rather than output it.
  • The ‘TREE’ can have TRUNKS, BRANCHES, AND LEAVES… so its not just a simple parent-child; tho each lower level should be able to know where it is "stored’
  • Dymanic /recursive-able… that means hard coding $a->branchFoo()->branchFoo()->branchFoo()->branchFoo()
  • With that being said , the mechanism is internal; it’s the object itself that ‘knows’ at which level its at and not the user/programmer .

Maybe attempting to create things via NESTING is what you mean by poor construction… I just thought it would be more intuitive if i could do it that way

I am trying to run your example. .but it says : Invalid argument supplied for foreach() in - on line 19 I will toy around with it tho

The child should not know where it is stored.

The child should not know where it is stored.

I suppose that’s all that I was looking for. I have learned or developed patterns for most things. I t seems pretty simple and normal to start from the the outermost and go inwards but the reverse is what i was trying to accomplish, if it was possible. In other words, sure I can get the parent to return a child object… but not the child object to return a parent.

I suppose I was crazy for trying… had to give it a shot :slight_smile:

What you need is another layer. You have the tree, with its parents and child relations. Within the tree no one really knows where they are in the tree. To manage the tree you have a second layer, this layer knows where everything is, who is the parent of this object, etc. Good example would be a file system, directories and files have no concept of their location, or where they are in the hierarchy of the file system. What manages that is, well at least in NTFS, you have the Master File Table whichs keeps track of relationships. The files and dictionaries themselves have no concept of those relationships.

Thats a good idea. I suppose you mean that this layer would be on the same level or independent from the tree? I guess I am unclear as to how this would be structured how would that be structured in PHP and could child elements access this second layer.

I didn’t quite follow everyone’s thought process throughout this thread, so please forgive me if I repeat something that’s already been communicated.

The code in the first post seems to be confusing sublcassing with object composition. You shouldn’t be creating a subclass to represent a depth in the tree. All you really need is one class with references to child nodes and a parent node.


class TreeNode
{
    private $childNodes = array();
    private $parentNode;

    // a name for this node; for demo purposes
    private $name;

    public function __construct($name)
    {
        $this->name = $name;
    }

    public function addChild($childNode)
    {
        $this->childNodes[] = $childNode;
        $childNode->parentNode = $this;
    }

    public function getParent()
    {
        return $this->parentNode;
    }

    public function __toString()
    {
        return $this->name;
    }
}

$root = new TreeNode('root');

// depth 1
$leafA1 = new TreeNode('A1');
$root->addChild($leafA1);

$leafA2 = new TreeNode('A2');
$root->addChild($leafA2);

// depth 2
$leafB1 = new TreeNode('B1');
$leafA1->addChild($leafB1);

// echo lineage
echo $leafB1; // B1
echo $leafB1->getParent(); // A1
echo $leafB1->getParent()->getParent(); // root

Jeff, I don’t think that’s what LogicEarth had in mind with his multi layer suggestion.

However…

public function addChild($childNode)
{
    $this-&gt;childNodes[] = $childNode;
    $childNode-&gt;parentNode = $this;
}

I was thinking of the same thing :). But I never bothered to pursue that avenue as I am afraid that containing the parent within the child would have serious recursive issues? maybe even memory leaks?

A=>B=>A=>B=>A=>…

I know that PHP is intelligent enough to avoid an ‘infinite loop’ in this case. Still, it seems risky?

Memory leaks shouldn’t be an issue. The garbage collector can identify and reclaim circular references.

As for recursive issues… true, as written, the code doesn’t stop the programmer from doing silly things, such as making two nodes each other’s parent. If we were going to use this code, we’d have to develop it a little further to add checks that protect the programmer from himself.