Абстрактные фабрики невозможны в php <5.3? - PullRequest
0 голосов
/ 13 августа 2010

Я работал над абстрактным классом, чтобы сэкономить на некотором коде для пары классов. Эти классы являются фабриками, которые создают себя с помощью различных статических вызовов. Я мог бы сохранить некоторый код, поместив все эти методы в абстрактный класс.

Однако я столкнулся с проблемой поздней статической привязки ... поскольку наш веб-хост не использует 5.3 или более позднюю версию, у меня нет доступа к get_called_class. Если у меня есть

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

в абстрактном классе, __CLASS__ - это имя абстрактного класса, когда я действительно хочу, чтобы он использовал вызываемый класс.

Я видел примеры абстрактных фабрик в сети, где у дочерних классов есть свои собственные методы создания экземпляров, и они не полагаются на это для абстрактного родителя. Однако в этой ситуации единственной причиной для абстрактного класса является сохранение кода, поэтому, если я не могу сделать это там, значение этого значительно уменьшается.

Есть ли обходной путь в php <5.3? <code>debug_backtrace()


Edit:

Я сделал тест, и кажется, debug_backtrace() не будет работать! Наверное, поэтому нам нужно позднее статическое связывание .

<?

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

class concreteFactory extends abstractFactory {}

$chimborazo = concreteFactory::create();

и результат:

$ 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 ]

1 голос
/ 13 августа 2010

Вот что я использовал до перехода к 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];
   }
}

Это позволяет вам определить в статической функции, с каким именем класса вызывается функция.Это обходной путь, который имеет некоторые проблемы с производительностью, но это единственный, который я нашел.Если есть другие, мне было бы интересно узнать.

1 голос
/ 13 августа 2010

Единственный обходной путь, который я видел для этого, включает в себя вызов debug_backtrace для определения имени класса вызывающего абонента.Это, конечно, гигантский хак.Я видел некоторый код, который комбинирует обратную трассировку с , фактически открывающим вызывающий файл и анализирующим его , чтобы разобраться.Странные, ужасные вещи.

Отсутствие LSB вернется и укусит вас позже.Обновите сейчас, даже если это означает переключение хостов.На самом деле, особенно если это означает переключение хостов.5.3 уже год не работает.

0 голосов
/ 13 августа 2010

Один из способов сделать это - переопределить различные методы создания экземпляров и напрямую передать имя класса:

<?

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();
...