LXF73:PHP

Материал из Linuxformat.

Перейти к: навигация, поиск
PHP (Пол Хадсон)

Содержание

PHP объекты данных в версии 5.1

Все приходит в своё время для тех, кто умеет ждать. Да, обновление PHP наконец-то произошло! Пол Хадсон (Paul Hudson) покажет нам его.

Давным-давно, в журнале, который скорее всего уже собирает пыль где-то на полках, я обещал вам рассказать про PHP 5.1. большая задержка связана с конкурсом Sudoku - мы провели несколько уроков за решением задач, подозрительно похожих на конкурсную. Мне хотелось дать вам преимущество по сравнению с теми сумасшедшими, кто не читает этот учебник. Так что я писал на тему конкурса вплоть до самого последнего его дня.

Как бы то ни было, у меня хорошие новости — в этой статье мы рассмотрим PHP 5.1, последний релиз PHP 5.x. Это первое крупное изменение версии PHP5, несмотря на то, что сам он вышел аж 15 лет назад. Но подождать действительно стоило. Мы получили новые функции, новую скорость и новые расширения, из которых, по моему мнению, самым важным стал PDO — ещё одна трёхбуквенная аббревиатура, обозначающая объекты данных в PHP (PHP Data Objects).

ещё быстрее, чем PHP 5.0

разработчиками PHP была проделана большая работа по повышению скорости работы PHP 5.1 на самом низком уровне. Помимо ускорения обычной компиляции и выполнения, были доработаны такие серьёзные вещи как оператор switch(), выборка переменных и «магический» вызов метода. Функция scandir() теперь работает в десять раз быстрее, функции работы с массивами были серьёзно переработаны для повышения производительности, а realpath() теперь имеет кэш результатов своей работы, чтобы избежать постоянного повторения поиска одного и того же виртуального пути. Так что PHP 5.1 работает быстро, быстрее и ещё быстрее, и вам даже не нужно переписывать свои сценарии, чтобы воспользоваться этим — всё ускорится само собой, как только вы перейдёте на новую версию.

кроме чистой производительности, вы теперь можете заполучить несколько новых функций: array_product() подсчитывает произведение всех элементов массива, array_diff() и array_intersect() теперь имеют аналоги для работы с ключами, для htmlspecialchars() теперь есть функция обратного преобразования под названием htmlspecialchars_decode(), и появилась новая потрясающая функция time_sleep_until(), которая прекращает выполнение сценария до тех пор, пока не наступит определённый момент времени. У некоторых функций добавились новые параметры… Но оставим пока этот вопрос: вы же хотите узнать, что такое PDO и почему вы должны им заинтересоваться. Итак…

что такое Pdo и как с ним бороться

Pear::DB и PDO могут счастливо жить вместе: один преобразует ваш SQL, а другой сводит множество расширений в один набор классов и методов.
Pear::DB и PDO могут счастливо жить вместе: один преобразует ваш SQL, а другой сводит множество расширений в один набор классов и методов.

давным-давно, в LXF48, мы рассматривали, как использовать пакет Pear::DB, чтобы создавать независимые от типа сервера баз данных PHP-сценарии. Pear::DB добивался этой цели очень простым способом — заставляя вас писать чистый SQL код и абстрагируясь от вызовов функций для работы с конкретной базой данных, так что вы могли поменять сервер с минимальными усилиями. его слабым местом была скорость — Pear::DB сам написан на PHP, и вынужден рассматривать много условий, чтобы вызвать нужную функцию. PDO разработан для того, чтобы забрать у Pear::DB половину работы — часть, связанную с запросом множества разных баз данных внутри одной функции — и переместить её в ядро PHP как написанное на C расширение. Это гораздо быстрее, и Pear::DB можно по-прежнему использовать для обработки SQL-кода.

Немного запутались? Попробую объяснить. В PHP 5.0, если вы хотели писать SQL так, чтобы он работал с любым сервером баз данных, вы использовали Pear::DB. Pear::DB обрабатывал подключение к различным серверам следующим образом: он предоставлял функцию вроде query() и заменял её на mysql_query(), pgsql_query() и так далее в зависимости от типа сервера. Это работало очень медленно, и именно эту часть PDO взяли на себя. Вместо обработке в query() различных условий и вызова правильной функции для этой базы данных, PDO вызывает её сразу же. Появление PDO не означает конец для Pear::DB, ему ещё предстоит долгая жизнь. Но для тех из нас, кто просто хотел иметь хороший способ переключаться между расширениями mysql и mysqli, PDO — это лучшее решение.

Нет смысла говорить про PDO, если не попытаться использовать его на практике, вот мы и попытаемся. Наш первый скрипт будет выполнять соединение с сервером MySQL под именем пользователя lxf и с паролем r0xx0r5, открывать базу данных flich и сохранять соединение для дальнейшего использования.

$db = new PDO(mysql:dbname=filch;host=127.0.0.1”, “lxf”, “r0xx0r5”);

если вы ожидали около пяти строк кода, то я извиняюсь, что разочаровал вас. Это всё, что нужно сделать, чтобы подключиться и приготовиться к выполнению запросов. если вы привыкли вызывать mysql_connect() и mysql_select_db(), то вы заметите, что тут их параметры были объединены в единый «источник данных» (DSN) в стиле Pear::DB. PDO DSN состоит из нескольких пар параметр=значение, перед которыми стоит тип сервера подключаемой базы данных. В этом примере тип сервера — mysql, filch — имя нужной базы данных (параметр dbname), 127.0.0.1 — IP адрес сервера (параметр host), lxf - имя пользователя, а r0xx0r5 — пароль.

Вам потребуется установленный PDO-драйвер сервера базы данных, с которой вы хотите работать. В этом примере мы используем драйвер mysql, то есть нам нужно, чтобы PHP был собран с указанием ключа --with-pdo-mysql. расширение PDO компилируется по умолчанию, так что всё, что вам надо — это указать базы данных, к которым вам потребуется доступ. кроме MySQL, существуют драйвера для PostgreSQL (--with-pdo-pgsql), Oracle (--with-pdo-oci), и так далее.

быстрые запросы

Подсказки
  • Вы можете использовать в качестве DSN путь к файлу в форме file://path/to/your/file. Внутри этого файла должна содержаться обычная строка с описанием источника данных.
  • Вместо PDO_FETCH_LAZY вы можете использовать PDO_FETCH_ASSOC, чтобы сымитировать работу функции mysql_fetch_assoc().
  • если вы предпочитаете отдельно выполнять запрос и проходить циклом по полученным данным в другом месте сценария, используйте метод fetch() объекта, который возвращается из функции $db->query().
  • если в Unreal Tournament нажать «Вперёд» четыре раза, ваш адреналин придаст вам дополнительную скорость. бу-га-га-га!

конечно, наш первый сценарий очень прост, и неудивительно, что его можно записать в одну строчку. давайте сделаем что-нибудь посложнее и напишем запрос к базе данных. для этого теста мы создадим простенькую табличку ut_results, в которой будем хранить информацию о победителях в матчах Unreal Tournament. Чтобы запросить эту таблицу из PHP, нам потребуется следующий код:

foreach($db->query(“SELECT Winner from ut_results;”) as $row)
echo $row[“Winner”], “\n”;

да, только две строчки! если вы провели много дней за написанием циклов обработки mysql_query() и mysql_fetch_assoc(), простите, но PDO использовать гораздо проще. Прелесть этого сценария в том, что он сочетает запрос с извлечением полученных данных в одной строчке. Вы можете подумать, что этот скрипт выполняет $db->query() множество раз, но это не так. если хотите убедиться, запустите монитор состояния MySQL и выполните команду status, что-бы увидеть число запросов.

Вы можете сделать запрос к базе данных ещё проще, включив так называемый «ленивый» режим работы. Тогда вместо считывания каждой строки в виде массива полей вы получите её как объект, у которого можно прочитать значения полей как значения его параметров. для этого нужно всего лишь передать параметр PDO_FETCh_LAZY в функцию $db->query(), примерно так:

foreach($db->query(“SELECT Winner from ut_results;”, PDO_FETCH_LAZY) as $row)
echo $row->Winner, “\n”;

если ваш сервер баз данных поддерживает транзакции, вы можете работать с ними из PHP. Вам потребуется MySQL 4.1, PostgreSQL, Oracle или другая транзакционная база данных, в противном случае команды работы с транзакциями будут просто игнорироваться. для начала выполните метод beginTransaction() объекта базы данных, а затем выполняйте все запросы, какие хотите, в рамках одной транзакции. если вы не изменяли структуру таблиц, добавляя или удаляя столбцы (некоторые сервера сбрасывают транзакцию в такой ситуации), всё будет прекрасно. В конце вам останется вызвать commit() или rollBack() в зависимости от того, как всё прошло.

Вот пример:

<?php
$db = new PDO(mysql:dbname=filch;host=127.0.0.1”, “lxf”,“r0xx0r5”);
$db->beginTransaction();
$db->query(“INSERT INTO great_bands (Name) VALUES (‘Marillion’);
// Ой! Мы просто не может позволить записать *это* в таблицу...
$db->rollBack();
?>

обработка ошибок

Последняя вещь, о которой я хочу поговорить — это обработка ошибок. PDO, будучи современным расширением PHP, может использовать исключения PHP для обработки ошибок, вместо того, чтобы просто возвращать необычные значения. По умолчанию используется смесь из двух методов — серьёзные ошибки («Неправильный пароль») вызывают исключения, а менее важные («этот запрос не работает») просто возвращают false в качестве значения функции. Я не знаю, что предпочитаете вы, а мне больше нравится, когда расширение пользуется исключениями везде. Я хочу, чтобы любая ошибка вызывала исключение, чёрт побери! к счастью, PDO можно настроить на использование исключений при любых ошибках с помощью функции setAttribute(). Посмотрите код:

<?php
try {
$db = new PDO(mysql:dbname=filch;host=127.0.0.1”, “lxf”, “r0xx0r5”);
$db->setAttribute( PDO_ATTR_ERRMODE, PDO_ERRMODE_EXCEPTION
);
try {
$result = $db->query(“SELECT Winner from ut_sresults;”,PDO_FETCH_LAZY);
foreach($result as $row) {
echo $row->Winner, “\n”;
}
} catch (PDOException $ex) {
echo “Query failed: {$ex->getMessage()}\n”;
}
} catch (PDOException $ex) {
echo “Couldn’t connect: {$ex->getMessage()}\n”;
}
?>

При помощи try/catch мы можем обработать два различных типа исключений одного и того же класса PDOException: внешний обработчик занимается ошибками при подключении к базе, а внутренний обрабатывает ошибки выполнения запроса. Проще простого!

Личные инструменты
  • Купить электронную версию
  • Подписаться на бумажную версию