문제

I was working on an abstract class to save on some code for a couple of classes. These classes are all factories that instantiate themselves through different static calls. I could save some code by putting all those methods in an abstract class.

However, I ran into a late static binding problem... since our web host isn't using 5.3 or later, I don't have access to get_called_class. If I have

$class = __CLASS__;
return new $class();

in the abstract class, __CLASS__ is the name of the abstract class, when I actually want it to use the called class.

I've seen examples of abstract factories on the web where the child classes have their own instantiation methods, and don't rely on the abstract parent for it. However, in this situation, the only reason for the abstract class is to save code, so if I can't do it there, the value of it diminishes greatly.

Is there a workaround in php < 5.3? debug_backtrace()?


Edit:

I did a test and it seems debug_backtrace() will not work! I guess this is why we need late static binding.

<?

abstract class abstractFactory {
    public function create() {
            print_r(debug_backtrace());
            $class = __CLASS__;
            return new $class();
    }
}

class concreteFactory extends abstractFactory {}

$chimborazo = concreteFactory::create();

and the result:

$ php test.php
Array
(
    [0] => Array
        (
            [file] => /var/www/test.php
            [line] => 13
            [function] => create
            [class] => abstractFactory
            [type] => ::
            [args] => Array
                (
                )

        )

)

Fatal error: Cannot instantiate abstract class abstractFactory in /var/www/test.php on line 7
도움이 되었습니까?

해결책 3

Once way to do it is to override the various instantiation methods, and pass the name of the class directly:

<?

abstract class abstractFactory {

    public function create($class) {
        return new $class();
    }

    public function instantiate($class) {
        return new $class();
    }

}

class concreteFactory extends abstractFactory {

    public function create() {
        parent::create(__CLASS__);
    }

    public function instantiate() {
        parent::instantiate(__CLASS__);
    }
}


$chimborazo = concreteFactory::create();
$chimborazo = concreteFactory::instantiate();

다른 팁

The only workaround I've seen for this involves calling debug_backtrace to determine the class name of the caller(s). This is of course a giant hack. I've seen some code that combines a backtrace with actually opening up the calling file and parsing it to figure things out. Bizarre, horrible stuff.

The lack of LSB is going to come back and bite you later. Upgrade now, even if it means switching hosts. In fact, especially if it means switching hosts. 5.3 has been out for a year now.

Here's what I've been using until moving to 5.3:

if (!function_exists('get_called_class')) {

   /**
    * Implementation of get_called_class() for pre-5.3 PHP
    *
    * @return string
    */
   function get_called_class()
   {
      $bt = debug_backtrace();
      $lines = file($bt[1]['file']);
      preg_match('/([a-zA-Z0-9\_]+)::'.$bt[1]['function'].'/',
               $lines[$bt[1]['line']-1],
               $matches);
      return $matches[1];
   }
}

This lets you determine in a static function what class name the function has been invoked with. It's a workaround that has some performance issues but it's the only one I've found. If there are others I'd be interested to know.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top