В этом пособии по PHP вы узнаете о подготовленных запросах PDO и о том, как эффективно их использовать.

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

Подготовленный запрос — это шаблон для выполнения одного или нескольких SQL-запросов с различными значениями. Подготовленный оператор является высокоэффективным и помогает защитить приложение от SQL-инъекций.

Когда сервер базы данных выполняет запрос, он проходит два основных этапа: подготовка и выполнение.

Подготовка — сервер базы данных проверяет синтаксис SQL-запроса и инициализирует внутренние ресурсы сервера для этапа выполнения.

Выполнение — приложение связывает значения и отправляет SQL-запрос на сервер базы данных. Сервер базы данных выполняет запрос с привязанными значениями, используя внутренние ресурсы сервера, выделенные на этапе подготовки.

Создание подготовленного запроса в PDO

Чтобы создать подготовленный запрос в PDO, выполните действия, которые я опишу ниже.

1. Во-первых, создаем шаблонный SQL-запрос. Например:

$sql = 'INSERT INTO authors (first_name, last_name)
        VALUES (?, ?)';

В этом выражении INSERT есть два вопросительных знака (?). Они называются позиционными заполнителями.

При выполнении оператора необходимо передать значения в позиционные заполнители по их позициям. Другими словами, например, в первый заполнитель нужно передать имя, а во второй — фамилию.

2. Во-вторых, вызовите метод prepare() экземпляра PDO:

$statement = $pdo->prepare($sql);

Метод prepare() возвращает новый экземпляр класса PDOStatement.

3. В-третьих, вызовите метод execute() и передайте значения заполнителям:

$statement->execute(['Sandra', 'Aamodt']);

Метод execute() заменит первый заполнитель на ‘Sandra’, а второй — на ‘Aamodt’ в операторе вставки.

Соединим все вместе.

Ниже показано, как использовать подготовленный запрос для вставки новой строки в таблицу «авторов»:

<?php

$pdo = require 'connect.php';

$sql = 'insert into authors(first_name, last_name)
        values(?,?)';

$statement = $pdo->prepare($sql);

$statement->execute(['Sandra', 'Aamodt']);

Выше в коде мы использовали вставку файла с данными для соединения с Базой Данных, как в статье PDO: cоединение с Базой Данных.

Использование именованных заполнителей

Когда вы используете позиционные заполнители в операторе SQL, вам необходимо передать значения, соответствующие позициям заполнителей.

Если в SQL-операторе много заполнителей, очень легко использовать неправильные позиции. Чтобы избежать этого, можно использовать именованные заполнители. Например:

$sql = 'INSERT INTO authors (first_name, last_name)
        VALUES (:first_name,:last_name)';

В этом примере вместо вопросительных знаков (?) используется имя параметра, перед которым ставится двоеточие (:). Двоеточие требуется в операторе SQL.

При выполнении оператора необходимо передать ассоциативный массив в метод execute() следующим образом:

$statement->execute([
	'first_name' => 'Henry',
	'last_name' => 'Aaron'
]);

Обратите внимание, что важен ключ массива, а не порядок элементов. Также, можно использовать символ : в ключах массива по желанию:

$statement->execute([
	':first_name' => 'Henry',
	':last_name' => 'Aaron'
]);

Порядок элементов массива не важен, поэтому вы можете использовать массив с элементами в любом порядке. Например:

$statement->execute([
	'last_name' => 'Aaron',
	'first_name' => 'Henry',
]);

Соединим все вместе.

<?php

$pdo = require 'connect.php';

$sql = 'INSERT INTO authors (first_name, last_name)
        VALUES (:first_name,:last_name)';

$statement = $pdo->prepare($sql);

$statement->execute([
	'last_name' => 'Aaron',
	'first_name' => 'Henry',
]);

Связанные значения

В приведенных выше примерах мы передаем значения в метод execute() для выполнения запроса. Эти утверждения называются не связанными запросами.

Помимо несвязанных запросов, PDO также поддерживает связанные запросы. Связанные запросы позволяют явно связать значение или переменную с именованным или позиционным заполнителем.

Чтобы связать значение, используется метод bindValue() объекта PDOStatement:

public PDOStatement::bindValue ( mixed $parameter , mixed $value , int $data_type = PDO::PARAM_STR ) : bool

Метод bindValue() имеет три параметра:

  • $parameter задает имя параметра :parameter, если в запросе используются именованные заполнители, или индекс параметра, если в запросе используются позиционные заполнители. В случае использования позиционных заполнителей первый параметр начинается с индекса 1.
  • $value указывает значение, которое нужно привязать к запросу.
  • $data_type указывает тип данных для параметра, используя PDO::PARAM_*, например, PDO::PARAM_INT. По умолчанию $data_type — это PDO::PARAM_STR.

В следующем примере показано, как вставить автора Nick Abadzis в таблицу authors с помощью связанного запроса:

<?php

$pdo = require 'connect.php';

$sql = 'INSERT INTO authors (first_name, last_name)
        VALUES (?, ?)';

$statement = $pdo->prepare($sql);

$statement->bindValue(':first_name', 'Nick');
$statement->bindValue(':last_name', 'Abadzis');

$statement->execute();

Когда вы используете метод bindValue(), метод execute() выполняет запрос со значениями, переданными методу bindValue(), а не со значениями на момент выполнения метода execute(). Например:

<?php

$pdo = require 'connect.php';

$sql = 'INSERT INTO authors (first_name, last_name)
        VALUES (:first_name,:last_name)';

$statement = $pdo->prepare($sql);

$author = [
	'first_name' => 'Chris',
	'last_name' => 'Abani',
];

$statement->bindValue(':first_name', $author['first_name']);
$statement->bindValue(':last_name', $author['last_name']);

// изменение автора
$author['first_name'] = 'Tom';
$author['last_name'] = 'Abate';

// выполнение запроса со значением Chris Abani
$statement->execute();

В данном примере:

  1. Во-первых, привязываем значения ‘Chris’ и ‘Abate’ к параметрам имени и фамилии.
  2. Во-вторых, изменяем значения переменной $author.
  3. В-третьих, выполняем запрос. Однако метод execute() использует значения, переданные методу bindValue(), а не значение $author на момент выполнения метода execute().

Поэтому в дело вступает метод bindParam().

Метод bindParam()

Для выполнения запроса, значения параметров которого оцениваются во время выполнения метода execute(), используется метод bindParam():

public PDOStatement::bindParam ( mixed $parameter , mixed &$variable , int $data_type = PDO::PARAM_STR , int $length = ? , mixed $driver_options = ? ) : bool

Следующий пример иллюстрирует использование метода bindParam() для вставки нового автора в таблицу authors:

<?php

$pdo = require 'connect.php';

$sql = 'insert into authors(first_name, last_name)
        values(:first_name,:last_name)';

$statement = $pdo->prepare($sql);

$author = [
	'first_name' => 'Chris',
	'last_name' => 'Abani',
];

$statement->bindParam(':first_name', $author['first_name']);
$statement->bindParam(':last_name', $author['last_name']);

// изменение переменной автора
$author['first_name'] = 'Tom';
$author['last_name'] = 'Abate';

// выполняем запрос со значением Tom Abate
$statement->execute();

В этом примере метод execute() оценивает переменную $author во время выполнения, поэтому вместо нее используются значения ‘Tom’ и ‘Abage’.

Заключение

Используйте подготовленный запрос PHP для многократного выполнения запроса с разными значениями.

Используйте позиционные заполнители (?) или именованные заполнители (:parameter) в SQL-запросе, прежде чем передать его в метод prepare() объекта PDOStatement.

Используйте метод execute() со значениями для запуска несвязанного запроса.

Используйте метод bindValue() или bindParam() для привязки значений к связанному запросу.

Статьи # #