PDO - расширение PHP для работы с базой данных
У любого современного сайта есть база данных и, если не использовать CMS или фраймверк, то понадобится универсальный интерфейс для доступа к этой базе. Желательно без привязки к конкретной СУБД и с возможностью ее смены с минимальными изменениями кода. Один из достойных вариантов - это PHP Data Objects (PDO).
PHP Data Objects (PDO) - это расширение PHP способное предоставить пользователю интерфейс для доступа к различным базам данных. Один из плюсов - высокая производительность, которая достигается за счет того, что при подключении к базе данных PDO использует их же драйвера. Стоит упомянуть, что на сегодняшний день список поддерживаемых СУБД не мал и все общеизвестные в нем присутствуют. Также PDO поддерживает работу сразу с несколькими базами данных одновременно.
Подключить PDO очень просто, правда есть небольшое различие для разных СУБД. Например:
// MуSQL
$pdo = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass);
// PostgreSQL
$pdo = new PDO("pgsql:host=$host;dbname=$dbname", $user, $pass);
// SQLite
$pdo = new PDO("sqlite:/path/database.db");
При неккоректных входных данных PDO отдаст исключение. При необходимости его можно перехватить с помощью конструкции try...catch. Также, при желании, можно настроить режим обработки ошибок. Делается это через метод $pdo->setAttribute():
// PDO::ERRMODE_SILENT: Возвращать код ошибки по принципу,
// как в расширениях mysql или mysqli (по умолчанию).
// PDO::ERRMODE_WARNING: Вызывать E_WARNING.
// PDO::ERRMODE_EXCEPTION: Выбрасывать исключения.
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
Выполнять запросы можно тремя способами. Зачем такое разнообразие? Это зависит от того, какой тип запроса нужно выполнить, нужен ли результат выполнения или подготовка к выполнению.
Например, для запросов, которые не возвращают никаких данных можно использовать функцию $pdo->exec(). При удачном выполнении вернет количество затронутых записей, при неудачном FALSE:
$pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8", $user, $pass);
$countRow = $pdo->exec('DELETE FROM products');
А вот если нужна выборка из базы, подойдет метод $pdo->query(). При удачном выполнении вернет PDOStatement, при неудачном FALSE:
$pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8", $user, $pass);
$sql = 'SELECT * FROM categories';
foreach ($pdo->query($sql) as $row)
{
echo $row['name'] . PHP_EOL;
}
Конечно можно и более индивидуально настроить запрос. Например:
$pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8", $user, $pass);
// Полученные записи будут в виде массива с объектами
if (false !== $query = $pdo->query('SELECT * FROM categories'))
{
$categories = $query->fetchAll(PDO::FETCH_OBJ);
foreach ($categories as $category)
{
echo $category->name . PHP_EOL;
}
}
// А здесь вернет строку из базы в виде объекта Product
class Product {
public $name;
}
if (false !== $query = $pdo->query('SELECT * FROM products WHERE id = 1'))
{
$product = $query->fetchObject(get_class(new Product));
if ($product instanceof Product)
echo $product->name . PHP_EOL;
}
И наконец, третий способ - подготовленный (или параметризованный) запрос. Вполне обоснованно может возникнуть вопрос: "Зачем же его подготавливать?". Ответ очень прост - для того, что бы его можно было выполнять многократно (например, поиск на сайте). Подготовка выполняется методом $pdo->prepare(), а выполнение - методом $pdo->execute().
При подготовке запроса сервер проверяет шаблон запроса, строит его план и выделяет для него ресурсы. При выполнении в шаблон подставляются реальные значения и выполняется отправка на сервер, который запускает уже готовый запрос (а не формирует его заново как с методом $pdo->query()). Пример:
$pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8", $user, $pass);
$stmt = $pdo->prepare('SELECT name FROM posts WHERE text LIKE :text');
$stmt->execute(array('text' => '%php%'));
foreach ($stmt->fetchAll() as $row)
{
echo $row['name'] . PHP_EOL;
}
В завершение опишу несколько полезных методов класса PDO.
Так как запросы в базу будем посылать не только мы, но и пользователи сайта (все тот же поиск по сайту), то мы просто обязаны защитить себя от sql инъекций. Для этого у PDO есть функция $pdo->quote(), которая экранирует специальные символы.
Если мы делаем запрос не методом $pdo->exec(), но при этом хотим узнать количество затронутых записей (например, после обновления характеристики товара, хотим узнать сколько товаров затронуло это обновление), то функция $pdo->rowCount() как раз то, что нам надо.
Если же нужно получить id последней добавленной записи, то нам поможет функция $pdo->lastInsertId().