ステートメントは、 mysqli::query(), mysqli::real_query(), mysqli::multi_query() を使って実行できます。 mysqli::query() がもっともよく使われますが、 ステートメントの実行と、 バッファリングされた結果セットの取得を一回の呼び出しで組み合わせることもできます。 mysqli::query() の呼び出しは、 mysqli::real_query() の後に mysqli::store_result() を呼び出すことと同じです。
例1 クエリを実行する
<?php
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli("example.com", "user", "password", "database");
$mysqli->query("DROP TABLE IF EXISTS test");
$mysqli->query("CREATE TABLE test(id INT)");
バッファリングされた結果セット
ステートメントを実行した後、 結果は一度に全部取得するか、 一行ずつ読み取ることのどちらかができます。 クライアント側で結果セットをバッファリングすることで、 サーバは結果セットに関連付けられたリソースをできるだけ早く開放できます。 一般的な話ですが、 クライアントが結果セットを処理する速度は遅いです。 そのため、バッファリングされた結果セットを使うことを推奨します。 mysqli::query() は、ステートメントの実行と結果セットのバッファリングを組み合わせます。
PHP アプリケーションは、 バッファリングされた結果セットを通して、結果を自由に操作できます。 そうすることで、結果セットがクライアント側のメモリに保持されるため、 高速です。 サーバ側をスケールさせるより、 クライアント側でスケールさせるほうが容易なことがある、 ということを頭に入れておいて下さい。
例2 バッファリングされた結果セットを操作する
<?php
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli("example.com", "user", "password", "database");
$mysqli->query("DROP TABLE IF EXISTS test");
$mysqli->query("CREATE TABLE test(id INT)");
$mysqli->query("INSERT INTO test(id) VALUES (1), (2), (3)");
$result = $mysqli->query("SELECT id FROM test ORDER BY id ASC");
echo "Reverse order...\n";
for ($row_no = $result->num_rows - 1; $row_no >= 0; $row_no--) {
$result->data_seek($row_no);
$row = $result->fetch_assoc();
echo " id = " . $row['id'] . "\n";
}
echo "Result set order...\n";
foreach ($result as $row) {
echo " id = " . $row['id'] . "\n";
}
上の例の出力は以下となります。
Reverse order... id = 3 id = 2 id = 1 Result set order... id = 1 id = 2 id = 3
結果セットをバッファリングしない場合
クライアント側のメモリが不足し、 かつサーバ側のリソースをできるだけ早く開放することで、 サーバの負荷を下げる必要がない場合、 結果セットのバッファリングを無効にできます。 結果セットをバッファリングしない場合、 全ての行を読み取るまで、 結果を操作することはできません。
例3 結果セットをバッファリングせず、結果を操作する
<?php
$mysqli->real_query("SELECT id FROM test ORDER BY id ASC");
$result = $mysqli->use_result();
echo "Result set order...\n";
foreach ($result as $row) {
echo " id = " . $row['id'] . "\n";
}
結果セットの値のデータ型
mysqli::query(),
mysqli::real_query(),
mysqli::multi_query()
関数は、準備されていないステートメントを実行するために使います。
MySQL のクライアントサーバプロトコルのレベルでは、
COM_QUERY
コマンドとテキストプロトコルをステートメントの実行に使います。
テキストプロトコルでは、
MySQL サーバは結果セットの全てのデータを、
送信する前に文字列に変換します。
この変換は、
SQL の結果セットの、
カラムのデータ型が何であっても行われます。
MySQL のクライアントライブラリは、
全てのカラムの値を文字列として受け取ります。
MySQL 側のネイティブなデータ側に戻すために、
それ以上のキャストがクライアント側で行われることはありません。
キャストするのではなく、
全ての値が PHP の文字列型として返されます。
例4 テキストプロトコルは、文字列を返すのがデフォルト
<?php
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli("example.com", "user", "password", "database");
$mysqli->query("DROP TABLE IF EXISTS test");
$mysqli->query("CREATE TABLE test(id INT, label CHAR(1))");
$mysqli->query("INSERT INTO test(id, label) VALUES (1, 'a')");
$result = $mysqli->query("SELECT id, label FROM test WHERE id = 1");
$row = $result->fetch_assoc();
printf("id = %s (%s)\n", $row['id'], gettype($row['id']));
printf("label = %s (%s)\n", $row['label'], gettype($row['label']));
上の例の出力は以下となります。
id = 1 (string) label = a (string)
mysqlnd ライブラリを使っている場合に、
MYSQLI_OPT_INT_AND_FLOAT_NATIVE
接続オプションを設定すると、
int や float 型のカラムの値を、
PHP の数値型に変換できます。
これを設定すると、mysqlnd ライブラリは、
結果セットのメタデータのカラム型を調べ、
PHP のデータ型の範囲が許可している場合に、
数値のSQLカラムの値を PHP の数値に変換します。
こうすることで、たとえば、
SQL の INT カラムを、数値として返すことができます。
例5 mysqlnd と接続オプションを設定することで、ネイティブのデータ型を扱う
<?php
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli();
$mysqli->options(MYSQLI_OPT_INT_AND_FLOAT_NATIVE, 1);
$mysqli->real_connect("example.com", "user", "password", "database");
$mysqli->query("DROP TABLE IF EXISTS test");
$mysqli->query("CREATE TABLE test(id INT, label CHAR(1))");
$mysqli->query("INSERT INTO test(id, label) VALUES (1, 'a')");
$result = $mysqli->query("SELECT id, label FROM test WHERE id = 1");
$row = $result->fetch_assoc();
printf("id = %s (%s)\n", $row['id'], gettype($row['id']));
printf("label = %s (%s)\n", $row['label'], gettype($row['label']));
上の例の出力は以下となります。
id = 1 (integer) label = a (string)
参照