在利用预处理语句的情形下,我们利用 execute() 实行之后,查询的结果集就会保存在 PDOStatement 工具中。对付数据的操作就转移到了 PHP 的工具中,以是我们须要 PDOStatement 的一些方法来得到结果集的内容。
fetch() 方法通过 fetch() 方法,得到的是查询结果集的下一行。
$stmt=$pdo->prepare("selectfromzyblog_test_user");$stmt->execute();$row=$stmt->fetch();print_r($row);//Array//(//[id]=>1//[0]=>1//[username]=>aaa//[1]=>aaa//[password]=>aaa//[2]=>aaa//[salt]=>aaa//[3]=>aaa//)
从返回的结果来看,我们没有给 PDO 工具指定 PDO::ATTR_DEFAULT_FETCH_MODE 属性,以是它是返回的默认的 PDO::FETCH_BOTH 格式,也便是字段名和下标同时存在的。实在这个方法可以直接指定我们须要的 FETCH_STYLE 。
结果集类型指定
$row=$stmt->fetch(PDO::FETCH_ASSOC);print_r($row);//Array//(//[id]=>2//[username]=>bbb//[password]=>bbb//[salt]=>123//)$row=$stmt->fetch(PDO::FETCH_LAZY);print_r($row);//PDORowObject//(//[queryString]=>selectfromzyblog_test_user//[id]=>3//[username]=>ccc//[password]=>bbb//[salt]=>c3//)$row=$stmt->fetch(PDO::FETCH_OBJ);print_r($row);//stdClassObject//(//[id]=>4//[username]=>ccc//[password]=>bbb//[salt]=>c3//)
和指定 PDO 工具的 PDO::ATTR_DEFAULT_FETCH_MODE 一样。利用 fetch() 方法时直接将须要的返回结果类型参数指定到方法的第一个参数,就实现了 FETCH_STYLE 的指定。详细支持的格式和之前讲过的 PDO 工具的 PDO::ATTR_DEFAULT_FETCH_MODE 属性是完备一样的,大家可以自行查阅。
获取全部数据从代码和定义中可以看出,fetch() 方法是获取当前数据集的下一行数据,就像数据库的游标操作一样。以是,我们可以通过循环 fetch() 来对结果集进行遍历,从而得到所有的结果集数据。
while($row=$stmt->fetch()){print_r($row);}//Array//(//[id]=>2//[0]=>2//[username]=>bbb//[1]=>bbb//[password]=>bbb//[2]=>bbb//[salt]=>123//[3]=>123//)//……
MySQL 不支持游标
上文中提到了游标操作,PDO 扩展是支持游标的,但是须要把稳的是,MySQL 扩展并不支持这个操作。以是我们利用游标干系的属性对付 MySQL 库是没有效果的。
$stmt=$pdo->prepare("selectfromzyblog_test_user",[PDO::ATTR_CURSOR=>PDO::CURSOR_SCROLL]);$stmt->execute();$row=$stmt->fetch(PDO::FETCH_ASSOC,PDO::FETCH_ORI_NEXT);print_r($row);//Array//(//[id]=>1//[username]=>aaa//[password]=>aaa//[salt]=>aaa//)$stmt=$pdo->prepare("selectfromzyblog_test_user",[PDO::ATTR_CURSOR=>PDO::CURSOR_SCROLL]);$stmt->execute();$row=$stmt->fetch(PDO::FETCH_ASSOC,PDO::FETCH_ORI_LAST);print_r($row);//Array//(//[id]=>1//[username]=>aaa//[password]=>aaa//[salt]=>aaa//)
如果是支持游标操作的数据库及扩展的话,上面代码中的 fetch() 的第二个参数指定后,获取的结果是会不同的。PDO::FETCH_ORI_NEXT 是获取游标的下一条数据,而 PDO::FETCH_ORI_LAST 是获取游标的末了一条数据。但是在我们对 MySQL 的测试中,它们并没有任何效果,依然是获取结果集的下一条数据。
fetchAll() 方法通过 fetch() 方法,我们可以得到结果集中的全部数据,不过还是须要一个循环才能进行遍历,多少还是有点麻烦。实在,PDO 早就为我们准备好了另一个方法,fetchAll() 便是返回一个包含结果集中所有行的数组。
$stmt=$pdo->prepare("selectfromzyblog_test_userlimit2");$stmt->execute();$list=$stmt->fetchAll();print_r($list);//Array//(//[0]=>Array//(//[id]=>1//[0]=>1//[username]=>aaa//[1]=>aaa//[password]=>aaa//[2]=>aaa//[salt]=>aaa//[3]=>aaa//)//[1]=>Array//(//[id]=>2//[0]=>2//[username]=>bbb//[1]=>bbb//[password]=>bbb//[2]=>bbb//[salt]=>123//[3]=>123//)//)
fetchAll() 便是在内部利用了 fetch() 帮我们遍历了一次结果集并且赋值到了一个数组中。以是我们如果在不重新 execute() 情形下再次调用 fetchAll() 的话,获取的便是空的数据。由于游标已经到底了。
$list=$stmt->fetchAll();print_r($list);//Array//(//)
它同样支持指定 FETCH_STYLE ,也和 fetch() 方法一样,直接将须要的类型常量赋值给第一个参数就可以了。
//PDO::FETCH_ASSOC$stmt=$pdo->prepare("selectfromzyblog_test_userlimit2");$stmt->execute();$list=$stmt->fetchAll(PDO::FETCH_ASSOC);print_r($list);//Array//(//[0]=>Array//(//[id]=>1//[username]=>aaa//[password]=>aaa//[salt]=>aaa//)//[1]=>Array//(//[id]=>2//[username]=>bbb//[password]=>bbb//[salt]=>123//)//)//PDO::FETCH_COLUMN$stmt=$pdo->prepare("selectfromzyblog_test_userlimit2");$stmt->execute();$list=$stmt->fetchAll(PDO::FETCH_COLUMN,1);print_r($list);//Array//(//[0]=>aaa//[1]=>bbb//)//PDO::FETCH_CLASSclassUser{function__construct($a){echo$a,PHP_EOL;}}$stmt=$pdo->prepare("selectfromzyblog_test_userlimit2");$stmt->execute();$list=$stmt->fetchAll(PDO::FETCH_CLASS,'User',['FetchAllUser']);print_r($list);//FetchAllUser//FetchAllUser//Array//(//[0]=>UserObject//(//[id]=>1//[username]=>aaa//[password]=>aaa//[salt]=>aaa//)//[1]=>UserObject//(//[id]=>2//[username]=>bbb//[password]=>bbb//[salt]=>123//)//)
是不是非常熟习了,这里就不多讲了,关于 FETCH_STYLE 的类型指定已经说过很多遍了,它的用法和 fetch() 以及 PDO 工具中的 query() 方法都是差不多的。不过它还支持一种以回调办法调用一个方法的形式来得到数据集。
functiongetValue(){print_r(func_get_args());}//Array//(//[0]=>1//[1]=>aaa//[2]=>aaa//[3]=>aaa//)//Array//(//[0]=>2//[1]=>bbb//[2]=>bbb//[3]=>123//)$stmt=$pdo->prepare("selectfromzyblog_test_userlimit2");$stmt->execute();$list=$stmt->fetchAll(PDO::FETCH_FUNC,'getValue');print_r($list);//Array//(//[0]=>//[1]=>//)
在这段代码中,我们利用的是 PDO::FETCH_FUNC ,第二个参数是一个方法名称。这样每一条构造集都会在遍历的时候作为方法的参数去调用指定的这个方法,我们通过 func_get_args() 就可以获取到这些参数内容。在这段代码中,结果集并不会通过 fetchAll() 方法的返回值赋值给 $list 变量了。由于数据都已经通报给了指定的 getValue() 方法了。
fetchColumn() 方法在上面的测试代码中,我们利用过 PDO::FETCH_COLUMN 来获取结果集的某一列数据。这样写没什么问题,但是还有更方便的办法,也便是 PDOStatment 直接为我们供应的一个 fetchColumn() 方法。它就相称于是默认的在方法内部指定了 PDO::FETCH_COLUMN ,并且只须要一个参数便是列的下标。
须要把稳的是,它的返回是下一行的指定列值,也便是说,它在底层是调用的 fetch() 方法。如果要获取结果集中所有指定列的内容,我们还须要通过和 fetch() 的遍历办法一样的方法来遍历结果集。
//fetchColumn$stmt=$pdo->prepare("selectfromzyblog_test_user");$stmt->execute();$column=$stmt->fetchColumn(2);echo$column,PHP_EOL;//aaa$column=$stmt->fetchColumn(3);echo$column,PHP_EOL;//123
fetchObject() 方法
fetchObject() 就不用多阐明了,它和 fetchColumn() 是类似的,只是返回的是下一行数据的工具格式。同样的,它也是可以通报布局参数的,这点和 PDO 工具的 query() 中指定的 PDO::FETCH_CLASS 格式的利用是一样的。我们在第一篇文章中就有讲解。
//fetchObject$stmt=$pdo->prepare("selectfromzyblog_test_user");$stmt->execute();$user=$stmt->fetchObject('User',['FetchObjectUser']);print_r($user);//FetchObjectUser//UserObject//(//[id]=>1//[username]=>aaa//[password]=>aaa//[salt]=>aaa//)
rowCount() 返回查询结果数量
要得到查询的结果集行数就须要我们的 rowCount() 方法了。数据库中不管是查询还是增、删、改操作,都会返回语句实行结果,也便是受影响的行数。这些信息都是通过 rowCount() 这个方法得到的。
查询语句返回行数须要把稳的是,在查询语句中,有些数据是可能返回此语句的行数的。但这种办法不能担保对所有数据有效,且对可移植的运用更不要依赖这种办法。我们如果须要知道当前查询结果的数量,还是通过遍历 fetch() 或者通过 count(fetchAll()) 来根据真实查询到的结果集数量确定这一次查询的真实施数。
实在它就像是 PDO 工具的 exec() 方法所返回的数据。在不该用预处理语句的情形下,直策应用 PDO 的 exec() 方法实行 SQL 语句后,返回的也是语句实行后受影响的行数。
$stmt=$pdo->prepare("selectfromzyblog_test_user");$stmt->execute();$rowCount=$stmt->rowCount();echo$rowCount,PHP_EOL;//41
增、删、改语句返回受影响的行数
$stmt=$pdo->prepare("insertintozyblog_test_user(username,password,salt)values(?,?,?)");$stmt->execute(['kkk','666','k6']);$rowCount=$stmt->rowCount();echo$rowCount,PHP_EOL;//1$id=$pdo->lastInsertId();echo$rowCount,PHP_EOL;//1$stmt=$pdo->prepare("updatezyblog_test_usersetusername=?whereusername=?");$stmt->execute(['ccc','cccc']);$rowCount=$stmt->rowCount();echo$rowCount,PHP_EOL;//25$stmt=$pdo->prepare("updatezyblog_test_usersetusername=?whereusername=?");$stmt->execute(['ccc','cccc']);$rowCount=$stmt->rowCount();echo$rowCount,PHP_EOL;//0$stmt=$pdo->prepare("deletefromzyblog_test_userwhereusername=?");$stmt->execute(['ddd']);$rowCount=$stmt->rowCount();echo$rowCount,PHP_EOL;//11$stmt=$pdo->prepare("deletefromzyblog_test_userwhereusername=?");$stmt->execute(['ddd']);$rowCount=$stmt->rowCount();echo$rowCount,PHP_EOL;//0
更新和删除操作在数据不存在、没有更新、没有删除的情形下都返回的是 0 。这一点我们也在 PDO 干系的第一篇文章中就说过了,对付业务来说,这种更新或删除到底算是成功还是失落败呢?还是大家根据自己的实际业务情形来确定吧!
关于 PDO 和 PDOStatement 干系的内容就学习到这里了。我们完全地梳理了一遍它们两个所有的方法,也都进行了干系的测试。大家在日常利用中可能打仗到的并不多,框架都已经为我们封装好了。不过对付学习来说,平常的小测试、小调试完备可以自己手写来加深影象和理解。在深入理解了这些扩展类的利用方法后,反过来又能帮助我们更加的清楚框架是如何去封装它们的。总之,学习便是不断的从高层到底层,再从底层返回高层,循环往来来往,才能更加的得心应手。
测试代码:
https://github.com/zhangyue0503/dev-blog/blob/master/php/202009/source/PHP%E4%B8%AD%E7%9A%84PDO%E6%93%8D%E4%BD%9C%E5%AD%A6%E4%B9%A0%EF%BC%88%E5%9B%9B%EF%BC%89%E6%9F%A5%E8%AF%A2%E7%BB%93%E6%9E%84%E9%9B%86.php
参考文档:
https://www.php.net/manual/zh/book.pdo.php