将 $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() 函数来访问它们?

将 Firebase 用户对象传递给新组件

将 parcelable 对象传递给新活动返回 null

当我将参数传递给类构造函数时,是否需要其他名称相同或自已的函数可用?

如何将选定的 uitableviewcell 核心数据对象传递给新的视图控制器?

如何将事件和其他参数传递给单击处理程序