Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Faking Late Static Binding before php 5.3

Tags:

oop

php

static

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.

like image 685
Tyson of the Northwest Avatar asked May 20 '09 22:05

Tyson of the Northwest


People also ask

What is PHP Late static binding?

Late static binding was a feature introduced with php 5.3. It allows us to inherit static methods from a parent class, and to reference the child class being called.

Which version of PHP introduced the concept called late static binding?

Late Static Binding. Late static binding is a feature that was introduced in version 5.3 of PHP.

What is static and dynamic binding in PHP?

In addition to this, any static function or variable is usually executed during runtime and not during compile time. Hence, if a value needs to be dynamically assigned to a variable that is static, it happens during runtime, and this is known as late static binding.


3 Answers

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

like image 118
Eugene Avatar answered Oct 17 '22 03:10

Eugene


Here's a quick example.

<?php

class ClassA{
   public function call(){
      return $this->inner();
   }

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

   static function init($class){
      return new $class();
   }   
}

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

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

?>

If you don't like passing in the class name you could add a static init function to the child class and explicitly pass it there as well. This would allow you to do something like: ClassA::init()->call() and ClassB::init()->call() but would have some minor code duplication.

like image 22
Derek Avatar answered Oct 17 '22 03:10

Derek


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.

like image 44
troelskn Avatar answered Oct 17 '22 04:10

troelskn