在PHP中将数据库连接/对象转换为函数的最佳方法是什么?

时间:2008-10-23 04:53:48

标签: php database

有两个选项:

$connection = {my db connection/object};

function PassedIn($connection) { ... }

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

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

所以,传入,通过引用传递,或使用全局。我正在考虑只在1个项目中使用的函数,它只有1个数据库连接。如果有多个连接,则通过引用明确传入或传递。

当你在PHP5中使用一个对象时,我不需要通过引用传递,因此传入或使用global是两种可能性。

我问的原因是因为我厌倦了总是在我的函数参数中添加$ connection。

6 个答案:

答案 0 :(得分:4)

我使用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);
        }
    }
}

然后在functions / objects /中:

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

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

答案 1 :(得分:2)

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

class MyClass {
  protected $_db;

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

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

答案 2 :(得分:2)

我看到很多人都提出了某种静态变量。

基本上,全局变量和静态变量之间的差别很小。除语法外,它们具有完全相同的特征。因此,通过用静态变量替换全局变量,你什么也得不到。在大多数示例中,存在一定程度的解耦,因为静态变量不是直接引用的,而是通过静态方法(例如,单例或静态注册表)。虽然略好一些,但仍存在全球范围的问题。如果您需要在应用程序中使用多个数据库连接,那就搞砸了。如果您想知道代码的哪些部分有副作用,则需要手动检查实现。这不会影响您的应用程序,但会使维护更难。

我建议你选择以下之一:

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

  • 将实例放在对象的范围内,该对象具有需要它的方法。例如。如果方法Foo->doStuff()需要数据库连接,请在Foo的构造函数中传递它,并将其设置为Foo上的受保护实例变量。你仍然可以最终得到传递方法的一些问题,但对于笨重的构造函数来说,它通常不是一个问题,而不是方法。如果您的应用程序变得足够大,您可以使用依赖注入容器来自动执行此操作。

答案 3 :(得分:1)

我的建议是避免大部分代码全局化 - 这很危险,难以跟踪并会咬你。

我这样做的方法是使用一个名为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),我更喜欢将它们作为静态方法保存在我的系统中类。

让每个类通过构造函数需要连接是最好的方法,最好的方法是最可靠和最孤立。

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

答案 4 :(得分:0)

以上都不是。

所有mysql函数都可以选择数据库连接参数 。如果你保留该参数,则假设是mysql_connect()的最后一个连接。

答案 5 :(得分:-1)

function usingFunc() {
  $connection = getConnection();
  ...
}

function getConnection() {
  static $connectionObject = null;
  if ($connectionObject == null) {
    $connectionObject = connectFoo("whatever","connection","method","you","choose");
  }
  return $connectionObject;
}

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