PHP中的MySQLi扩展学习(二)mysqli类的一些少见的属
虽说是少见的一些属性方法,但是可能还是有不少同学在日常的开发中使用过,这里只是学习了可能相对来说我们用得比较少的一些 mysqli 的属性或方法。就当是扩展一下自己的知识体系。
切换用户
首先就是切换一下当前连接数据库的用户。
// 切换用户
$mysqli->change_user('root2', "123", 'blog_test');
// 错误信息
$res = $mysqli->query( "SELECT * FROM zyblog_test_user");
var_dump($res); // bool(false)
var_dump($mysqli->error_list);
// array(1) {
// [0]=>
// array(3) {
// ["errno"]=>
// int(1142)
// ["sqlstate"]=>
// string(5) "42000"
// ["error"]=>
// string(78) "SELECT command denied to user 'root2'@'localhost' for table 'zyblog_test_user'"
// }
// }
使用 change_user() 方法就能够方便地在 mysqli 对象已经实例化之后再来进行用户的切换。在这段代码中,我们的 root2 用户没有 blog_test 表的 SELECT 权限,所以返回的 query() 查询结果是空的。通过打印 mysqli 的 error_list 属性就可以看到当前的错误信息。
错误信息
紧接着上一段,对于执行语句的错误信息,我们可以通过几个 mysqli 中的属性来获得。比如上文中的 error_list 。它里面包含的就是所有的错误信息列表,并且是非常详细的错误信息内容。不过我们还可以通过另外两个属性来获得单独的错误号和错误信息的字符串。
var_dump($mysqli->errno); // int(1142)
var_dump($mysqli->error); // string(78) "SELECT command denied to user 'root2'@'localhost' for table 'zyblog_test_user'"
errno 属性里面保存的就是数据库的错误号,error 属性中保存的是错误信息的详细文本说明。这两个错误信息内容都是在执行 SQL 语句之后数据库返回的内容。
连接错误信息
当然,如果在连接数据库的时候就产生了错误,我们也可以通过 connect_errno 和 connect_error 来获得它们的错误号和错误信息内容。
$mysqli2 = @new mysqli("xxx", "root", "", "blog_test");
var_dump($mysqli2->connect_errno); // int(2002)
var_dump($mysqli2->connect_error); // string(90) "php_network_getaddresses: getaddrinfo failed: nodename nor servname provided, or not known"
在这段代码中,我们使用了错误的 host 信息。如果不在实例化的时候加上错误抑制符,那么在实例化的时候就会报出 PHP 的警告信息 Warning 。在这里我们为了测试输出的清晰,加上了错误抑制符。
客户端连接的统计数据
var_dump($mysqli->get_connection_stats());
// array(163) {
// ["bytes_sent"]=>
// string(3) "306"
// ["bytes_received"]=>
// string(3) "287"
// ["packets_sent"]=>
// string(2) "10"
// ["packets_received"]=>
// string(1) "6"
// ["protocol_overhead_in"]=>
// string(2) "24"
// ["protocol_overhead_out"]=>
// string(2) "40"
// ["bytes_received_ok_packet"]=>
// string(1) "0"
// ["bytes_received_eof_packet"]=>
// string(1) "0"
// ……
// ……
// ["bytes_received_real_data_normal"]=>
// string(1) "0"
// ["bytes_received_real_data_ps"]=>
// string(1) "0"
// }
通过 get_connection_stats() 方法,我们可以获得当前数据库连接的一些统计信息。返回的内容非常多,官方也没有具体的每个字段的说明文档。不过从字段名中我们还是可以看到一些有用的信息,比如 bytes_sent 字节发送的数量,bytes_received 字节接收的数量。
字符集
最近这些年,我们使用 PHP + MySQL 开发基本上都已经是统一地在使用 UTF-8 来作为默认的字符集编码了。不过在早些时候,包括 Discuz 、 DedeCMS 这些早期的开源建站程序都会提供一套 UTF-8 和一套 GBK 的源码供大家使用。而 mysqli 则可以方便快捷地获取及切换当前数据库所使用的字符集。
获取数据库字符
// 获取数据库字符
var_dump($mysqli->character_set_name()); // string(4) "utf8"
character_set_name() 不要以为看到一个 set 关键字就是设置或者修改什么,这个方法是获取当前的字符集信息的。
字符集详细信息
var_dump($mysqli->get_charset());
// object(stdClass)#2 (8) {
// ["charset"]=>
// string(4) "utf8"
// ["collation"]=>
// string(15) "utf8_general_ci"
// ["dir"]=>
// string(0) ""
// ["min_length"]=>
// int(1)
// ["max_length"]=>
// int(3)
// ["number"]=>
// int(33)
// ["state"]=>
// int(1)
// ["comment"]=>
// string(13) "UTF-8 Unicode"
// }
我们也可以通过 get_charset() 获取当前数据库连接的详细字符集信息。其中 charset 就是字符类型,我们这里是 UTF-8 类型的,字符集是 utf8_general_ci ,这一套基本上就是我们现在开发时的标配了。
设置字符集
$mysqli->set_charset('gbk');
$mysqli->query("insert into zyblog_test_user(username, password, salt) values('GBK字符','dd','d')");
var_dump($mysqli->error); // string(65) "Incorrect string value: '\xAC\xA6' for column 'username' at row 1"
$mysqli->set_charset('utf8');
$mysqli->query("insert into zyblog_test_user(username, password, salt) values('UTF字符','dd','d')");
var_dump($mysqli->error);
echo $mysqli->insert_id, PHP_EOL;
通过 set_charset() 方法就可以设置当前数据库连接的字符。在第一段代码中我们将连接字符设置为 gbk ,然后执行插入语句,直接就会返回字符不匹配的信息了。
特殊字符转义
既然说到字符的问题了,我们顺便多提一句关于 SQL 注入的问题。除了使用 预处理 功能来解决 SQL 注入之外,MySQLi 还为我们提供了一个 real_escape_string() 方法,可以手工地解决SQL语句中的一些特殊符号问题。
$username = "aaa ' bbb";
$username = $mysqli->real_escape_string($username);
var_dump($username); // string(10) "aaa \' bbb"
使用这个方法可以说和 addslashes() 方法类似,不过它比 addslashes() 方法转义的内容更多一些,它包括: NUL (ASCII 0),\n,\r,\,'," 和 Control-Z 这些字符。
线程操作
关于 MySQL 的线程问题,我们将来在深入学习并且刷 MySQL 文档的时候再说(因为现在我也不是很清楚~~)。在这里,我们就先看看 mysqli 中关于 MySQL 线程的几个属性和方法吧。
var_dump($mysqli->thread_safe); // NULL
var_dump($mysqli->thread_id); // int(600)
$thread_id = $mysqli->thread_id;
$mysqli->kill($thread_id);
if (!$mysqli->query("insert into zyblog_test_user(username, password, salt) values('kill线程了','dd','d')")) {
var_dump($mysqli->error); // string(26) "MySQL server has gone away"
}
thread_safe 属性是保存的当前数据库连接是否是线程安全的,在我们的测试中返回的是 NULL 而不是正常的布尔值,这一块将来我们学习到了再说。thread_id 属性保存的是当前连接的线程ID,通过这个线程ID,我们就可以使用另外一个 kill() 方法来杀死当前的线程。其实就相当于关闭了当前这个 mysqli 对象的连接,这时我们再使用这个连接对象进行其它操作时就会出现 MySQL server has gone away 的提示信息了。
mysqli 对象
上面说的很多属性其实我们可以直接通过打印 mysqli 对象就可以查看到。
var_dump($mysqli);
// object(mysqli)#1 (19) {
// ["affected_rows"]=>
// int(1)
// ["client_info"]=>
// string(79) "mysqlnd 5.0.12-dev - 20150407 - $Id: 7cc7cc96e675f6d72e5cf0f267f48e167c2abb23 $"
// ["client_version"]=>
// int(50012)
// ["connect_errno"]=>
// int(2002)
// ["connect_error"]=>
// string(90) "php_network_getaddresses: getaddrinfo failed: nodename nor servname provided, or not known"
// ["errno"]=>
// int(0)
// ["error"]=>
// string(0) ""
// ["error_list"]=>
// array(0) {
// }
// ["field_count"]=>
// int(0)
// ["host_info"]=>
// string(25) "Localhost via UNIX socket"
// ["info"]=>
// NULL
// ["insert_id"]=>
// int(59)
// ["server_info"]=>
// string(6) "8.0.17"
// ["server_version"]=>
// int(80017)
// ["stat"]=>
// string(139) "Uptime: 355128 Threads: 4 Questions: 35696 Slow queries: 0 Opens: 764 Flush tables: 3 Open tables: 636 Queries per second avg: 0.100"
// ["sqlstate"]=>
// string(5) "00000"
// ["protocol_version"]=>
// int(10)
// ["thread_id"]=>
// int(606)
// ["warning_count"]=>
// int(0)
// }
像是 host_info 显示的是我们连接数据库的 host 信息,server_info 是连接到的数据库的版本信息,就像我们这里使用的是 MySQL8 。stat 简单的统计信息,里面能看到有 4 个线程,没有慢查询等等。大家可以仔细地研究一下这个对象中的这些属性,或许某些内容就是你在实际项目中所需要的。
总结
今天的文章学习的就是一些简单的 mysqli 类所持有的属性和方法。我们还没有正式开始学习查询之类的语句,不过从这些属性方法就可以看出,相对于 PDO 来说,mysqli 提供的功能确实更加的全面一些。后面我们将继续深入地学习和探索 mysqli 的各种方法和使用。
测试代码:
参考文档:
https://www.php.net/manual/zh/book.mysqli.php
各自媒体平台均可搜索【硬核项目经理】