多个 mysqli 对象相互覆盖

multiple mysqli objects overwrite each other

如果我创建到两个服务器的两个并行连接:

$gw03 = new mysqli('gw03.example', 'user', 'pass', 'db');
$gw04 = new mysqli('gw04.example', 'user', 'pass', 'db');

if (!$gw03->connect_errno) {
  ...
} else if (!$gw04->connect_errno) {
  ...
} else {
  echo "Failed to connect to gw03: (" . $gw03->connect_errno . ") " . $gw03->connect_error . PHP_EOL;
  echo "Failed to connect to gw04: (" . $gw04->connect_errno . ") " . $gw04->connect_error . PHP_EOL;
}

如果gw03可用,gw04不可用,结果如下

Failed to connect to gw03: (2002) No route to host
Failed to connect to gw04: (2002) No route to host

未能连接到 $gw04 似乎覆盖了 $gw03。 $gw03 和 $gw04 不是独立的对象吗?这是怎么回事?

它们是单独的连接,但是 connect_errno 方法“returns 来自上次连接调用的错误代码”。

https://www.php.net/manual/en/mysqli.connect-errno.php

您需要在每次连接尝试后立即检查连接错误。

$gw03 = new mysqli('gw03.example', 'user', 'pass', 'db');
# check $gw03 for connection error before attempting next connection
$gw04 = new mysqli('gw04.example', 'user', 'pass', 'db');

不幸的是,mysqli 的设计很糟糕。属性 connect_errnoconnect_error 并不是真正的属性。它们只是全局变量的快捷方式。当第二个连接失败时,全局变量在内部被覆盖。

这是的一个很好的理由。当错误发生时,您的代码应该抛出错误而不是警告或静默失败。此错误应由您的应用程序正确处理并记录在服务器上的安全位置。不要try-catchecho错误信息给用户!

要启用 mysqli 错误报告,您应该在任何 new mysqli()/mysqli_connect():

之前添加以下行
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);

这个设置会告诉mysqli一旦遇到错误就抛出异常。不再需要手动检查,也不再有全局变量覆盖自身的问题。