【问题标题】:Passing database connection by reference in PHP在 PHP 中通过引用传递数据库连接
【发布时间】:2010-09-19 11:18:14
【问题描述】:

问题是数据库连接应该通过引用还是值传递?

对我来说,我特别质疑 PHP 到 MySQL 的连接,但我认为它适用于所有数据库。

我听说在 PHP 中,当您将变量传递给函数或对象时,它会被复制到内存中,因此会立即使用两倍的内存。我还听说只有在对值进行更改后才会复制它(例如从数组中添加/删除键)。

在数据库连接中,我认为它正在函数内被更改,因为查询可能会更改最后插入 id 或 num 行之类的内容。 (我想这是另一个问题:是像 num rows 和 insert id 这样存储在连接中还是实际调用回数据库?)

那么,如果连接是通过引用或值传递的,内存或速度是否重要? PHP 4 和 5 有区别吗?

// $connection is resource
function DoSomething1(&$connection) { ... }
function DoSomething2($connection) { ... }

【问题讨论】:

    标签: php mysql database


    【解决方案1】:

    PHP 资源是一种特殊类型,它本身就是一个引用。通过值或通过引用显式传递它不会产生影响(即,它仍然是一个引用)。你可以在 PHP4 下自己检查这个:

    function get_connection() {
      $test = mysql_connect('localhost', 'user', 'password');
      mysql_select_db('db');
      return $test;
    }
    
    $conn1 = get_connection();
    $conn2 = get_connection(); // "copied" resource under PHP4
    
    $query = "INSERT INTO test_table (id, field) VALUES ('', 'test')";
    mysql_query($query, $conn1);
    print mysql_insert_id($conn1)."<br />"; // prints 1
    
    mysql_query($query, $conn2);
    print mysql_insert_id($conn2)."<br />"; // prints 2
    
    print mysql_insert_id($conn1); // prints 2, would print 1 if this was not a reference
    

    【讨论】:

      【解决方案2】:

      调用时传递引用正在被贬值,所以我不会使用首先描述的方法。另外,一般来说,资源在 PHP 5 中默认是通过引用传递的。因此,不应要求提供任何引用,并且除非您确实需要,否则永远不要打开多个数据库连接。

      就我个人而言,我使用单例工厂类进行数据库连接,每当我需要数据库引用时,我只需调用 Factory::database(),这样我就不必担心多个连接或传递/接收参考文献。

      <?php
      Class Factory
      {
        private static $local_db;
      
      /**
      * Open new local database connection
      *
      * @return MySql
      */
      public static function localDatabase() {
          if (!is_a(self::$local_db, "MySql")) {
              self::$local_db = new MySql(false);
              self::$local_db->connect(DB_HOST, DB_USER, DB_PASS, DB_DATABASE);
              self::$local_db->debugging = DEBUG;
          }
          return self::$local_db;
      }
      }
      ?>
      

      【讨论】:

      • "function DoSomething1(&$connection) { ... }" 不是调用时传递引用
      • 我只是想说和 tom 一样的话——这不是调用时传递引用,顾名思义,它发生在函数时。调用,而不是声明。调用时传递引用看起来像这样
      • 全局状态通常是任何问题的错误答案。
      • “已弃用”,而不是“已弃用”。
      • @troelskn,总是需要全局状态。数据库连接就是一个很好的例子。
      【解决方案3】:

      你应该关心的不是速度,而是内存。

      在 PHP 4 中,数据库连接和结果集之类的东西应该通过引用显式传递。在 PHP 5 中,这是自动完成的,因此您不必明确说明。

      顺便说一句,用于创建数据库句柄的单例方法是个好主意:您可以使用$db = &amp; Database::Connection(); 并始终获得正确的句柄。这使您免于使用全局,并且静态方法可以为您发挥额外的作用(例如自动打开它)。当你的应用程序扩展到需要多个数据库时要小心:然后你的魔法函数必须知道如何把正确的返回给你。 IME 这不是很困难;解决这个问题的基本方法是代码层需要数据库句柄知道如何请求正确的句柄。

      【讨论】:

        【解决方案4】:

        数据库连接 实际上并不保存底层值,因此您不必担心丢失函数内部的分配。打个比方,您可以将 DB connection 想象成一个跑道号——“OK,DB Connection 12 已被清除以用于查询”——查询和结果集 使用连接,可能需要一段时间的独占访问,但连接对底层数据一无所知。

        【讨论】:

          【解决方案5】:

          有些人说过,对于 PHP 5,您无需担心这一点。这是不正确的,如果您有一个用于所有访问的数据库 OBJECT。在这种情况下,您确实需要通过引用传递,否则它会实例化一个新的 DB 对象,该对象(通常)会创建与数据库的新连接。

          我使用 XDebug 和 WinCacheGrind 发现了这一点,它友好地显示了所有被调用的析构函数 - 在我的例子中,是六个或更多的数据库对象。

          澄清一下:我指出这一点的原因是这是使用数据库连接而不是原始连接资源的常用方式。

          【讨论】:

            【解决方案6】:

            我对 php 并没有真正的具体答案,但总的来说,如果您不确定在按值传递时遇到性能问题,您可能希望通过引用传递它。

            【讨论】:

              【解决方案7】:

              一般来说,引用在 PHP 中并不快。这是一个常见的误解,因为它们在语义上与 C 指针相似,所以熟悉 C 的人通常认为它们的工作方式相同。不是这样。事实上,引用比复制要慢一点,除非你实际分配给变量(在任何情况下都是不好的风格,除非变量是一个对象)。

              PHP 有一种称为写时复制的机制,这意味着在需要之前实际上复制变量。您可以将巨大的数据结构传递给函数;只要它只是从中读取,就没有区别。然而,一个引用需要在内部寄存器中添加一个额外的条目,因此它实际上需要一些额外的处理(虽然几乎不引人注意)。

              【讨论】:

                猜你喜欢
                • 2021-12-11
                • 1970-01-01
                • 2015-07-04
                • 2011-05-24
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2023-03-30
                • 1970-01-01
                相关资源
                最近更新 更多