tags:

views:

754

answers:

4

I need an inherited static function "call" to call another static function "inner" that has been overridden. I could do this with late static binding, but my host does not have php5.3 yet and so I need to work around it.

class ClassA{
    static function call()
    {
     return self::inner();
    }

    static function inner(){
     return "Class A";
    } 
}

class ClassB extends ClassA{
    static function inner(){
     return "Class B";
    }
}

echo "<p>Class A = " . ClassA::call();
echo "<p>Class B = " . ClassB::call();

I would like the output to be:
Class A = Class A
Class B = Class B

But what it is:
Class A = Class A
Class B = Class A

My gut tells me that I should be able to write something in call() to detect what object was referenced when "call()" was, well, called. So instead of self::inner() it would so something along the lines of calledclass::inner(). Detecting the proper version of inner() to call from the original method call.

+1  A: 

Unfortunately there is no nice way to do it (otherwise PHPers wouldn't cheer so much for that feature).

You have to pass class name. PHP < 5.3 also doesn't have nice syntax for static calls with dynamic class name which makes whole thing even uglier:

static function call($class)
{
    return call_user_func(array($class,"inner"));
}
…
ClassA::call("ClassA");
ClassB::call("ClassB");

If you can change the code (and not use static), then singletons make it more bearable. You can make helper function to ease the syntax:

X("ClassA")->call();
X("ClassB")->call();

The X function should look up, create and return instance of a class.

porneL
So basically avoid this issue entirely by structuring the code so it is either, unnecessary to do this, or wait until 5.3? suck.
tvanover
+1  A: 

You can use object instances rather than classes. If you want a global symbol, you can use a global variable. Since they are rather unwieldy in PHP, one trick is to wrap it in a function. Eg.:

class ClassA {
  function call() {
    return $this->inner();
  }
  function inner() {
    return "Class A";
  }   
}
function ClassA() {
  static $instance;
  return $instance ? $instance : new ClassA();
}

class ClassB extends ClassA {
  function inner() {
    return "Class B";
  }
}
function ClassB() {
  static $instance;
  return $instance ? $instance : new ClassB();
}

echo "<p>Class A = " . ClassA()->call();
echo "<p>Class B = " . ClassB()->call();

But a better idea might be to avoid global symbols altogether; The reason why it works well in Ruby/Rails, is that Ruby doesn't really have static state in the same way that PHP has. A class can be rebound and added to at runtime, which allows for easy extension of the framework. In PHP, classes are always final, so referring to them in application code, is a very strong degree of coupling.

troelskn
You could also use singletons, wrap the instance code in static function getInstance() and have function classB() { return classB::getInstance(); }
jcinacio
+1  A: 

If performance is not an issue, you can use debug_backtrace() to find the called class:

$bt = debug_backtrace();
return get_class($bt[1]['object']);

http://php.net/manual/en/function.debug-backtrace.php

Eugene