使用 PHP 5.2.X 扩展单例

发布于 2024-12-11 17:48:45 字数 1124 浏览 0 评论 0原文

我在 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 中提供。无论如何,我是否可以扩展单例而无需在扩展类中重新定义设计模式?

I have this code running on 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>";

Here's the output

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

When I ask for an instance of Chucknorris, I always get the Singleton one. I'd like to find out a way to extend the Singleton.

I know we can use get_called_class method to do it but it comes only with PHP 5.3. Is there anyway I can extend a Singleton without redefining the design pattern in the extended classes ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

苦妄 2024-12-18 17:48:45

PHP 的最佳选择5.3 是使用单例工厂:

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>";

这里唯一的缺点是你的单例构造函数是公共的..所以这是对该模式的基本违反。

更新:
这是一个删除公共构造函数的版本(警告:这会进入混乱/黑客/糟糕的设计领域)

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!

Your best bet in PHP < 5.3 is to use a Singleton Factory:

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>";

The only downside here is that your Singleton constructor is public.. so that's a basic violation of that pattern.

Update:
Here's a version that removes the public constructor (warning: this is getting into messy/hacky/poor design territory)

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!
小傻瓜 2024-12-18 17:48:45

如果 5.3 PHP 版本中不存在 get_class_function,为什么不模拟它呢?
这段代码可能会回答你的问题。

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>";

Why don't you simulate the get_class_function if it doesn't exist with 5.3 PHP version ?
This code may answer your question.

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>";
听风吹 2024-12-18 17:48:45

您可以在 Chucknorris 中重新定义 getinstance 方法(以及实例本身)来获取它的实例而不是父实例,但我不确定您的目的是什么目标是。只需将扩展类更改为:

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

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

这是您想要的吗?如果是这样——你想要它的原因是什么?我可以想到一些,但如果您分享您的目标,我会很高兴。

You can redefine just the getinstance method (and the instance itself) in Chucknorris to get an instance of it instead of the parent, but I'm not exactly sure what your end goal is. Just change the extending class to:

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

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

Is this what you want? And if so - what is the reason you want it? I could think of a few, but would be glad if you share you goal.

后eg是否自 2024-12-18 17:48:45

如果您将static private $instance = false;移动到子类并使其受保护而不是私有,您的代码很可能会起作用。
您还需要将 self:: 替换为 static::,以便在子类中设置静态变量。
这需要 PHP 5.3 - 但是,这应该不是问题,因为 PHP 5.2 自 2011 年 1 月起就已终止生命/支持(包括安全更新!)!

Your code will most likely work if you move static private $instance = false; to the subclass and make it protected instead of private.
You also need to replace self:: with static:: so the static var is set in the subclass.
This requires PHP 5.3 - however, this shouldn't be a problem because PHP 5.2 reached end-of-life/support (that includes security updates!) as of january 2011!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文