Расширение Singleton с помощью PHP 5.2.X - PullRequest
2 голосов
/ 26 октября 2011

У меня этот код работает на PHP 5.2.6

class Singleton {
    static private $instance = false;
    private $id = false;
    protected function __construct() {
        $this->id = uniqid();
    }

    static public function instance() {
        if (!self :: $instance) {
            self :: $instance = new self();
        }
        return self :: $instance;
    }
    public function get_id() {
        return $this->id;
    }
}

class Chucknorris extends Singleton {

}

echo "php version = ".phpversion()."<br>";

$singleton = Singleton::instance();
echo get_class($singleton)."<br>";
echo "singleton id = ".$singleton->get_id()."<br>";

$chucknorris = Chucknorris::instance();
echo get_class($chucknorris)."<br>";
echo "chucknorris id = ".$chucknorris->get_id()."<br>";

Вот вывод

php version = 5.2.6
Singleton
singleton id = 4ea7dca7d8f23
Singleton
chucknorris id = 4ea7dca7d8f23

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

Я знаю, что мы можем использовать метод get_called_class, но он поставляется только с PHP 5.3.Можно ли как-то расширить Singleton, не переопределяя шаблон проектирования в расширенных классах?

Ответы [ 4 ]

3 голосов
/ 26 октября 2011

Лучше всего в PHP <5.3 использовать фабрику синглтона: </p>

class Singleton
{
    private $id = false;

    public function __construct() {
        $this->id = uniqid();
    }

    public function get_id() {
        return $this->id;
    }
}

class SingletonFactory
{
    private static $instance_array = array();

    public static function getInstance($class_name)
    {
        if (!isset(self::$instance_array[$class_name]))
        {
            self::$instance_array[$class_name] = new $class_name();
        }
        return self::$instance_array[$class_name];
    }
}

class Chucknorris extends Singleton {}


$singleton = SingletonFactory::getInstance('Singleton');
echo get_class($singleton)."<br>";
echo "singleton id = ".$singleton->get_id()."<br>";

$chucknorris = SingletonFactory::getInstance('Chucknorris');
echo get_class($chucknorris)."<br>";
echo "chucknorris id = ".$chucknorris->get_id()."<br>";

Единственным недостатком здесь является то, что ваш конструктор Singleton является общедоступным ... так что это основное нарушение этого шаблона.

Обновление: Вот версия, которая удаляет общедоступный конструктор (предупреждение: это становится грязной / хакерской / плохой территорией дизайна)

class Singleton
{
    private $id = false;

    public function __construct() {
        $back = debug_backtrace(false);
        if (!isset($back[1]['class']) || $back[1]['class'] != 'SingletonFactory')
        {
            throw new Exception('Consturctor not available, use SingletonFactory::getInstance("CLASSNAME")');
        }

        $this->id = uniqid();
    }

    public function get_id() {
        return $this->id;
    }
}

class SingletonFactory
{
    private static $instance_array = array();

    public static function getInstance($class_name)
    {
        if (!isset(self::$instance_array[$class_name]))
        {
            self::$instance_array[$class_name] = new $class_name($class_name);
        }
        return self::$instance_array[$class_name];
    }
}

class Chucknorris extends Singleton {}


$singleton = SingletonFactory::getInstance('Singleton');
echo get_class($singleton)."<br>";
echo "singleton id = ".$singleton->get_id()."<br>";

$chucknorris = SingletonFactory::getInstance('Chucknorris');
echo get_class($chucknorris)."<br>";
echo "chucknorris id = ".$chucknorris->get_id()."<br>";

$badchuck = new Chucknorris(); // Exception!
2 голосов
/ 26 октября 2011

Почему бы вам не смоделировать функцию get_class_function, если она не существует в версии 5.3 PHP? Этот код может ответить на ваш вопрос.

if (!function_exists('get_called_class')) {
    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];
    }
}

abstract class Singleton {
    private $id = false;

    protected function __construct() {
        $this->id = uniqid();
    }

    static public function instance() {
        static $instances = array();
        $called_class_name = get_called_class();
        if (!isset($instances[$called_class_name])) {
            $instances[$called_class_name] = new $called_class_name();
        }
        return $instances[$called_class_name];
    }

    public function get_id() {
        return $this->id;
    }
}

class Chucknorris extends Singleton {}
class Brucelee extends Singleton {}

echo "php version = ".phpversion()."<br>";

$chucknorris = Chucknorris::instance();
echo get_class($chucknorris)."<br>";
echo "chucknorris id = ".$chucknorris->get_id()."<br>";

$brucelee = Brucelee::instance();
echo get_class($brucelee)."<br>";
echo "brucelee id = ".$brucelee->get_id()."<br>";
1 голос
/ 26 октября 2011

Вы можете переопределить только метод getinstance (и сам экземпляр) в Chucknorris, чтобы получить его экземпляр вместо родителя, но я не совсем уверен, какова ваша конечная цель.Просто измените класс расширения на:

class Chucknorris extends Singleton {
    static private $instance = false;

    static public function instance()
    {
        if (!self :: $instance) {
            self :: $instance = new self();
        }
        return self :: $instance;
    }
}

Это то, что вы хотите?И если так - то по какой причине вы этого хотите?Я мог бы подумать о нескольких, но был бы рад, если бы вы поделились своей целью.

0 голосов
/ 26 октября 2011

Ваш код, скорее всего, будет работать, если вы переместите static private $instance = false; в подкласс и сделаете его protected вместо private.Вам также необходимо заменить self:: на static::, чтобы в подклассе была установлена ​​статическая переменная.Это требует PHP 5.3 - однако, это не должно быть проблемой, потому что PHP 5.2 достиг конца срока службы / поддержки (включая обновления безопасности!) С января 2011 года!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...