(PHP) 单例数据库类 - 静态方法怎么办?

3

这是一个基础网站。根据这里的答案,我正在做以下操作:

private $db;

public function __construct($id = null) {
    $this->db = Db::getInstance(); //singleton from the Db class

但是如果有一个静态方法,我就不能使用特定于对象的变量。

有没有比在静态方法内手动指定db变量更好的方法?

public static function someFunction($theID){
    $db = Db::getInstance();

编辑:将变量设置为静态并不能解决问题。访问未声明的静态属性。我仍然需要在静态函数内分配变量。问题是询问是否有一种方法可以避免这种情况。

我的DB类(虽然和本讨论无关):

class Db {
private static $m_pInstance;
private function __construct() { ... }

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

}


1
你为什么不能在 someFunction 中直接使用 $this->db?你在构造函数中设置它的原因是什么? - DaOgre
@Igor K:不是这样的;-)你已经按照单例模式的常规方式实现了它。工厂(抽象工厂和工厂方法)甚至都没有接近这里。 - zerkms
@Digital Precision:只要你试图反驳定义,就会有点难以推翻它。正如我上面提到的-请阅读维基百科文章。 - zerkms
@IgorK:你能同时发布你的类定义吗? - Mike Purcell
@IgorK:我指的是构造函数和someFunction()的类定义,只是想确保它们在同一个类中。 - Mike Purcell
显示剩余13条评论
2个回答

5

是的,你可以将$db设置为静态:

static private $db;

我假设这就是你需要的,因为你正在从静态方法中访问它。如果有任何原因你不想这样做,那可能意味着该方法不应该是静态的。
编辑:
根据@zerkms(感谢)评论,您可以使用self::访问静态变量:
self::$db = Db::getInstance(); 

1
但这会引发严格标准违规通知。不好。 - zerkms
1
@zerkms:“从单例检索的静态实例”听起来很肮脏:))。现在我感觉自己处于面向对象编程的黑暗面。 - Luchian Grigore
1
问题:$db变量在构造函数中赋值,但静态方法被调用时不会调用构造函数。那么我该怎么处理呢?“访问未声明的静态属性” - Marcus
@Luchian Grigore:php不允许这样做。嘿嘿,你看 - 这就是为什么它不好 :-) - zerkms
@Luchian Grigore:这意味着将此代码放置在所有静态函数内部,因此与在静态方法中定义本地 $db 变量相比,并没有更好的效果,除非我错过了什么? - Marcus
显示剩余13条评论

3

当将可以被实例化的类中的静态方法与静态成员变量混合使用时,您会遇到一些问题。在实例化时通过设置成员变量并期望可以通过调用静态方法访问它们是行不通的。唯一真正的解决方法是为数据库单例设置一个特定于类的单例,或将DB对象传递给静态方法。

// Option 1
class MyClass
{
    private static $db;

    public function __construct($id = null)
    {
        self::$db = Db::getInstance(); //singleton from the Db class
    }

    public static function someFunction($theID)
    {
        self::$db->query('SELECT * FROM my_table');    
    }
}

// Singleton DB for MyClass will be initalized via constructor
$myClass = new MyClass();    

// This call will have access to DB object set via class specific singleton
MyClass::someFunction(4);

// Option 2
class MyClass
{
    private $db;

    public function __construct($id = null)
    {
        $this->$db = Db::getInstance(); //singleton from the Db class

        if (!is_null($id)) {
            $this->id = $id;
        }
    }

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

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

    // Sub-Option 1: If Id ISNT set via object
    public static function someFunction($object, $theID)
    {
        $object->getDb()->query('SELECT * FROM my_table WHERE id = ' . (int) $theID);    
    }

    // Sub-Option 2: If Id IS set via object
    public static function someFunction($object)
    {
        $object->getDb()->query('SELECT * FROM my_table WHERE id = ' . (int) $object->getId());    
    }
}

// Sub-Option 1 call
$myClass = new MyClass();

MyClass::someFunction($myClass, 4);

// Sub-Option 2 call
$myClass = new MyClass(4);

MyClass::someFunction($myclass);

由于大多数情况下您都是从已实例化的类中调用静态方法,将DB对象传递给静态方法是一个很好的方法,可以避免处理将DB单例类声明为静态时可能出现的问题。在我的情况下,这个答案完美地解决了问题,没有造成混乱。 - Mike

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接