【问题标题】:What is the best method for getting a database connection/object into a function in PHP?将数据库连接/对象放入 PHP 中的函数的最佳方法是什么?
【发布时间】:2008-10-23 04:53:48
【问题描述】:

几个选项是:

$connection = {my db connection/object};

function PassedIn($connection) { ... }

function PassedByReference(&$connection) { ... }

function UsingGlobal() {
    global $connection;
    ...
}

所以,传入,通过引用传递,或者使用全局。我正在考虑仅在只有 1 个数据库连接的 1 个项目中使用的功能。如果有多个连接,肯定是传入或引用传递。

我认为当您在 PHP5 中使用对象时不需要通过引用传递,因此传入或使用全局是两种可能性。

我问的原因是因为我厌倦了总是将 $connection 放入我的函数参数中。

【问题讨论】:

标签: php database


【解决方案1】:

我使用 Singleton ResourceManager 类来处理整个应用程序中的数据库连接和配置设置等内容:

class ResourceManager {
    private static $DB;
    private static $Config;

    public static function get($resource, $options = false) {
        if (property_exists('ResourceManager', $resource)) {
            if (empty(self::$$resource)) {
                self::_init_resource($resource, $options);
            }
            if (!empty(self::$$resource)) {
                return self::$$resource;
            }
        }
        return null;
    }

    private static function _init_resource($resource, $options = null) {
        if ($resource == 'DB') {
            $dsn = 'mysql:host=localhost';
            $username = 'my_username';
            $password = 'p4ssw0rd';
            try {
                self::$DB = new PDO($dsn, $username, $password);
            } catch (PDOException $e) {
                echo 'Connection failed: ' . $e->getMessage();
            }
        } elseif (class_exists($resource) && property_exists('ResourceManager', $resource)) {
            self::$$resource = new $resource($options);
        }
    }
}

然后在函数/对象/任何地方:

function doDBThingy() {
    $db = ResourceManager::get('DB');
    if ($db) {
        $stmt = $db->prepare('SELECT * FROM `table`');
        etc...
    }
}

我用它来存储消息、错误消息和警告,以及全局变量。有一个有趣的问题here 是关于何时实际使用这种类型的类。

【讨论】:

  • 很好,我喜欢这个主意。现在我得看看如何实现它。
  • 我不久前开始使用它,它为我开辟了很多可能性。它比每个函数的混乱全局变量和数据库参数要好得多。它还保持全局命名空间中没有变量。
  • 这和全局变量一样是全局的。静态不是避免全局状态的解决方案,构造函数注入是。
【解决方案2】:

尝试以面向对象的方式设计您的代码。使用数据库的方法应该分组在一个类中,并且类实例应该包含数据库连接作为类变量。这样,数据库连接可供需要它的函数使用,但它不是全局的。

class MyClass {
  protected $_db;

  public function __construct($db)
  {
    $this->_db = $db;
  }

  public function doSomething()
  {
    $this->_db->query(...);
  }
}

【讨论】:

  • 这里的主要问题是必须将 $db 对象传递给经常实例化的类是非常烦人的。如果有静态函数也需要 $db 对象怎么办?您是否也必须将 $db 传递给那些?它确实有效,但似乎没有必要。
  • 不,没有必要,构造函数注入是开发可测试、解耦代码的唯一干净方法。
【解决方案3】:

我看到很多人建议使用某种静态变量。

本质上,全局变量和静态变量之间几乎没有区别。除了语法之外,它们具有完全相同的特征。因此,通过将全局变量替换为静态变量,您将一无所获。在大多数示例中,存在一定程度的解耦,因为不是直接引用静态变量,而是通过静态方法(例如,单例或静态注册表)。虽然稍微好一点,但这仍然存在全局范围的问题。如果您需要在应用程序中使用多个数据库连接,那您就完蛋了。如果您想知道代码的哪些部分有副作用,则需要手动检查实现。这不会影响您的应用程序的成败,但会使其更难维护。

我建议您选择以下之一:

  • 将实例作为参数传递给需要它的函数。这是迄今为止最简单的,它具有范围狭窄的所有优点,但它可能会变得相当笨拙。它也是引入依赖项的来源,因为您的代码的某些部分最终可能会成为中间人。如果发生这种情况,请继续..

  • 把实例放到对象的范围内,里面有需要的方法。例如。如果方法Foo->doStuff() 需要数据库连接,则将其传入Foo 的构造函数并将其设置为Foo 上的受保护实例变量。您仍然可能会遇到一些传递方法的问题,但是对于笨拙的构造函数而言,与方法相比,这通常不是问题。如果您的应用程序变得足够大,您可以使用依赖注入容器来自动执行此操作。

【讨论】:

    【解决方案4】:

    我的建议是避免在大部分代码中使用全局代码 - 这很危险、难以跟踪并且会咬你。

    我这样做的方法是有一个名为 getDB() 的函数,它可以通过构造函数注入在类级别或在公共类中静态。

    所以代码变成了

    class SomeClass {
        protected $dbc;
    
        public function __construct($db) {
            $this->dbc = $db;
        }
    
        public function getDB() {
            return $this->dbc;
        }
    
        function read_something() {
            $db = getDB();
            $db->query();
        }
    }
    

    或使用公共共享类。

    function read_something() {
        $db = System::getDB();
        $db->query();
    }
    

    无论你做了多么优雅的系统设计,总有一些项目在范围内是必然的(例如 DB、Session、Config),我更喜欢将这些作为静态方法保留在我的系统中 类。

    让每个类都需要通过构造函数进行连接是最好的方法,我的意思是最可靠和隔离的。

    但是请注意,使用公共共享类来执行此操作可能会影响完全隔离使用它的对象的能力以及对这些对象执行单元测试的能力。

    【讨论】:

    • 您对 void global 的建议很好,但您的解决方案都是全局状态的一种形式。
    • 谢谢 - 回顾这个答案,我意识到我并不清楚我提出的是构造函数注入还是单例,并且我没有正确解释每种方法的优缺点。答案现已编辑。
    【解决方案5】:

    以上都不是。

    所有mysql 函数都采用数据库连接参数可选。如果您不考虑该参数,则假定 mysql_connect() 的最后一个连接。

    【讨论】:

    • 如果你有一个自定义的数据库连接对象或者你正在使用 PDO 会发生什么:php.net/manual/en/pdo.query.php
    • 苛刻 - 海报没有说他是。在进一步澄清之前,这不值得反对。
    【解决方案6】:
    function usingFunc() {
      $connection = getConnection();
      ...
    }
    
    function getConnection() {
      static $connectionObject = null;
      if ($connectionObject == null) {
        $connectionObject = connectFoo("whatever","connection","method","you","choose");
      }
      return $connectionObject;
    }
    

    这样,静态 $connectionObject 在 getConnection 调用之间被保留。

    【讨论】:

    • 尽管名声不好,我还是决定把它留在这里——作为一个不这样做的例子。 匆忙重构
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-15
    • 2011-03-20
    • 2011-02-19
    • 1970-01-01
    • 2010-12-12
    • 1970-01-01
    • 2010-09-24
    相关资源
    最近更新 更多