将 $db 对象传递给其他类,以便它们可以访问数据库
Posted
技术标签:
【中文标题】将 $db 对象传递给其他类,以便它们可以访问数据库【英文标题】:Passing $db object to other classes so they can access the database 【发布时间】:2011-07-09 16:31:19 【问题描述】:我有一个 php 数据库类,它连接到 mysql 并包装了所有 PDO 代码,我用它来查询数据库。基本上在页面控制器中我创建了一个新对象:
$db = new Database($dbConfig);
然后我可以使用准备好的查询从数据库中获取数据:
$params = array('username' => $username);
$result = $db->preparedSelect('select password, salt from users where username = :username', $params);
它将 PDO 语句结果复制到一个新的 assoc 数组中,并仅将数据库结果返回到调用页面。我用一个简单的 foreach 遍历它们,如下所示:
foreach ($result as $key => $val)
$password = $val['password'];
$salt = $val['salt'];
好吧,假设我希望另一个类使用我的 $db 对象,以便它可以通过某些方法访问数据库。目前其他类看起来像这样:
class General
// Database object
private $db;
public function __construct($db)
$this->db = $db;
效果很好,但我只是想知道构造函数是否应该如下所示:
public function __construct(&$db)
$this->db = $db;
这应该意味着我通过引用传递它而不是将对象复制到另一个类中。我不想要类中的 $db 对象的副本,我希望它使用现有的数据库对象,这样我就不会有它的多个副本漂浮在内存中。
在 PHP5 中将其作为 $db 或 &$db 传递有什么区别?通过阅读,PHP5 默认通过引用传递对象,而其他人说它现在以 Java 方式进行,有些人说使用 & 会产生硬链接。我糊涂了。最好的方法是什么?
非常感谢!
【问题讨论】:
【参考方案1】:有区别,但并不是你想象的那样。
在 PHP5 中,保存对象的“$db”基本上等同于 C 或 C++ 中的“Foo *”。换句话说,$db 不存储整个对象,它只存储一个小标记,让代码在必要时找到对象。当您按值传递此标记时,它与传递整数值而不是整个对象的副本一样快。但是,如果您分配 $db,它不会更改调用者中的值,因为您正在更改保存令牌的本地变量以包含不同的令牌。
如果函数采用“&$db”,那基本上相当于在 C 中传递“Foo **”,或者更准确地说,函数采用 C++ 中的“Foo *&”。调用速度一样快,因为它传递的大小相同,但在函数内部,如果你分配给 $db 它将改变调用者中 $db 的值,因为“通过引用传递”变量将你指向内存在调用者中持有令牌的位置。
最好的方法是按值传递(不要使用“&”),除非你知道自己在做什么以及为什么这样做。
【讨论】:
所以基本上如果我执行 _construct($db) 然后更改 $db 对象中的值,例如$db->testvar = 1 我将在内存中有两个 $db 对象,原始的和新的,其中 testvar 包含一个“1”。那正确吗?如果我执行 _construct(&$db) 然后分配 $db->testvar = 1,我应该会影响原始对象并且在内存中只有一个 $db 对象实例。对吗? 不,在这两种情况下,您都会拥有一个具有更改值的对象,因为在这两种情况下都不会复制对象本身。在第一个函数中,如果您执行$db = null
,调用者仍将拥有原来的 $db,而在第二个函数中,调用者将不再拥有原来的 $db。【参考方案2】:
这是个好问题。
您始终可以通过打开 $db 句柄、将其传递给函数并通过 === 运算符检查它们以确保它们是同一个对象来进行测试。
【讨论】:
我做了一个测试,它们似乎是完全相同的对象。我认为您必须使用 clone $db 来实际制作原始 $db 对象的副本。否则,您从另一个类中对 $db 对象所做的任何更改都会更新原始对象。【参考方案3】:这对于静态方法来说是件好事。这就是完成相同任务的框架的数量。
class DB
private static $db = FALSE:
public static function init($dbConfig)
if(! self:$db)
self::$db = new Database($dbConfig);
public static function preparedSelect($sql, $params)
if(! self::$db)
die("call the init method first");
// db stuff, where you would call $this->db call self::$db
因此,在您想要调用数据库的其他类中,您所要做的就是:
class General
public function __construct()
DB::init($dbConfig);
public function someMethod()
$params = array('username' => $username);
$result = DB::preparedSelect('select password, salt from users where username = :username', $params);
【讨论】:
我正打算为此使用静态方法,但经过研究表明,像 General 类(当前是 DB)这样的依赖关系并不立即明显 - 并且可能会导致混乱。不应该以这种方式使用静态方法/单例 - 而应该使用 依赖注入 / 将变量显式传递给构造函数,以便可以准确地看到类依赖于哪些类:)以上是关于将 $db 对象传递给其他类,以便它们可以访问数据库的主要内容,如果未能解决你的问题,请参考以下文章
是否可以创建同一对象的不同实例并通过将参数传递给 Koin 中的 get() 函数来访问它们?
当我将参数传递给类构造函数时,是否需要其他名称相同或自已的函数可用?