tags:

views:

237

answers:

4

Say you have two classes, A and B. Is it possible to instantiate both classes once and then let class B call methods in class A, and vice versa?

It can be done using double colon (::) ... ... but then the method becomes static - is that a disadvantage? (see example below)

Can it be done in other ways? With interfaces?

This code shows what I try to do:

class A {
  function horse() {
    echo "horse";
  }
}

class B {
  function jump() {
    // $A = new A; ... don't want to add this in each method.
    $A->horse();  // Fails - $A is out of scope ($A = new A;).
    // A::horse();  // Old code style - works.
    // $this->horse();  // Works if you extend A - not self-documenting.
    // $this->A->horse();  // Fails - out of scope.
  }
}

$A = new A;
$B = new B; // Better to use "$B = new B($A);" ?
$B->jump(); // fails - the horse is sleeping.

Edit

Well, I am building a MVC-framework and I want to re-use code from other classes. Some real-world examples:

  • a database object that is being passed across classes.
  • a "url" class that creates/manipulates url's - used by other classes.
  • ... and a code example:

    class url { function anchor($url,$name) { return "{$name}"; } }

    class someclass { function text($str,$url) { return "{$str}. " . $url->anchor($url,"Read more..."); } }

A: 

I think that this should work:

$B = new B();
$B->jump();

But you should read/refer to http://www.php.net/manual/en/language.oop5.php

Of course you should import the class if you're accessing it from a different php file. And if you're in the object you're calling the method of you should use

$this->jump();
Daryl
I want the code to be self-documenting - so instead of $this, I want to use the foreign class name. For example, $HtmlTable->generate() is self-explanatory while $this->generate() is not.
Kristoffer Bohmann
A: 

I would suggest reading about the factory and strategy pattern. You can read more about this from chapter one of this fantastic book. link text

I would recomend you reading the whole book.

Benjamin Ortuzar
Thanks - looks useful. I also came across: "The Singleton Design Pattern for PHP" - http://www.tonymarston.net/php-mysql/singleton.html
Kristoffer Bohmann
Design Patterns by Head First, is a fantastic book that will show you all this patterns in an easy to understand, fun and practical way. I would suggest it to anyone trying to improve their OO principles and learn some usefull design patterns.
Benjamin Ortuzar
+1  A: 

I think what you are asking for is multiple inheritance where you could extend both A and B like this

<?php
class C extends A,B {

//...

}

This however is not possible in PHP for good reasons(it actually is creating more problems than it's trying to solve).

Now you might ask yourself if there is any alternative to multiple inheritance and the answer is: Yes, there is! Have a look at the strategy pattern(as Benjamin Ortuzar also has pointed out).

UPDATE:

I just read your question a second time and figured that you might be looking for the singleton pattern, which lets you instantiate an instance of an class only once like this:

class A
{

    protected static $_instance;

    protected function __construct() //prohibit creating instances from outside
    { }

    public static function getInstance() 
    {
      if( self::$_instance === NULL ) {
        self::$_instance = new self();
      }
      return self::$_instance;
    }
}

$instance = A::getInstance();

Now A::getInstance() always returns the same instance of A which you can use in B and you can have both the advantages of dynamic functions and the accessibility of static functions.

UPDATE2:

Your database belongs into a registry if you can have more than one db-connection. If you're absolutely certain that you will always need only one db-connection you could as well make it a singleton.

For the URL helper I'd suggest writing a static class if you can and if you really need it to be dynamic make it a singleton, as mentioned before.

André Hoffmann
A: 

Maybe (just guessing) you're looking for something like aggregation in COM:

Aggregation is the object reuse mechanism in which the outer object exposes interfaces from the inner object as if they were implemented on the outer object itself.

You can build something like that with the "magic method" __call. Each time a method is called that isn't callable in the object's context this method is invoked and your code can decide what to do with this call. E.g. it can test if another object that is stored as a property of the "outer" object exposes a method with that name and than call that inner object's method.

class Foo {
  protected $inner = null;
  public function __construct($inner=null) {
    if ( is_null($inner) && !is_object($inner) ) {
      throw new Exception('...');
    }
    $this->inner = $inner;
  }

  public function __call($name, $arguments) {
    // also check http://uk.php.net/is_callable
    if ( !is_null($this->inner) && method_exists($this->inner, $name) ) {
      return call_user_func_array( array($this->inner, $name), $arguments);
    }
    else {
      // add some error handler here
      throw new Exception('...');
    }
  }

  function jump() {
    $this->horse();
    echo " jumps";
  }
}

class Bar {
  function horse() {
    echo "horse";
  }
}

$foo = new Foo(new Bar);
$foo->jump();

This works. But I'd recommend something like that only for quite specific circumstances. The most obvious reason beeing that it's hard to tell from the outside what this object $foo really can and cannot do.

VolkerK