Listing objects

Do you have a question? Post it now! No Registration Necessary.  Now with pictures!

Threaded View

Suppose we have a hierarchical class structure that looks something like  

   +-- Main
   +-- Object1
   |     |
   |     +-- Object11
   |     |
   |     +-- Object 12
   +-- Object2
   +-- Object3
   +-- Object4
         +-- Object41
         |     |
         |     +-- Object 411
         +-- Object 42

Now, the application looks like this:

$app = new Main(...);

Class Main() is instantiated only once, however it works with all other  
classes, which may be instantiated a number of times.

Now suppose there is a scenario:

Main creates Object11.
Object11 calls Object1::foo(), which creates Object2.
Object2 may then create Object1, in which case
   Object1 calls its foo(), which creates Object2.
   Object2 may then create Object1
      ..etc. until Object2 decides not to create Object1..

So, basically we'd get:


Now, when Object2 instantiates, it assigns a value to its variable, say,  
Object2::var, which should be unique. So, after assigning the value,  
Object2 has to check it against any other Object2::var.
However, Object2 is not necessarily instantiated under Object1, so,  
let's say we have

   $obj11 = Object11
     $obj2 = Object2
        $obj1 = Object1
          $obj2 = Object2
   $obj3 = Object3
     $obj2 = Object2
   $obj411 = Object411
     $obj42 = Object42
       $obj1 = Object1
         $obj2 = Object2

Assume $app->obj11->obj2->obj1->obj2::var should be checked against


I assumed the easiest way would be to have a global array of all objects  
descending from Object and update it in Object's constructor:

function Object() {
   global $objects;
   $objects[count($objects)] = &$this;

Then we could simply iterate through $objects, and if object's class is  
Object2, compare the var's.
However, this does not work, even through the object is passed by  
reference - if the object's variables are updated (by the object itself  
or by another object), the global array apparently has a copy of the  
initial object state:

$obj2 = new Object2();
   results in
$obj2 = Object2( var => 1 )
$objects[0] = Object2( var => 1 )

   results in
$obj2 = Object2( var => 2 )
$objects[0] = Object2( var => 1 )

So, I guess, some other mechanism should be used.

Any ideas?


Re: Listing objects

Following on from Lüpher Cypher's message. . .
Quoted text here. Click to load it
Sorry, I lost the plot half way through.

Your objects can be
1 -  nesting : object has a 'what are my children' and 'who is my  
parent' functionality.

2 - pointing : eg object has a 'these are my siblings' or  
'previous/next' functionality

3 - dictionary entries : object in some container is discoverable by  

Variations and combinations of course apply.  BUT every object exists in  
some context.  I /think/ you might be trying to get A's to point-to/own  
B's where more than one A could be the parent of a B.  Eg
"Sally is daughter of Jean"
"Geoffrey is son of Teddy"
"Sally is daughter of Teddy"  // Only one Sally! J+T are married.

In this case[1] create an array of children and point to elements in  
that array from your parent objects.

eg $child['Sally'] = new ChildObj(.....);
then $Jean->AddChild('Sally')   // just a key name or index
or $Jean->AddChild($child['Sally'])  // inside the routine do $myKids[]  
= & $NewChild
where $NewChild is the function argument.

[1] If in this example children can be parents then you should be  
looking at a single universal 'person' class with the necessary links.

PETER FOX Not the same since the adhesive company came unstuck
2 Tees Close, Witham, Essex.
Gravity beer in Essex  <

Re: Listing objects

Peter Fox wrote:
Quoted text here. Click to load it

It is more of a [1] and [3] :)
[1] for I do have a tree-like structure of objects. I have $parent (for  
all objects) and $owner (for objects that are of subclasses of some  
class) properties so, I can go bottom-up. I also do have children array  
for objects that have owner so, I can go top-down.
[3] for I am trying to have a global associative array that has unqiue  
object names as keys and object references as values.

Quoted text here. Click to load it

I do have a universal class :)

class Object
    var $name;
    var $owner;
    var $children[];


class A extends Object
class B extends Object

A's can be owned by A's and/or B's, B's can have many A's and/or B's
B's can be owned by A's and/or B's and can have many A's and/or B's as well.

One of the things I am trying to do is to have global references to all  

global $objects;
$objects = array();

function Object() {
    global $objects;
    ... assign name ...
    $objects[$this->name] = &$this;

However, if a property of some Object changes, $objects[$object_name]  
still has the "old" object. I assume $objects[$object_name] does not  
reference the object then, rather has a copy of it. So far I was unable  
to solve this.. By the way, this will work:

$obj = new Object();
$objects[$obj->name] = &$obj;

if it is executed outside any function and any class..


Re: Listing objects

Lüpher Cypher wrote:

Quoted text here. Click to load it

This is a textbook case of a badly designed set of classes. Their  
relationships are so complicated that even you the architect, are having  
problems explaining yourself. I think you'll need to go back to the  
drawing board on this one.

Extract the common features into a set of interfaces which should help  
clarify the class relationships and clean up the design. Also wherever  
possible, try to use (design) patterns, that way, your code will be  
reusable (not to mention easir to maintain). Incidentally, your Main  
class looks like a Singleton pattern, but only you the archiect, can  
know that for sure since your description given here is not very lucid.

hope that helps

Re: Listing objects

As Peter Fox has pointed out, put the tasks where they belong. I have  
the feeling that you are playing the role of a conductor who has to  
learn each musician how to play as well.

Use clear names for objects. If your model represents companies,  
departments, employees, tasks and subtasks, just call your classes those  
descriptive names.

If you have to compare different instances that might have the same  
state (value of internal variables), you could give the class an  
IsEqualTo method to do the comparison. Even better, a lazy collection  
can be used to ensure that equal objects are actually the same instance.  
You could then just use the reference equality operator (===).

Oh, and just delegate. Conductors trust their musicians in their skills.  
At least in a concert. In software, use unit tests as a "musician's exam".
For instance, if each object in your structure has some value and you  
want to calculate the total of it, don't traverse the structure  
yourself. Trust your directly known objects and ask them to calculate  
THEIR total and add these.

It is not always bad to repeat methods:
May be defined as

The short verion is clearer AND independent of the underlying structure,  
giving you more architectural flexibility.

If you fancy some technical stuff, google for the "Law of Demeter". It  
is about what objects should know each other and what objects should not.

Best regards

Re: Listing objects

Dikkie Dik wrote:
Quoted text here. Click to load it

I figured that much :)

Quoted text here. Click to load it

Hmm.. $a === $b will return true if $a == $b (i.e. their properties have  
the same values) and they are of the same class. That doesn't mean they  
are the same object, though..

Ok, let me try a clearer version :)

   +--- App
   |      ::$page
   +--- Control
   |      ::$parent
   |      ::$data
   |      ::$object
   +--- Data
   |      ::$id
   +--- Template
          |  ::owner
          |  ::control
          +--- Page

In the main script I have

$app = new App();

In constructors I have

function App() {
    $null = null;
    $this->page = new Page($null);

function Page(&$owner) {

function Template(&$owner) {
    $this->owner = &$owner;
    $this->control = new Control(&$this);

function Control(&$parent) {
    $this->parent = &$parent;
    $this->data = new Data();
    if (already_exists($this->data->id)) {
       echo "Duplicate ID";
    if ($some_condition) {
       $object = new $CustomSubclassOfTemplate($this->parent);

function Data() {
    $this->id = $some_retrieved_id;

Basically, the interesting part is:

When Template is instantiated (initially Page in App constructor), it  
instantiates Control, which, in turn, instantiates Data. At this point,  
$data->id will be set.
At the end of Control's constructor, if some condition is satisfied, a  
subclass of Template will be instantiated and stored in Control's $object.
Thus, we can have:
We can also pretty much go bottom-up through Template objects via $owner  
and we can get the Template object from Control via $parent.

Now, in the middle of Control's constructor there is a check that  
$data-id does not already exist.

One way would be to go through Templates:

$temp = $this->parent;
while (isset($temp)) {
   if ($this->data->id == $temp->control->data->id) {
      echo "error";

Apparently this does not work, even though owner is passed by reference.

Another way would be to have a global array and save all objects there  
by reference. This is actually more appealing to me, since then I could  
access any object at any time from anywhere. Say, if I have an array of  
objects under Template and each of them has an associative array  
key=>value, then to "compile" an associative array from all those  
arrays, I'd simply iterate through the global array, check object's  
class, and take in the key/value pairs in the resulting array, rather  
than traverse a tree of Templates and those objects. Anyways, what I  
tried is something like this:

global $objects;
$objects = array();

class Object() {
    global $objects;
    $objects[count($objects)] = &$this;

However, if a property of an object is changed, the object in $objects  
stays the same.. But then, it must be a copy?


Re: Listing objects

Quoted text here. Click to load it

Sorry, I'm probably confusing with other languages.

Quoted text here. Click to load it

This is the inheritance hiearchy, I assume that you also have an  
association hierachy. App will be the root, and then...
I would think that an App creates a page and creates a data channel, or  
asks a Control to do that. Within my perception, a page has a template  
and date (gets it from App). So App knows Control and Page, and also  
knows that Control has Data. All these objects do not have to know App  
as far as I can see.

Quoted text here. Click to load it

If the problem is here, let's keep it here. I have written my own  
DatabaseID class with its own IsEqualTo method (and an IsNew method).  
For the very simple reason: A data-object might be constructed with  
database data (known ID) or be a new record that was not yet stored in  
the database. With this DatabaseID class, I can give EVERY data-object  
an ID. If the DatabaseID instance is not contructed with a database ID,  
the IsEqualTo method will always return FALSE. Two new records are per  
definition different in my application. Only if both compared objects  
were constructed with an ID from the database, an actual by-value  
comparison if done.

Quoted text here. Click to load it

What is template doing in Control? If Control is responsible for both  
templates and data, it is a clear signal that this class wants to be  
split into two classes.

Quoted text here. Click to load it

Is that bad? Frankly I don't care how deep a structure goes, as long as  
it makes sense and is finite.

Quoted text here. Click to load it

One of the main features of object-oriented programming is that you can  
nicely shield off what others should not access. The contents of a page  
should only be accessible by asking the $page object, which is only  
accessible by asking $app. Why? Because it allows $page to decide how  
and when to fill in the data, and to throw an exception if no data was  
passed. That is $page's reponsibility, not $app's, and not even yours.  
If you want to peek inside of $page's internals, write a temporary  
method or echo statement, during development only.
Not even your responsibility? No. You can program it, write a unit test  
for it, and when it is finished, it can live on its own. It is sad, but  
the only thing left for you to do is typing the URL...

Quoted text here. Click to load it

Re: Listing objects

Dikkie Dik wrote:
Quoted text here. Click to load it

Well, App only creates and knows Page (Template).
Template creates Controller, which creates Data. So, Template knows  
Control, and Control knows Data. However, depending on the Data, Control  
may instantiate another Template (at which point the process repeats).  
The original Template has access to Control's Template.
Right now it's like this:

$app = new App(
    $page = new Page(
       $ctl = new Control(
          $data = new Data()
          if (<another template>) {
             $temp = new TemplateSubclass(
                 $ctl = new Control(
       if ($ctl->temp exists) {
          $out = $ctl->temp->render(
             if ($ctl->temp exists) {
                $out = $ctl->temp->render(
             return $out.<custom output>;
       return $out.<custom output>;
    echo <results>;

Some of these do call App's methods, though, for instance to get a  
global application parameter..

Quoted text here. Click to load it

Well, all I need is just checking whether an ID exists. In this case,  
Data loads an XML file and sets its ID value to a string. This ID should  
be unique. So, after Controller instantiates Data, it should check that  
the loaded ID wasn't already assigned in some other Controller. I figure  
the easiest way is to iterate an array of objects, see if an object has  
Control as its class, and compare the IDs in Datas. :)

Quoted text here. Click to load it

Well, Template is presentation class so, it's all about *how* the data  
should be displayed and has no other functionality. It knows its Control  
so that it can present dynamic data. Control relies on Data to choose  
*what* should be displayed.
Suppose Data consists of 3 classes. Control chooses one of them and  
instantiates it. Template simply outputs whatever it is, inserting the  
output of the class Control chose along way. This way Data is only about  
data, Control is about what should be output, and Template is only about  
how it should be output, no matter what the actual content is. I figure  
instantiating the chosen class in Template would mean that Template is  
also about data, and instantiating it in Data would mean that data is  
dynamic.. :)

Quoted text here. Click to load it

Well, it's actually not all that bad, since there is no need to write  
such long references :) It is finite, otherwise the page will never load :)

Quoted text here. Click to load it

Found where the mistake is :) Apparently $a = new A() means that $a is a  
copy of the actually instantiated class A() ;-o All I had to do was to  
change all instantiations to form $a = &new A();

Quoted text here. Click to load it

Well, echo's are what I usually use to debug things :)
In this case, however, I could either traverse a tree, meaning that I  
would start in a leaf, and would have to traverse all nodes and leaves,  
bottom-up, check if a node/leaf is of appropriate class, and then check  
whether ID is the same or not.
With array, I can simply use foreach:

foreach($objects as $name=>$obj) {
   if (!is_a($obj,"Control")) { continue; }
   if ($name == $this->getName()) { continue; }
   if ($this->getId() == $obj->getId()) { echo "error"; return; }

Where each object has a unique name :) That's what I actually use, now  
that the references work in the global array.
It is pretty much a shortcut to doing some things :)


Re: Listing objects

Oh, forgot to update $temp here:

$temp = $this->parent;
while (isset($temp)) {
   if ($this->data->id == $temp->control->data->id) {
      echo "error";
   $temp = $temp->owner;

Also, it does not work because $temp->control->data is null. However, if  
$this->data is accessed from $temp->control, it is instantiated..


Site Timeline