ホームページ  >  記事  >  バックエンド開発  >  PHP で設定されたクエリ構造を 3 分で理解できます

PHP で設定されたクエリ構造を 3 分で理解できます

醉折花枝作酒筹
醉折花枝作酒筹転載
2021-06-18 17:04:371609ブラウズ

この記事では、PHPPHP で設定されるクエリ構造について紹介します。一定の参考値があるので、困っている友達が参考になれば幸いです。

PHP で設定されたクエリ構造を 3 分で理解できます

# PHP で学ぶ PDO 操作 (4) クエリ構造セット

PDO に関する前回の記事では、PDO の操作について説明します。結果セットのクエリが完了しました。データベース操作では、クエリが非常に大きな割合を占めることがよくあります。日常の開発では、ほとんどのビジネスは読み書き不要のビジネスであるため、クエリ関連の操作を習得することは学習の重要な部分です。 mysqli と同様に、PDO のクエリのサポートも非常に便利かつ高速で、いくつかの関数を使用してさまざまなクエリ ステートメントを非常に便利かつ効率的に操作できます。

準備されたステートメントを使用する場合、execute() を使用して実行した後、クエリの結果セットは PDOStatement オブジェクトに保存されます。データに対する操作は PHP オブジェクトに転送されるため、結果セットの内容を取得するには PDOStatement のいくつかのメソッドが必要です。

fetch() メソッド

fetch() メソッドを通じて、クエリ結果セットの次の行が取得されます。

$stmt = $pdo->prepare("select * from zyblog_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);
// PDORow Object
// (
//     [queryString] => select * from zyblog_test_user
//     [id] => 3
//     [username] => ccc
//     [password] => bbb
//     [salt] => c3
// )

$row = $stmt->fetch(PDO::FETCH_OBJ);
print_r($row);
// stdClass Object
// (
//     [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("select * from zyblog_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("select * from zyblog_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() の第 2 パラメータを指定した後の結果は異なります。 PDO::FETCH_ORI_NEXT はカーソルの次のデータを取得し、PDO::FETCH_ORI_LAST はカーソルの最後のデータを取得します。しかし、MySQL でのテストでは、効果はなく、結果セット内の次のデータが引き続き取得されました。

fetchAll() メソッド

fetch() メソッドを通じて、結果セット内のすべてのデータを取得できますが、それでもループを通過する必要があります。まだ少し面倒です。実際、PDO は、結果セット内のすべての行を含む配列を返す別のメソッド fetchAll() をすでに用意しています。

$stmt = $pdo->prepare("select * from zyblog_test_user limit 2");
$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() を使用して、結果セットを走査して配列に割り当てるのに役立ちます。したがって、re-execute() を行わずに fetchAll() を再度呼び出すと、空のデータが取得されます。カーソルが一番下まで来たからです。

$list = $stmt->fetchAll();
print_r($list);
// Array
// (
// )

FETCH_STYLE の指定もサポートされており、fetch() メソッドと同様に、必要な型定数を最初のパラメーターに直接割り当てることができます。

// PDO::FETCH_ASSOC
$stmt = $pdo->prepare("select * from zyblog_test_user limit 2");
$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("select * from zyblog_test_user limit 2");
$stmt->execute();

$list = $stmt->fetchAll(PDO::FETCH_COLUMN, 1);
print_r($list);
// Array
// (
//     [0] => aaa
//     [1] => bbb
// )

// PDO::FETCH_CLASS
class User{
    function __construct($a){
        echo $a, PHP_EOL;
    }
}
$stmt = $pdo->prepare("select * from zyblog_test_user limit 2");
$stmt->execute();
$list = $stmt->fetchAll(PDO::FETCH_CLASS, 'User', ['FetchAll User']);
print_r($list);
// FetchAll User
// FetchAll User
// Array
// (
//     [0] => User Object
//         (
//             [id] => 1
//             [username] => aaa
//             [password] => aaa
//             [salt] => aaa
//         )

//     [1] => User Object
//         (
//             [id] => 2
//             [username] => bbb
//             [password] => bbb
//             [salt] => 123
//         )

// )

ご存知ですか?ここでは詳しく説明しません。FETCH_STYLE の型指定については何度もお話してきました。使い方は fetch() メソッドや query() メソッドと同じです。 PDO オブジェクト内でもほぼ同じです。ただし、データセットを取得するためにコールバックでメソッドを呼び出す形式もサポートしています。

function getValue(){
    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("select * from zyblog_test_user limit 2");
$stmt->execute();
$list = $stmt->fetchAll(PDO::FETCH_FUNC, 'getValue');
print_r($list);
// Array
// (
//     [0] => 
//     [1] => 
// )

このコードでは PDO::FETCH_FUNC を使用しており、2 番目のパラメーターはメソッド名です。このようにして、各構造体セットは、トラバーサル中に指定されたメソッドを呼び出すためのメソッド パラメーターとして使用され、func_get_args() を通じてこれらのパラメーターの内容を取得できます。このコードでは、結果セットは fetchAll() メソッドの戻り値を通じて $list 変数に割り当てられません。データは指定された getValue() メソッドに渡されているためです。

fetchColumn() メソッド

上記のテスト コードでは、PDO::FETCH_COLUMN を使用して、結果セット内の特定のデータ列を取得しました。この方法で記述することに問題はありませんが、より便利な方法があります。それは、PDOStatment が直接提供する fetchColumn() メソッドです。これは、メソッド内でデフォルトで PDO::FETCH_COLUMN を指定するのと同等で、必要なパラメータは列の添え字 1 つだけです。

関数の戻り値は次の行の指定された列の値であることに注意してください。つまり、最後に fetch() メソッドが呼び出されます。結果セット内の指定されたすべての列の内容を取得したい場合は、 fetch() と同じ方法で結果セットを走査する必要もあります。

// fetchColumn
$stmt = $pdo->prepare("select * from zyblog_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("select * from zyblog_test_user");
$stmt->execute();
$user = $stmt->fetchObject('User', ['FetchObject User']);
print_r($user);
// FetchObject User
// User Object
// (
//     [id] => 1
//     [username] => aaa
//     [password] => aaa
//     [salt] => aaa
// )

rowCount() 返回查询结果数量

要获得查询的结果集行数就需要我们的 rowCount() 方法了。数据库中不管是查询还是增、删、改操作,都会返回语句执行结果,也就是受影响的行数。这些信息都是通过 rowCount() 这个方法获得的。

查询语句返回行数

需要注意的是,在查询语句中,有些数据是可能返回此语句的行数的。但这种方式不能保证对所有数据有效,且对可移植的应用更不要依赖这种方式。我们如果需要知道当前查询结果的数量,还是通过遍历 fetch() 或者通过 count(fetchAll()) 来根据真实查询到的结果集数量确定这一次查询的真实行数。

其实它就像是 PDO 对象的 exec() 方法所返回的数据。在不使用预处理语句的情况下,直接使用 PDO 的 exec() 方法执行 SQL 语句后,返回的也是语句执行后受影响的行数。

$stmt = $pdo->prepare("select * from zyblog_test_user");
$stmt->execute();
$rowCount = $stmt->rowCount();
echo $rowCount, PHP_EOL;
// 41

增、删、改语句返回受影响的行数

$stmt = $pdo->prepare("insert into zyblog_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("update zyblog_test_user set username=? where username = ?");
$stmt->execute(['ccc','cccc']);
$rowCount = $stmt->rowCount();
echo $rowCount, PHP_EOL; // 25

$stmt = $pdo->prepare("update zyblog_test_user set username=? where username = ?");
$stmt->execute(['ccc','cccc']);
$rowCount = $stmt->rowCount();
echo $rowCount, PHP_EOL; // 0

$stmt = $pdo->prepare("delete from zyblog_test_user where username = ?");
$stmt->execute(['ddd']);
$rowCount = $stmt->rowCount();
echo $rowCount, PHP_EOL; // 11

$stmt = $pdo->prepare("delete from zyblog_test_user where username = ?");
$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

推荐学习:php视频教程

以上がPHP で設定されたクエリ構造を 3 分で理解できますの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はsegmentfault.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。