PHP print_r清除mysqli连接对象的状态?

时间:2014-08-06 05:10:06

标签: php mysql mysqli

我有一个MySQL表,我需要三个列,每个列在表中是唯一的,userName,userEmail和userUID。对于每个列,使用UNIQUE设置该表。为了防止竞争条件,我尝试单个插入新用户,然后选择重复的条目'错误,解析错误消息以确定哪个列出现问题,然后询问用户新信息。我正在尝试调试此代码并放置print_r($dbConn, true)以捕获INSERT语句的结果,然后再对重复的列名进行任何测试。这打破了很长时间,因为它似乎消灭了mysqli连接对象中的errnoerror值。这是一个说明问题的简化示例:

<?php
    error_reporting(E_ALL);
    echo 'PHP Version: ' . phpversion() . PHP_EOL;
    $dbConn = @new mysqli('127.0.0.1', 'userX', 'passwordX', 'databaseX');
    $dbConn->query('CREATE TABLE IF NOT EXISTS print_r_test (' .
            'username VARCHAR(64), UNIQUE (username)');
    echo 'Created print_r_test table.' . PHP_EOL;
    $dbConn->query('TRUNCATE TABLE print_r_test');
    echo 'Truncated print_r_test table.' . PHP_EOL;
    $dbConn->query('INSERT INTO print_r_test (username) VALUES (\'testuser\')');
    echo '' . 'INSERT#1: ' . $dbConn->errno . ': ' . $dbConn->error . PHP_EOL;
    // This next one fails with duplicate entry 'testuser' for 'username'
    $dbConn->query('INSERT INTO print_r_test (username) VALUES (\'testuser\')');
//  echo '$dbConn: ' . print_r($dbConn, true) . PHP_EOL;
    echo '' . 'INSERT#2: ' . $dbConn->errno . ': ' . $dbConn->error . PHP_EOL;
?>

请注意,第14行已注释掉。

如果按原样运行(在更改userX,passwordX和databaseX之后),它按预期工作:

H:>php print_r_test2.php
PHP Version: 5.4.10
Created print_r_test table.
Truncated print_r_test table.
INSERT#1: 0:
INSERT#2: 1062: Duplicate entry 'testuser' for key 'username'

第10行的第一个INSERT工作并报告errno = 0。第二个插入失败,错误为errno = 1-62,并显示一条消息,指示重复的用户名。

现在,删除第14行上的//,以便将$ dbConn内容打印到输出中,然后我得到:

H:>php print_r_test2.php
PHP Version: 5.4.10
Created print_r_test table.
Truncated print_r_test table.
INSERT#1: 0:
$dbConn: mysqli Object
(
    [affected_rows] => -1
    [client_info] => mysqlnd 5.0.10 - 20111026 - $Id: b0b3b15c693b7f6aeb3aa66b646fee339f175e39 $
    [client_version] => 50010
    [connect_errno] => 0
    [connect_error] =>
    [errno] => 1062
    [error] => Duplicate entry 'testuser' for key 'username'
    [error_list] => Array
        (
            [0] => Array
                (
                    [errno] => 1062
                    [sqlstate] => 23000
                    [error] => Duplicate entry 'testuser' for key 'username'
                )

        )

    [field_count] => 0
    [host_info] => 127.0.0.1 via TCP/IP
    [info] =>
    [insert_id] => 0
    [server_info] => 5.6.19
    [server_version] => 50619
    [stat] => Uptime: 26920  Threads: 2  Questions: 97  Slow queries: 0  Opens: 85  Flush tables: 1  Open tables: 61  Queries per second avg: 0.003
    [sqlstate] => 00000
    [protocol_version] => 10
    [thread_id] => 20
    [warning_count] => 0
)

INSERT#2: 0:

第二个INSERT报告0表示确定,但显然失败了。

这里似乎发生的是print_r($dbConn, true)导致errno连接对象的error$dbConn属性设置为零。这导致我的代码查找1062错误无法找到它。

如果我将print_r行注释掉并复制INSERT#2行,则会打印出1062错误消息两次。

如果我复制了print_r行,那么我会看到第二行打印出errno -> 0error为空。我注意到的是,第二个显示连接Questions中的stat计数已增加1。所以我的想法是print_r的{​​{1}}导致对MySQL的另一个查询成功并返回0表示确定并吹掉那里的先前值。

这似乎不是很有帮助,或者我在这里遗失了一些令人目眩的事情?

感谢。

在下面的@ Phil评论中,我的问题是我做错了什么(如果有的话)打破了$dbConn对象中的errnoerror回复?< / p>

它与$dbConn无关。用以下代替最后一行:

print_r

导致输出为:

echo '' . 'INSERT#2: ' . $dbConn->errno . ': ' . $dbConn->error . PHP_EOL . $dbConn->stat . PHP_EOL;
echo '' . 'INSERT#2: ' . $dbConn->errno . ': ' . $dbConn->error . PHP_EOL . $dbConn->stat . PHP_EOL;

这样做:

INSERT#2: 1062: Duplicate entry 'testuser' for key 'username'
Uptime: 29364  Threads: 2  Questions: 136  Slow queries: 0  Opens: 91  Flush tables: 1  Open tables: 61  Queries per second avg: 0.004
INSERT#2: 0:
Uptime: 29364  Threads: 2  Questions: 137  Slow queries: 0  Opens: 91  Flush tables: 1  Open tables: 61  Queries per second avg: 0.004

结果:

echo '' . 'INSERT#2: ' . $dbConn->errno . ': ' . $dbConn->error . PHP_EOL;
echo '' . 'INSERT#2: ' . $dbConn->errno . ': ' . $dbConn->error . PHP_EOL;

如果读取连接对象不是幂等操作,那么这对我来说就像是一个陷阱,也是问题和挫折的根源。所以我的问题是,是否有一些我做错了或遗失的事情,或者这是mysqli的一些奇怪特征?

2 个答案:

答案 0 :(得分:3)

如果查看documentation for mysqli->stat(),它是一个在服务器上执行命令'mysqladmin status'的函数,并返回服务器返回的任何内容。如果您查看the documentation for mysqli->errno,您会看到它“返回最近函数调用的错误代码”。

那会发生什么?

您执行查询,并阅读错误代码。然后执行另一个未失败的命令,并读取该命令的错误代码。这正是你应该发生的事情。


如果在调用stat()之后需要使用errno或error的值,则在调用stat()之前,没有任何内容阻止您将这些值存储在变量中:

$a = $dbConn->errno;
$b = $dbConn->error;
$c = $dbConn->stat();

echo $a . $b . $c;

答案 1 :(得分:2)

这是一个有趣的问题,我在查看文档后找到答案:http://php.net/manual/en/class.mysqli.php

这些是对象属性:错误,错误。因此,访问它们不会影响对象的状态。

另一方面,stat()是对象的方法调用。这意味着将更新errno和错误以反映该调用是成功还是失败。