【问题标题】:PHP, Variable Scope QuestionPHP,变量范围问题
【发布时间】:2011-08-11 18:28:38
【问题描述】:

我的问题是我在我的通用脚本代码和我的一个函数中使用了变量 $db。它的目的是成为用于 MySQL 连接的变量。我需要在函数内部将一些数据写入数据库。在我的脚本中,我不能假设现有的数据库连接将打开,因此我打开一个新连接并在函数退出之前将其关闭。自从这样做以来,我在脚本运行后出现错误,提示 MySQL 引用错误/不存在。

我唯一可以将它固定在我的核心代码中,我使用变量 $db 作为数据库连接的变量名。我也在函数中使用相同的变量。我没想到这会是个问题,因为我没有在函数中的 $db 前面使用 global。这应该意味着我在函数中引用的 $db 在函数私有范围内,但它似乎正在关闭公共 $db 的连接。

有什么想法吗?

我的代码片段是:

database.php

db_connect()
{
 // open mysql db connection and return it;
}

db_close( &$db )
{
 // close the passed by reference db connection
}

api.php

api_verify( $keyid, $userid, $key )
{
  // open a new db connection
  $db = db_connect();

  // check for errors. if any errors are found note them in the db

  // close the db
  db_close($db);
}

ma​​in.php

include api.php;
include database.php;

// open a connection to the db
$db = db_connect();

// pull a list of things to process from the db and move through them one at a time
  // call api_verify() on each key before working through it's data.

db_close($db)

【问题讨论】:

  • 这取决于您的连接代码。如果您实际上是从池中提供连接,并且您的内部方法之一关闭了连接,那么您的外部方法之一指向的连接可能是陈旧的
  • 不要关闭连接...如果您使用相同的参数打开一个新连接,它只会重用已打开的连接,因此如果您在您的 api 函数中关闭该连接,您会在任何地方关闭它 - 即使你不会通过引用传递
  • 为什么要关闭连接?
  • 我想这只是我的偏执狂。我在函数中打开了一个新连接,因为我不想依赖已经打开的全局数据库连接,我关闭它是因为我喜欢关闭或释放我打开或创建的资源。
  • 好吧,我用我的代码做了更多的测试。似乎当您使用内置 mysql_connect 和 mysql_close 函数时,您将连接变量命名为什么并不重要。如果您使用 mysql_close 关闭与 mysql 服务器的连接,它将关闭与该特定服务器的所有连接。您无法创建与同一数据库服务器的独立连接并根据您创建它们的对象关闭它们,这有点烦人。无论哪种方式,我现在都假设 $db 对象已创建。

标签: php mysql scope


【解决方案1】:

要管理数据库连接,您可以创建一个类而不是一对函数。如果您说“MySQL 参考”,确切的错误是指“MySQL 资源”,那么您使用的是过时的 mysql 扩展,应该切换到更现代的扩展,例如 PDO。

class DBConnection {
    protected static $_connections = array(),
    static connect($dsn) {
        if (!isset(self::$_connections[$dsn])) {
            $credentials = self::getCredentials();
            /* Create connection. For example: */
            try {
                self::$_connections[$dsn][0] = new PDO($dsn, $credentials['username'], $credentials['password']);
            } catch (PDOException $exc) {
                // erase the frame w/ password from call trace to prevent leak.
                throw new PDOException($exc->getMessage(), $exc->getCode());
            }
            /* End create connection example */
            self::$_connections[$dsn][0]->dsn = $dsn;
        }
        ++self::$_connections[$dsn]['count'];
        return self::$_connections[$dsn][0];
    }
    static close($db) {
        if (isset(self::$_connections[$db->dsn])) {
            if (--(self::$_connections[$db->dsn]['count']) < 1) {
                unset(self::$_connections[$db->dsn]);
            }
        }
    }
    static getCredentials() {
        /* credentials can be stored in configuration file or script, in this method, or some other approach of your own devising */
    }
}

请注意,这并不完全是 OOP(它是,但仅在技术意义上)。以上不适合单元测试。如果您想要一种更面向对象的方法(这将更适合单元测试),请扩展或包装 PDO。使用dependency injection 也可以帮助解决上述coupling 问题。

【讨论】:

  • 我喜欢你对使用类的看法。一点也不坏=)。
  • @Mr.迷路:private state+functions = OOP(或者函数式编程,不过那需要PHP 5.3或更高,结果还是OOP)。
【解决方案2】:

我假设您在调用 db_connect 的每个位置都使用相同的用户名/密码打开与同一个数据库的连接。这样做时,除非您的 db_connect 明确指定您正在创建一个新链接,否则它将返回一个已打开的链接。如果该链接随后使用 db_close() 关闭,它也会关闭另一个连接,因为该链接是相同的。如果您使用 mysql_connect 连接到数据库,它需要一个名为 new link 的参数

new_link 如果使用相同的参数对 mysql_connect() 进行第二次调用,则不会建立新链接,而是返回已打开链接的链接标识符。 new_link 参数修改了这种行为并使 mysql_connect() 始终打开一个新链接,即使之前使用相同的参数调用了 mysql_connect() 也是如此。在 SQL 安全模式下,该参数被忽略。

参考http://php.net/manual/en/function.mysql-connect.php

我不确定这是否是您面临的问题。希望对您有所帮助。

【讨论】:

  • 干得好!这就是我一直在寻找的。我自己搜索了 google 和 php.net,但知道它的人确实是最好的资源!
【解决方案3】:

我会假设正在发生的事情是连接取消,因为已经有一个连接,然后关闭结束当前连接。
我会建议 A)在文件的开头开始一个连接,并且只知道它总是在那里(我做什么);或 B) 检查是否设置了 $db 变量,如果没有则创建连接,并始终在文件末尾结束连接。

【讨论】:

    猜你喜欢
    • 2016-08-30
    • 2011-04-10
    • 2013-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-21
    • 2011-04-13
    • 2011-10-20
    相关资源
    最近更新 更多