PHP 7.2.0 Release Candidate 4 Released

Выполнение запросов

За выполнение запросов отвечают функции mysqli_query(), mysqli_real_query() и mysqli_multi_query(). Чаще всего применяется функция mysqli_query(), так как она выполняет сразу две задачи: выполняет запрос и буферизует на клиенте результат этого запроса (если он есть). Вызов mysqli_query() идентичен последовательному вызову функций mysqli_real_query() и mysqli_store_result().

Пример #1 Подключение к MySQL

<?php
$mysqli 
= new mysqli("example.com""user""password""database");
if (
$mysqli->connect_errno) {
    echo 
"Не удалось подключиться к MySQL: (" $mysqli->connect_errno ") " $mysqli->connect_error;
}

if (!
$mysqli->query("DROP TABLE IF EXISTS test") ||
    !
$mysqli->query("CREATE TABLE test(id INT)") ||
    !
$mysqli->query("INSERT INTO test(id) VALUES (1)")) {
    echo 
"Не удалось создать таблицу: (" $mysqli->errno ") " $mysqli->error;
}
?>

Буферизация результатов запроса

После выполнения запроса его результаты можно целиком буферизовать на клиенте, либо читать построчно с сервера. Буферизация на клиенте позволяет серверу как можно быстрее освобождать занятые запросом ресурсы. Построчное же чтение и дальнейшая обработка результатов клиентом довольно медленный процесс. Поэтому рекомендуется использовать буферизацию результирующих наборов. Функция mysqli_query() совмещает в себе операции выполнения запроса и буферизации результирующего набора.

PHP приложения могут свободно оперировать данными внутри буферизованных результирующих наборов. Быстрая навигация по строкам наборов обусловлена тем, что наборы полностью располагаются в памяти клиента. Следует помнить, что зачастую обработка результатов на клиенте проще, нежели средствами сервера.

Пример #2 Навигация по строкам буферизованной результирующей таблицы

<?php
$mysqli 
= new mysqli("example.com""user""password""database");
if (
$mysqli->connect_errno) {
    echo 
"Не удалось подключиться к MySQL: (" $mysqli->connect_errno ") " $mysqli->connect_error;
}

if (!
$mysqli->query("DROP TABLE IF EXISTS test") ||
    !
$mysqli->query("CREATE TABLE test(id INT)") ||
    !
$mysqli->query("INSERT INTO test(id) VALUES (1), (2), (3)")) {
    echo 
"Не удалось создать таблицу: (" $mysqli->errno ") " $mysqli->error;
}

$res $mysqli->query("SELECT id FROM test ORDER BY id ASC");

echo 
"Обратный порядок...\n";
for (
$row_no $res->num_rows 1$row_no >= 0$row_no--) {
    
$res->data_seek($row_no);
    
$row $res->fetch_assoc();
    echo 
" id = " $row['id'] . "\n";
}

echo 
"Исходный порядок строк...\n";
$res->data_seek(0);
while (
$row $res->fetch_assoc()) {
    echo 
" id = " $row['id'] . "\n";
}
?>

Результат выполнения данного примера:

Обратный порядок...
 id = 3
 id = 2
 id = 1
Исходный порядок строк...
 id = 1
 id = 2
 id = 3

Небуферизуемые результирующие наборы

Если клиентские ресурсы ограничены, и в тоже время не требуется поддерживать низкую нагрузку на сервер, можно использовать не буферизованные результирующие наборы. Навигация по таким таблицам невозможна, потому что так или иначе должны быть обработаны все строки набора.

Пример #3 Навигация по строкам не буферизованной результирующей таблицы

<?php
$mysqli
->real_query("SELECT id FROM test ORDER BY id ASC");
$res $mysqli->use_result();

echo 
"Порядок строк в результирующем наборе...\n";
while (
$row $res->fetch_assoc()) {
    echo 
" id = " $row['id'] . "\n";
}
?>

Типы данных значений в результирующей таблице

Функции mysqli_query(), mysqli_real_query() и mysqli_multi_query() предназначены для выполнения не подготавливаемых запросов. На уровне протокола клиент-серверного взаимодействия MySQL за выполнение запросов отвечают команда COM_QUERY и текстовый протокол. Когда используется текстовый протокол, сервер MySQL перед отправкой клиенту преобразует все данные в результирующем наборе в текстовые строки. Это преобразование выполняется вне зависимости от типа данных SQL столбца результирующей таблицы. Клиентские библиотеки mysql, в свою очередь, получают все данные, принимая их за строки. На клиенте не проводится никакого обратного преобразования к исходным типам, все данные, полученные приложением остаются PHP строками.

Пример #4 Текстовый протокол по умолчанию возвращает строки

<?php
$mysqli 
= new mysqli("example.com""user""password""database");
if (
$mysqli->connect_errno) {
    echo 
"Не удалось подключиться к MySQL: (" $mysqli->connect_errno ") " $mysqli->connect_error;
}

if (!
$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')")) {
    echo 
"Не удалось создать таблицу: (" $mysqli->errno ") " $mysqli->error;
}

$res $mysqli->query("SELECT id, label FROM test WHERE id = 1");
$row $res->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, можно включить преобразование целочисленных значений и чисел с плавающей запятой из столбцов таблицы в PHP числа. Делается это заданием настройки подключения MYSQLI_OPT_INT_AND_FLOAT_NATIVE. В таком случае mysqlnd будет проверять метаданные столбцов и преобразовывать SQL числа этих полей в PHP числа, если эти значения не выходят за рамки допустимых диапазонов типов данных PHP. То есть, например, SQL INT число попадет в PHP приложение в виде целого (integer).

Пример #5 Получение исходных типов данных в приложении

<?php
$mysqli 
mysqli_init();
$mysqli->options(MYSQLI_OPT_INT_AND_FLOAT_NATIVE1);
$mysqli->real_connect("example.com""user""password""database");

if (
$mysqli->connect_errno) {
    echo 
"Не удалось подключиться к MySQL: (" $mysqli->connect_errno ") " $mysqli->connect_error;
}

if (!
$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')")) {
    echo 
"Не удалось создать таблицу: (" $mysqli->errno ") " $mysqli->error;
}

$res $mysqli->query("SELECT id, label FROM test WHERE id = 1");
$row $res->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)

См. также

add a note add a note

User Contributed Notes 1 note

up
-40
developer at 4seasonsconsulting dot com
4 years ago
When accessing columns of type ENUM or SET, your results may not always come back as expected. Given:

SQL:
CREATE TABLE `items` (
  `item_key` char(4) NOT NULL DEFAULT 'xxxx',
  `item_id` smallint(5) unsigned NOT NULL,
  `item_media` enum('pdf','tape','cd','dvd','mp3','mp4')  NOT NULL DEFAULT 'mp3',
  `item_file` varchar(40) DEFAULT NULL,
  PRIMARY KEY (`item_key`,`item_id`,`item_media`)
) ENGINE=MyISAM;

INSERT INTO `items` (`item_key`, `item_id`, `item_media`) VALUES
('A1B2', 1, 'mp3'),
('A1B2', 2, 'mp4'),
('A1B2', 3, 'pdf'),
('A1B2', 4, 'dvd'),
('A1B2', 5, 'mp3');

<?php
...
$result = mysql_query("SELECT `item_id`, `item_media`+0 FROM `items`
WHERE `item_key`='A1B2' ORDER BY `item_media`"
;
while (
$row = mysql_fetch_array($result) )
echo
'id=' . $row[0] . ', media=' . $row[1] . "\r\n";
...
?>

When just the query is run in phpMyAdmin,
you most likely will get:

id=3, media=1
id=4, media=4
id=1, media=5
id=5, media=5
id=2, media=6

but php will give you:

id=1, media=0
id=2, media=0
id=3, media=0
id=4, media=0
id=5, media=0

This is because the translation of <enum or set>+0
is evaluated as a string (converted to zero)+0,

This does need further research for a fix.
To Top