views:

50

answers:

3

Hey all,

I'm making a templating system where I instantiate each tag using a foreach loop. The issue is that some of the tags rely on each other so, I'm wondering how to get around that ordering from the looping.

Here's an example:

Class A {
  public $width;
  __construct() {
     $this->width = $B->width; // Undefined! Or atleast not set yet..
  }

}

Class B {
  public $width;
  __construct() {
     $this->width = "500px";
  }
  __tostring() {
      return "Hello World!";
  }
}

Template.php

$tags = array("A", "B");
foreach ($tags as $tag) {
   $TagObj[$tag] = new $tag();
}

echo $TagObj['A']->width; // Nadamundo!

EDIT: Ok just to clarify.. My main problem is that Class A relies on Class B, but class A is instantiated before class B, so therefore width has not yet been defined in class B. I am looking for a good way to make sure all the classes are loaded for everyone allowing the interdependencies to exist. For the future, please don't consider any syntax errors.. I just made up this example on the spot. Also assume that I have access to class B from class A after class B gets instantiated.

I know this has applications elsewhere and I'm sure this has been solved before, if someone could enlighten me or point me in the right direction that'd be great!

Thanks! Matt Mueler

A: 

You are missing width() method in B class that you are calling in A class $this->width = $B->width(); (and you should include or sort of use inheritance to use B class in A class)

Class B {
  private $width;
  __construct() {
     $this->width = "500px";
  }
  __tostring() {
      return "Hello World!";
  }

  function width() {
   return $this->width;
  }
}

As for ordering, you should be more specific.

Sarfraz
Thanks for your response. Please read my edit for clarification. The syntax error was my fault but besides the point.
Matt
+1  A: 

The easiest way will probably be by making a second pass over the array of tag objects once they've all been instantiated, and calling some standard method (see template method pattern e.g. http://java.dzone.com/articles/design-patterns-template-method ) on each e.g.

$tags = array("A", "B");
foreach ($tags as $tag) {
   $TagObj[$tag] = new $tag();
}

foreach (array_keys($TagObj) as $tagName) {
   $TagObj[$tagName]->resolveDependencies($TagObj);
}

How resolveDependencies is implemented will vary from class to class.

HarryF
+1  A: 

Where does this $B instance in A::construct() come from? It's not there in scope.

Possible solitions:
1) Static values:

class B {
    static $width = '500px';
...

class A {
    function construct(){
        $this->width = B::$width;
     }

2) Static functions:

class B {
    static function width(){
         return '500px';
...

class A {
    function construct(){
        $this->width = B::width();
     }

3) Just in time factorymethod (or object if you need one), if you need objects

function getTag($name){
    global $TagObj;
    if(!isset($TagObj[$name]) && class_exists($name)){
         $TagObj[$name] = new $name();
    }
    return $TagObj[$name];
}

class A {
    function construct(){
        $this->width = getTag('B')->width();
     }
....
$tags = array("A", "B");
foreach ($tags as $tag) {
   $TagObj[$tag] = getTag($tag);
}

And if you want a change in B to reflect in A you could always use references instead of assignments. All this of course expects the class definition to be available, define an __autoload() if not, or include them all beforehand.

Wrikken