返回实例变量V/s返回直接对象


Returning instance variable V/s returning direct object

我正在寻找2009年建立的网站的源代码,这是一个自定义框架。

有什么区别?

<?php
class DbAccess {
    private static $instance;
    /**
     * Returns the instance of the DB Class
     */
    public static function getInstance()
    {
        self::$instance = new DbAccess();
        return self::$instance;
    }
}

V/s

<?php
class DbAccess {

    /**
     * Returns the instance of the DB Class
     */
    public static function getInstance()
    {
        return new DbAccess();
    }
}

我曾在几个定制框架和不同模式的库集上工作过,但是,有时,我看到返回实例的方法是通过self::$instance,有时,它直接通过new返回

哪一个是好的实践?

在讨论OOP时,这两种方法都不是很好的实践。正如其他人已经指出的那样,第一种方法看起来像是有人试图实现单例模式并失败了。单例在面向对象方面有什么不好呢?它引入了紧密耦合、隐藏依赖和全局状态。基本上,它只是使用global关键字的一种奇特方式。

现在是第二个例子。它基本上是相同的东西,只是有完全相同的缺点。

注意,这两个示例在每次调用该方法时都会创建一个新的数据库连接。这是……不是最优的。

现在我要做的是像下面这样的事情(使用依赖注入):

假设你有一个需要访问数据库的类,你可以这样做:

class Foo
{
    private $db;
    public function __construct($db)
    {
        $this->db = $db;
    }
    public function methodWhichNeedsDatabaseAccess()
    {
        // do something with $this->db
    }
}
// or whatever instance for database access you are using
$db = new PDO(dsn);
$foo = new Foo($db);
$foo->methodWhichNeedsDatabaseAccess();

静态函数都返回对象的新实例。第一个示例允许您在将来再次静态引用该实例,尽管它存储在私有静态中,因此只能从该类中的成员(函数)访问它。

第一个示例看起来像一个单例示例,但是,它没有被包装在典型的if exists包装器中。当您只希望创建类的一个实例时,使用单例是一种很好的做法:

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

这样做的方式是,你只能通过一个实例访问这个类(这样你就不会打开多个连接到同一个数据库)。

如果要控制构造函数,则可以遵循第二种模式。可以将构造函数设为私有(这样就只有那个类可以调用构造函数并创建新对象)。这在工厂里很常见。