【问题标题】:PHP: Utilizing singleton pattern correctly?PHP:正确使用单例模式?
【发布时间】:2011-02-10 18:11:12
【问题描述】:

我正在尝试学习 PHP OOP,并研究了如何制作一个全局数据库类以在我的项目中使用。从我所见,最合适的可用模式是单例,它可以确保始终只存在一个数据库连接。然而,由于这是我第一次使用单例模式,我不确定我是否做对了。

这是一个合适的单身人士吗?此代码是否仅确保一个数据库连接?有什么办法可以测试吗? (学会一个人钓鱼,他的余生都会有食物......)

我使用 redbean 作为我的 ORM,我是这样设置的:

require_once PLUGINPATH.'rb.php';
$redbean= R::setup("mysql:host=192.168.1.1;dbname=myDatabase",'username','password');

我根据this source 制作了以下脚本,作为我自己的单例数据库类;

class database {
    private $connection = null;

    private function __construct(){
        require_once PLUGINPATH.'rb.php';
        $this->connection = R::setup("mysql:host=192.168.1.1;dbname=myDatabase",'username','password');
    }

    public static function get() {
        static $db = null;

        if ( $db === null )
        $db = new database();

        return $db;
    }

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

谢谢!

【问题讨论】:

  • 学会一个人搜索等等;)Creating the Singleton design pattern in PHP5的可能重复
  • 嗨 - 我认为自己是一个体面的 Google 员工,但由于我在 Singletons 上找不到任何东西,在这种情况下如何共享 redbean 提供的Static 连接,我不是确定要做什么,并期待一些帮助:)
  • 只是一个花絮:对于单身人士/工厂来说,new self() 是一个有趣的简写,它使以后更容易更改类名,应该需要它。这是一个几乎可以忽略不计的好处,但我发现至少值得了解这个选项。
  • @pinkgothic:Beware when using the self keyword and inheritance。您可能会大吃一惊。
  • @netcoder:我个人认为这并不奇怪。如果您的示例返回了 SuperSingleton,那会让我感到惊讶! :) 它的工作方式就是它应该如何工作。 (当然,这是一种观点,事实上 PHP 引入了后期静态绑定作为 PHP 处理静态方面的替代方法,这很好地表明了其他人不同意我的观点。)

标签: php oop design-patterns singleton


【解决方案1】:

实例变量需要是类的静态成员。我还没有测试过这段代码,但它应该可以工作。连接也应该是静态的。使用此代码,您将拥有一个数据库类实例和一个连接实例。可以在没有静态连接的情况下执行此操作,但将其设为静态将确保只有一个连接实例。我还将类的字面名称更改为 php 魔术常量。这使您的代码更易于维护。如果您以后更改类的名称,则不必在代码中查找旧类名称的所有文字实例。现在这似乎有点矫枉过正,但相信我,当您从事越来越复杂的项目时,您会欣赏它的价值。

class database {
    private static $connection = null;
    private static $db;

    private function __construct(){
        require_once PLUGINPATH.'rb.php';
        self::$connection = R::setup("mysql:host=192.168.1.1;dbname=myDatabase",'username','password');
    }

    public static function get() {
        if ( !(self::$db instanceof __CLASS__) ) {
            $klass = __CLASS__; // have to set this to a var, cant use the constant with "new"
            self::$db = new $klass();
        }

        return self::$db;
        }

    public function connection() {
        return self::$connection;
    }
}

【讨论】:

  • +1 表示 $klass / __CLASS__ 东西。此外,您的答案比我的更接近 OPs 问题。
  • @Linus Kleen,谢谢。过去我不得不做一些可怕的查找和替换会话。
  • 您需要使用 self::$connection 来获取静态 $connection 变量。我已经更改了代码。您需要使用 self:: 来访问所有静态变量。如您所见,使用 $this-> 会出错。
  • @Industrial 实际上,我认为这很好。当我这么说的时候,我有点误会了。我以为连接是你创建的一个对象,我没看清楚代码。
  • @industrial,连接方法将使用 -> 调用,因为该方法不是静态的。作为 php 中的一条规则,如果您正在访问静态变量或方法,则无论您是在类内部还是外部,都需要使用范围解析运算符 (::)。如果要访问非静态类成员或函数,请使用箭头运算符 (->)。希望对您有所帮助,如果没有,请告诉我,我可以进一步澄清。
【解决方案2】:

你是单身几乎是正确的。

私有成员(没有双关语)$connection 也需要是静态的。您也可以选择以下方法:

class database {
    private static $instance = NULL;
    protected $conn;

    private function __construct() {
        $this->conn = mysql_connect( ... );
    }

    public static function init() {
        if (NULL !== self::$instance) 
            throw new SingletonException();
        self::$instance = new database();
    }

    public static function get_handle() {
        if (NULL === self::$instance)
            ; // error handling here
        return self::$instance->conn;
    }
}

【讨论】:

  • 这是对的一半。 $connection 应该是静态的,但是 connection() 不需要是静态的,因为它打算在单例实例的范围内使用,在类的范围内。即,他打算致电:database::get()->connection()
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-09-26
  • 1970-01-01
  • 2012-06-14
  • 1970-01-01
  • 2022-07-26
  • 1970-01-01
  • 2018-02-05
相关资源
最近更新 更多