Как в pdo загрузить данные бд. Как настроить и использовать PDO (PHP Data Objects) для доступа к базе

Я думаю настало время повысить свой экспириенс, и перейти при работе с базой данных с mysql_ функций на PDO. Эта библиотека является мощным и быстрым дополнением к PHP. Одно из ее преимуществ – работа со многими базами данных (MS SQL , MySQL , PostgreSQL , Oracle и др.). Также отличительной характеристикой этой библиотеки являются подготовленные выражения, так называемые prepared statements, которые должны ускорить работу с базой, а главное сделать обмен данным безопасными и забыть о таких уязвимостях как sql-enjection. Кроме того, есть и другие очень полезные возможности. В этой статье я попытался собрать часто используемые примеры работ, по которым можно сразу понять суть работы PDO.

В PHP существуют три расширения для работы с базой MySQL: mysql, mysqli и PDO. PHP PDO (PHP Data Objects) включено в PHP 5.1 и выше. Как я понял, на сегодняшний момент, функции для работы с базой данных mysql_ не рекомендуют к использованию, так как разработка php_mysql остановилась на поддержке функционала MySQL 4.1.3. и также не поддерживает транзакции, объектный интерфейс и подвержено уязвимостям при подстановке значений в запрос. После mysql_ появилось расширение mysqli (MySQL Improved в 5 версии), которое поддерживает новые возможности MySQL и использует как ОПП синтаксис так и процедурное программирование. Все эти библиотеки используют стандартную клиентскую библиотеку MySQL (libmysql). В этой же заметке давайте на живых примерах посмотрим как осуществляется работа с mysql, при помощи самого свежего расширения – PDO .

PDO Соединение с БД

//пример соединения с MySQL при помощи PDO $db = new PDO("mysql:host=localhost;dbname=test", $user, $pass);

Как только будет установлено успешное соединение с конкретным сервером базы данных, то будет возвращен объект PDO. Этот объект позволяет выполнять самые разнообразные задачи баз данных.

Если есть какие-либо ошибки подключения, то сработает механизм исключений – PDOException. Нужно всегда оборачивать операции PDO в блок try/catch. Вы можете поймать исключение, если вы хотите обрабатывать ошибки, или вы можете оставить его для глобального обработчика исключений (exception), которые вы создали с помощью set_exception_handler (). В PDO есть специальные функции для ошибок: errorCode() – вернет номер ошибки, errorInfo() – вернет массив с номером ошибки и описанием. Они нужны так как по умолчанию режим работы с ошибками стоит ERRMODE_SILENT. В этом случае чтобы увидеть эти ошибки придется их вызвать:

Echo $conn->errorCode(); echo $conn->errorInfo();

Чтобы этого не делать, в режиме разработке проще сразу выставить нужный режим работы с ошибками: ATTR_ERRMODE и ERRMODE_EXCEPTION. Можно также прописать кодировку работы с базой. В итоге у нас получится такой вот код подключения:

Try { $db = new PDO("mysql:host=$host;dbname=$dbname", $user, $password); $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $db->exec("set names utf8"); } catch(PDOException $e) { echo $e->getMessage(); }

После успешного подключения к базе данных, экземпляр класса PDO возвращается в сценарий. $db содержит дескриптор базы данных. Соединение остается активным в течение всей жизни объекта PDO. Чтобы закрыть соединение, вам нужно уничтожить объект с гарантией, что все остальные ссылки на него будут удалены. Сделать это можно путем присвоения переменной, которая содержит объект, значения NULL. Если вы не сделаете этого явно, PHP будет автоматически закрывать соединение после завершения работы скрипта.

//Закрытие соединения $db = null;

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

//Постоянное соединение $dbh = new PDO("mysql:host=localhost;dbname=test", $user, $pass, array(PDO::ATTR_PERSISTENT => true));

Теперь, когда вы увидели, как открывать и закрывать соединение, давайте рассмотрим другие примеры работы с PDO. В данном случае я собираюсь показать вам, как выполнять запросы к конкретной базе данных. Запросы можно делать 3 функциями: exec(), query() и prepare+execute.

Exec()

Первый – exec вернет только кол-во задействованных строк или FALSE при ошибке и используется там, где не возвращаются данные, например при удалении:

//использование метода exec() try{ $db = new PDO("mysql:host=localhost;dbname=test","user","password"); $delrows=$db->exec("DELETE FROM users WHERE id>20"); echo "Количество удаленных строк: ".$delrows; } catch(PDOException $e){ echo "Error: ".$e->getMessage(); exit(); } //Еще $db->exec("DELETE FROM folks WHERE 1"); //или $db->exec("SET time_zone = "-8:00""); //или $db->exec("CREATE TABLE `test`(id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(20) NOT NULL DEFAULT "", email VARCHAR(50) NOT NULL DEFAULT "")"); //или $db->exec("SET CHARACTER SET utf8");

Query()

Второй – query() вернет результат в объекте PDOStatement. Также возвращает результат или FALSE при ошибке. Ему можно доверить простые запросы. Можно использовать query() с условием (я правда не знаю зачем кому то это может понадобиться), но тогда все равно придется экранировать данные методом PDO::quote

//Простые запросы $db->query("SET CHARACTER SET utf8"); $db->query("SELECT * FROM users"); //Можно вычислить количество строк $stmt = $db->query("SELECT * FROM table"); $row_count = $stmt->rowCount(); echo $row_count." rows selected"; //Еще вариант с количеством $stmt = $db->query("SELECT * from users"); $rows = $stmt->fetchAll(); $count = count($rows); foreach($rows as $row) { print_r($row); } //Запрос с условием и экранированием $conn->query("SELECT * FROM table WHERE id = " . $conn->quote($id));

lastInsertId() возвращает идентификатор последней вставленной строки базы данных.

//метод lastInsertId() возвращает id последней записи $db->query("INSERT INTO users SET name="Vasya",address="Here",email="[email protected]""); $insertId=$db->lastInsertId();

Подготовленные выражения – prepared statments.

Третий способ - prepare+execute - Подготовленные выражения , они же подготовленные инструкции они же плейсхолдеры они же prepared statments или связываемые переменные, позволяют определить выражение один раз, а затем многократно его выполнять с разными параметрами. Также они позволяют отделить переменные от запроса, что делает код безопаснее и повышает скорость выполнения. В вашем коде больше не надо будет пытаться очистить передаваемые данные. Мы сделаем это только один раз перед выполнением запроса к БД. Для этого используем функцию Prepare() ; В качестве параметра она принимает SQL запрос, но в нем, вместо переменных используются метки, в виде знака вопроса ‘?’ или номеров ‘:1′, или переменой, имя которой начинается с двоеточия ‘:’. Если вы остановились на знаках вопроса (:цифрах), то вам надо в функцию execute передать массив значений, в соответствующей последовательности. Если ваш выбор именованные переменные, то надо назначить каждой переменной значение через одну из двух функций: либо bindValue(), которая присваивает псевдо-переменной значение, либо bindParam(), которая связывает псевдо-переменную с настоящей переменной. Третьим параметром можно указать тип переменной, например $db->bindParam(‘:id’,$id, PDO::PARAM_INT).

//Не именованные метки try { $stmt = $db->prepare("INSERT INTO test (label,color) VALUES (?,?)"); $stmt -> execute(array("perfect","green")); } catch(PDOException $e){ echo "Error: ".$e->getMessage(); exit(); } //stmt - это "дескриптор состояния" //Именованные метки $stmt = $db->prepare("INSERT INTO test (label,color) VALUES (:label,:color)"); $stmt -> execute(array("label"=>"perfect", "color"=>"green")); //Еще вариант $stmt = $db->prepare("INSERT INTO users (firstname, lastname, email) VALUES (:firstname, :lastname, :email)"); $stmt->bindParam(":firstname", $firstname); $stmt->bindParam(":lastname", $lastname); $stmt->bindParam(":email", $email); $firstname = "John"; $lastname = "Smith"; $email = "[email protected]"; $stmt->execute();

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

PDO SELECT данных

Для выборки данных используются методы fetch() или fetchAll(). Перед вызовом функции нужно указать PDO как Вы будете доставать данные из базы. PDO::FETCH_ASSOC вернет строки в виде ассоциативного массива с именами полей в качестве ключей. PDO::FETCH_NUM вернет строки в виде числового массива. По умолчанию выборка происходит с PDO::FETCH_BOTH, который дублирует данные как с численными так и с ассоциативными ключами, поэтому рекомендуется указать один способ, чтобы не иметь дублирующих массивов:

$stmt = $db->query("SELECT * from users"); //Установка fetch mode $stmt->setFetchMode(PDO::FETCH_ASSOC); while($row = $stmt->fetch()) { echo "

" . $row["firstname"] . " " . $row["lastname"] . "

"; echo "

" . $row["email"] . "


"; }

Либо можно указать метод выборки в самом методе ->fetch()

$stmt = $db->query("SELECT * FROM table"); while($row = $stmt->fetch(PDO::FETCH_ASSOC)) { echo $row["field1"]." ".$row["field2"]; //и т.д... } //Внимание, не работающий пример с LIKE! $stmt = $db->prepare("SELECT field FROM table WHERE field LIKE %?%"); $stmt->bindParam(1, $search, PDO::PARAM_STR); $stmt->execute(); //Нужно так: $stmt = $db->prepare("SELECT field FROM table WHERE field LIKE ?"); $stmt->bindValue(1, "%$search%", PDO::PARAM_STR); $stmt->execute(); //Еще пример $stmt = $db->prepare("SELECT * FROM table WHERE id=? AND name=?"); $stmt->bindValue(1, $id, PDO::PARAM_INT); $stmt->bindValue(2, $name, PDO::PARAM_STR); $stmt->execute(); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); //Еще вариант $stmt = $db->prepare("SELECT * from users"); $stmt -> execute(); while($row = $stmt->fetch()) { print_r($row); }

PDO UPDATE данных

Происходит по существу также как и INSERT и SELECT (в данном случае опять же будем использовать именованные метки (placeholders)):

$stmt = $db->prepare("UPDATE users set email = :email where lastname=:lastname"); $stmt->bindParam(":lastname", $lastname); $stmt->bindParam(":email", $email); $lastname = "Smith"; $email = "[email protected]"; $stmt->execute();

DELETE Удаление происходит простейшим образом:

$db->exec("DELETE FROM users");

Конечно вы можете также использовать именованные параметры (placeholders) при удалении.

Если у вас есть свои часто используемые заготовки при работе с расширением PHP PDO, буду признателен если вы ими поделитесь. Ссылка на мануал

Если у вас возникла ошибка Undefined variable: DBH … то можете почитать как это исправить.

Google помог найти шпаргалку по PDO, может кому пригодится:

мета теги (5)

Время от времени я вижу вопросы о подключении к базе данных.
Большинство ответов - это не то, как я это делаю, или я просто не могу правильно ответить. Так или иначе; Я никогда не думал об этом, потому что способ, которым я это делаю, работает для меня.

Но вот сумасшедшая мысль; Возможно, я делаю все это неправильно, и если это так; Мне бы очень хотелось знать, как правильно подключиться к базе данных MySQL с помощью PHP и PDO и сделать ее доступной.

Вот как я это делаю:

Во-первых, вот моя файловая структура (урезанная) :

Public_html/ * index.php * initialize/ -- load.initialize.php -- configure.php -- sessions.php

index.php
На самом верху я require("initialize/load.initialize.php"); ,

load.initialize.php

# site configurations require("configure.php"); # connect to database require("root/somewhere/connect.php"); // this file is placed outside of public_html for better security. # include classes foreach (glob("assets/classes/*.class.php") as $class_filename){ include($class_filename); } # include functions foreach (glob("assets/functions/*.func.php") as $func_filename){ include($func_filename); } # handle sessions require("sessions.php");

Я знаю, что есть лучший, или более правильный способ включения классов, но не помню, что это было. Не получили времени, чтобы изучить его еще, но я думаю, что это было что-то с autoload . что-то вроде того...

configure.php
Здесь я в основном просто переопределяю некоторые php.ini -properties и выполняю некоторые другие глобальные настройки для сайта

connect.php
Я установил соединение в класс, чтобы другие классы могли расширять этот...

Class connect_pdo { protected $dbh; public function __construct() { try { $db_host = " "; // hostname $db_name = " "; // databasename $db_user = " "; // username $user_pw = " "; // password $con = new PDO("mysql:host=".$db_host."; dbname=".$db_name, $db_user, $user_pw); $con->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $con->exec("SET CHARACTER SET utf8"); // return all sql requests as UTF-8 } catch (PDOException $err) { echo "harmless error message if the connection fails"; $err->getMessage() . "
"; file_put_contents("PDOErrors.txt",$err, FILE_APPEND); // write some details to an error-log outside public_html die(); // terminate connection } } public function dbh() { return $this->dbh; } } # put database handler into a var for easier access $con = new connect_pdo(); $con = $con->dbh(); //

Здесь я действительно верю, что есть место для массового улучшения, так как я недавно начал изучать ООП и использовал PDO вместо mysql.
Поэтому я только что последовал за несколькими учебниками для начинающих и опробовал разные вещи...

sessions.php
Помимо обработки обычных сеансов, я также инициализирую некоторые классы в сеансе следующим образом:

If (!isset($_SESSION["sqlQuery"])){ session_start(); $_SESSION["sqlQuery"] = new sqlQuery(); }

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

Echo $_SESSION["sqlQuery"]->getAreaName("county",9); // outputs: Aust-Agder (the county name with that id in the database)

Внутри моего класса sqlQuery , который extends мой класс connect_pdo , у меня есть открытая функция getAreaName которая обрабатывает запрос в моей базе данных.
Думаю, довольно аккуратный.

Работает как шарм
Так вот в основном, как я это делаю.
Кроме того, всякий раз, когда мне нужно что-то извлекать из моего БД из класса, я просто делаю что-то похожее на это:

$id = 123; $sql = "SELECT whatever FROM MyTable WHERE id = :id"; $qry = $con->prepare($sql); $qry -> bindParam(":id", $id, PDO::PARAM_INT); $qry -> execute(); $get = $qry->fetch(PDO::FETCH_ASSOC);

Поскольку я вставляю соединение в переменную внутри connect_pdo.php , я просто ссылаюсь на нее, и мне хорошо идти. Оно работает. Я получаю ожидаемые результаты...

Но независимо от этого; Я был бы очень признателен, если бы вы, ребята, могли сказать мне, если я уйду отсюда. Вместо этого я должен был бы изменить области, которые я мог или должен изменить для улучшения и т. Д. ...

Я очень хочу учиться...

Answers

$dsn = "mysql:host=your_host_name;dbname=your_db_name_here"; // define host name and database name $username = "you"; // define the username $pwd="your_password"; // password try { $db = new PDO($dsn, $username, $pwd); } catch (PDOException $e) { $error_message = $e->getMessage(); echo "this is displayed because an error was found"; exit(); }

Недавно я пришел к аналогичному ответу / вопросу самостоятельно. Это то, что я сделал, в случае, если кто-то заинтересован:

args = func_get_args(); } public function __call($method, $args) { if (empty($this->db)) { $Ref = new \ReflectionClass("\PDO"); $this->db = $Ref->newInstanceArgs($this->args); } return call_user_func_array(array($this->db, $method), $args); } }

Для его вызова вам нужно только изменить эту строку:

$DB = new \Library\PDO(/* normal arguments */);

И тип-намек, если вы используете его (\ Library \ PDO $ DB).

Это действительно похоже на принятый ответ и ваш; однако он имеет значительное преимущество. Рассмотрим этот код:

$DB = new \Library\PDO(/* args */); $STH = $DB->prepare("SELECT * FROM users WHERE user = ?"); $STH->execute(array(25)); $User = $STH->fetch();

Хотя он может выглядеть как обычный PDO (он изменяется только этим \Library\ only), он фактически не инициализирует объект, пока вы не вызовете первый метод, в зависимости от того, что это такое. Это делает его более оптимизированным, поскольку создание объекта PDO немного дорого. Это прозрачный класс, или то, что он называется Ghost , форма . Вы можете обрабатывать $ DB как обычный экземпляр PDO, передавать его, выполнять те же операции и т. Д.

Я бы предложил не использовать $_SESSION для доступа к вашему соединению с БД глобально.

Вы можете сделать одну из нескольких вещей (в порядке худших для лучших практик):

  • Доступ к $dbh с использованием global $dbh внутри ваших функций и классов
  • Используйте одноэлементный реестр и доступ к нему глобально, например:

    $registry = MyRegistry::getInstance(); $dbh = $registry->getDbh();

    Внесите обработчик базы данных в нужные ему классы:

    Class MyClass { public function __construct($dbh) { /* ... */ } }

Однако он немного более продвинутый и требует больше «проводки» без рамки. Таким образом, если инъекция зависимостей слишком сложна для вас, используйте реестр singleton вместо совокупности глобальных переменных.

Цель

Как я вижу, ваша цель в этом случае двоякая:

  • создавать и поддерживать одно / многоразовое соединение для каждой базы данных
  • убедитесь, что соединение настроено правильно

Решение

$provider = function() { $instance = new PDO("mysql:......;charset=utf8", "username", "password"); $instance->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $instance->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); return $instance; }; $factory = new StructureFactory($provider);

Затем в другом файле или ниже в том же файле:

$something = $factory->create("Something"); $foobar = $factory->create("Foobar");

Сама фабрика должна выглядеть примерно так:

Class StructureFactory { protected $provider = null; protected $connection = null; public function __construct(callable $provider) { $this->provider = $provider; } public function create($name) { if ($this->connection === null) { $this->connection = call_user_func($this->provider); } return new $name($this->connection); } }

Таким образом, вы можете иметь централизованную структуру, которая гарантирует, что соединение создается только тогда, когда это необходимо. Это также облегчило бы процесс модульного тестирования и обслуживания.PHP , и этот код добавить обратные слэши следующие символы: \x00 , \n , \r , \ , " , " и \x1a . Передайте входные значения в качестве параметров, чтобы свести к минимуму вероятность внедрения SQL.

  • Самый продвинутый способ - использование PDO.
  • Я надеюсь, что это поможет вам.

    Рассмотрим следующий запрос:

    $iId = mysql_real_escape_string("1 OR 1=1"); $sSql = "SELECT * FROM table WHERE id = $iId";

    mysql_real_escape_string () не будет защищать здесь. Если вы используете одиночные кавычки ("") вокруг ваших переменных внутри вашего запроса, это то, что защищает вас от этого. Ниже приведено ниже решение:

    $iId = (int) mysql_real_escape_string("1 OR 1=1"); $sSql = "SELECT * FROM table WHERE id = $iId";

    На этот question есть хорошие ответы.

    Я предлагаю, что использование PDO - лучший вариант.

    Редактировать:

    mysql_real_escape_string() устарел от PHP 5.5.0. Используйте либо mysqli, либо PDO.

    Альтернативой mysql_real_escape_string () является

    String mysqli_real_escape_string (mysqli $link , string $escapestr)

    Пример:

    $iId = $mysqli->real_escape_string("1 OR 1=1"); $mysqli->query("SELECT * FROM table WHERE id = $iId");

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

    Наверняка, многие уже слышали аббревиатуру PDO , но мало кто знает, что же это. Вот давайте сегодня об этом и поговорим.

    Что такое PDO?

    PDO(PHP Data Objects) - это просто интерфейс , позволяющий нам абстрагироваться от конкретной базы данных. Лучше всего показать на примере.

    Mysql_connect($host, $user, $pass); // MySQL
    mysql_select_db($db);

    Sqlite_open($db); // sqlite

    Pg_connect("host=$host, dbname=$db, user=$user, password=$pass"); // PostgreSQL

    В коде выше представлены способы для подключения к трём разным базам данных: MySQL , sqlite и PostgreSQL . Как видите, функции у каждой БД отличаются.

    То же самое с другими действиями. Например, выборка данных из БД.

    $sql = "INSERT INTO(name, pass) VALUES($name, $pass)";

    Mysql_query($sql); // MySQL
    sqlite_query($sql); // sqlite
    pg_query($sql); // PostgreSQL

    Зачем нужен PDO?

    Представим, что у нас есть огромная база данных PostgreSQL , и мы решили сменить её на MySQL . Нам придётся переписывать очень много кода, и, скорее всего, без ошибок не обойдётся. Чтобы решить эту проблему и существует PDO , позволяющий нам не зависеть от конкретной базы.

    Давайте рассмотрим, как мы теперь можем подключиться.

    $db = new PDO("mysql:host=$host;dbname=$db", $user, $pass); // MySQL
    $db = new PDO("sqlite:host=$host;dbname=$db", $user, $pass); // sqlite
    $db = new PDO("pgsql:host=$host;dbname=$db", $user, $pass); // PostgreSQL

    Как видно из кода выше, в этих трёх подключениях меняется только строчка с названием БД, а остальное всё то же самое.

    Чтобы что-нибудь выбрать, мы можем написать так:

    $db->exec($sql);

    Всё! Запрос выполнится независимо от того, какая у нас база данных.

    Поддержка

    PDO доступен с PHP 5.1 . Чтобы мы могли "забыть", какую базу данных мы используем, за нас всё делают их драйверы . Чтобы их активировать, зайдите в файл php.ini и найдите там строчки, которые начинаются на extension=php_pdo_ , а затем идёт название базы данных, и раскоментируйте их.

    На этом всё для вступительной статьи, а в следующей мы уже начнём разбираться, как использовать PDO .












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

    Пример правильного соединения:

    $host = "127.0.0.1" ;
    $db = "test" ;
    $user = "root" ;
    $pass = "" ;
    $charset = "utf8" ;

    $dsn = "mysql:host= $host ;dbname= $db ;charset= $charset " ;
    $opt = [
    PDO :: ATTR_ERRMODE => PDO :: ERRMODE_EXCEPTION ,
    PDO :: ATTR_DEFAULT_FETCH_MODE => PDO :: FETCH_ASSOC ,
    PDO :: ATTR_EMULATE_PREPARES => false ,
    ];
    $pdo = new PDO ($dsn , $user , $pass , $opt );

    Что здесь происходит?

    В $dsn задается тип БД, с которым будем работать (mysql), хост, имя базы данных и чарсет.
    - затем идут имя пользователя и пароль
    - после которого задается массив опций, про который ни в одном из руководств не пишут.

    При том что этот массив - чрезвычайно полезная, как уже говорилось выше, штука. Самое главное - режим выдачи ошибок надо задавать только в виде исключений.
    - Во-первых, потому что во всех остальных режимах PDO не сообщает об ошибке ничего внятного,
    - во-вторых, потому что исключение всегда содержит в себе незаменимый stack trace,
    - в-третьих - исключения чрезвычайно удобно обрабатывать.

    Плюс очень удобно задать FETCH_MODE по умолчанию, чтобы не писать его в КАЖДОМ запросе, как это очень любят делать прилежные хомячки.
    Также здесь можно задавать режим pconnect-а, эмуляции подготовленных выражений и много других страшных слов.

    В результате мы получаем переменную $pdo, с которой и работаем далее на протяжении всего скрипта.

    Для выполнения запросов можно пользоваться двумя методами.
    Если в запрос не передаются никакие переменные, то можно воспользоваться функцией query(). Она выполнит запрос и вернёт специальный объект - PDO statement. Очень грубо можно его сравнить с mysql resource, который возвращала mysql_query(). Получить данные из этого объекта можно как традиционным образом, через while, так и через foreach(). Также можно попросить вернуть полученные данные в особом формате, о чем ниже.
    $stmt = $pdo -> query ("SELECT name FROM users" );
    while ($row = $stmt -> fetch ())
    {
    }

    Если же в запрос передаётся хотя бы одна переменная, то этот запрос в обязательном порядке должен выполняться только через подготовленные выражения . Что это такое? Это обычный SQL запрос, в котором вместо переменной ставится специальный маркер - плейсхолдер. PDO поддерживает позиционные плейсхолдеры (?), для которых важен порядок передаваемых переменных, и именованные (:name), для которых порядок не важен. Примеры:
    $sql = ;
    $sql = ;

    Чтобы выполнить такой запрос, сначала его надо подготовить с помощью функции prepare(). Она также возвращает PDO statement, но ещё без данных. Чтобы их получить, надо исполнить этот запрос, предварительно передав в него переменные. Передать можно двумя способами:
    Чаще всего можно просто выполнить метод execute(), передав ему массив с переменными:
    $stmt = $pdo -> prepare ("SELECT name FROM users WHERE email = ?" );
    $stmt -> execute (array($email ));

    $stmt = $pdo -> prepare ("SELECT name FROM users WHERE email = :email" );
    $stmt -> execute (array("email" => $email ));
    Как видно, в случае именованных плейсхолдеров в execute() должен передаваться массив, в котором ключи должны совпадать с именами плейсхолдеров.

    Иногда, очень редко, может потребоваться второй способ, когда переменные сначала привязывают к запросу по одной, с помощью bindValue() / bindParam(), а потом только исполняют. В этом случае в execute() ничего не передается. Пример можно посмотреть в мануале
    Используя этот метод, всегда следует предпочесть bindValue()? поскольку поведение bindParam() не очевидно для новичков и будет приводить к проблемам.

    После этого можно использовать PDO statement теми же способами, что и выше. Например, через foreach:
    $stmt = $pdo -> prepare ("SELECT name FROM users WHERE email = ?" );
    $stmt ->
    foreach ($stmt as $row )
    {
    echo $row [ "name" ] . "\n" ;
    }

    ВАЖНО: Подготовленные выражения - основная причина использовать PDO, поскольку это единственный безопасный способ выполнения SQL запросов, в которых участвуют переменные.

    Также prepare() / execute() могут использоваться для многократного выполнения единожды подготовленного запроса с разными наборами данных. На практике это бывает нужно чрезвычайно редко, и особого прироста в скорости не приносит. Но на случай, если понадобится делать много однотипных запросов, то можно писать так:

    $data = array(
    1 => 1000,
    5 => 300,
    9 => 200,
    );

    $stmt = $pdo -> prepare ("UPDATE users SET bonus = bonus + ? WHERE id = ?" );
    foreach ($data as $id => $bonus )
    {
    $stmt -> execute ([ $bonus , $id ]);
    }

    Здесь мы один раз подготавливаем запрос, а затем много раз выполняем.

    Мы уже выше познакомились с методом fetch(), который служит для последовательного получения строк из БД. Этот метод является аналогом функции mysq_fetch_array() и ей подобных, но действует по-другому: вместо множества функций здесь используется одна, но ее поведение задается переданным параметром. В подробностях об этих параметрах будет написано позже, а в качестве краткой рекомендации посоветую применять fetch() в режиме FETCH_LAZY :
    $stmt = $pdo -> prepare ("SELECT name FROM users WHERE email = ?" );
    $stmt -> execute ([ $_GET [ "email" ]]);
    while ($row = $stmt -> fetch (PDO :: FETCH_LAZY ))
    {
    echo $row [ 0 ] . "\n" ;
    echo $row [ "name" ] . "\n" ;
    echo $row -> name . "\n" ;
    }

    В этом режиме не тратится лишняя память, и к тому же к колонкам можно обращаться любым из трех способов - через индекс, имя, или свойство.

    Также у PDO statement есть функция-хелпер для получения значения единственной колонки. Очень удобно, если мы запрашиваем только одно поле - в этом случае значительно сокращается количество писанины:
    $stmt = $pdo -> prepare ("SELECT name FROM table WHERE id=?" );
    $stmt -> execute (array($id ));
    $name = $stmt -> fetchColumn ();

    Но самой интересной функцией, с самым большим функционалом, является fetchAll(). Именно она делает PDO высокоуровневой библиотекой для работы с БД, а не просто низкоуровневым драйвером.

    FetchAll() возвращает массив, который состоит из всех строк, которые вернул запрос. Из чего можно сделать два вывода:
    1. Эту функцию не стоит применять тогда, когда запрос возвращает много данных. В таком случае лучше использовать традиционный цикл с fetch()
    2. Поскольку в современных РНР приложениях данные никогда не выводятся сразу по получении, а передаются для этого в шаблон, fetchAll() становится просто незаменимой, позволяя не писать циклы вручную, и тем самым сократить количество кода.

    Получение простого массива.
    Вызванная без параметров, эта функция возвращает обычный индексированный массив, в котором лежат строки из бд, в формате, который задан в FETCH_MODE по умолчанию. Константы PDO::FETCH_NUM, PDO::FETCH_ASSOC, PDO::FETCH_OBJ могут менять формат на лету.

    Получение колонки.
    Иногда бывает нужно получить простой одномерный массив, запросив единственное поле из кучи строк. Для этого используется режим PDO::FETCH_COLUMN
    $data = $pdo -> query ("SELECT name FROM users" )-> fetchAll (PDO :: FETCH_COLUMN );
    array (
    0 => "John" ,
    1 => "Mike" ,
    2 => "Mary" ,
    3 => "Kathy" ,
    )

    Получение пар ключ-значение.
    Также востребованный формат, когда желательно получить ту же колонку, но индексированную не числами, а одним из полей. За это отвечает константа PDO::FETCH_KEY_PAIR.
    $data = $pdo -> query ("SELECT id, name FROM users" )-> fetchAll (PDO :: FETCH_KEY_PAIR );
    array (
    104 => "John" ,
    110 => "Mike" ,
    120 => "Mary" ,
    121 => "Kathy" ,
    )

    Получение всех строк, индексированных полем.
    Также часто бывает нужно получить все строки из БД, но также индексированные не числами, а уникальным полем. Это делает константа PDO::FETCH_UNIQUE
    $data = $pdo -> query ("SELECT * FROM users" )-> fetchAll (PDO :: FETCH_UNIQUE );
    array (
    104 => array (
    "name" => "John" ,
    "car" => "Toyota" ,
    ),
    110 => array (
    "name" => "Mike" ,
    "car" => "Ford" ,
    ),
    120 => array (
    "name" => "Mary" ,
    "car" => "Mazda" ,
    ),
    121 => array (
    "name" => "Kathy" ,
    "car" => "Mazda" ,
    ),
    )

    Следует помнить, что первой в колонкой надо обязательно выбирать уникальное поле.

    Всего различных режимов получения данных в PDO больше полутора десятков. Плюс ещё их можно комбинировать! Но это уже тема для отдельной статьи.

    Работая с подготовленными выражениями, следует понимать, что плейсхолдер может заменять только строку или число. Ни ключевое слово, ни идентификатор, ни часть строки или набор строк через плейсхолдер подставить нельзя. Поэтому для LIKE надо сначала подготовить строку поиска целиком, а потом ее подставлять в запрос:

    $name = "% $name %" ;
    $stm = $pdo -> prepare ("SELECT * FROM table WHERE name LIKE ?" );
    $stm -> execute (array($name ));
    $data = $stm -> fetchAll ();

    Ну, вы поняли. Тут тоже всё плохо. PDO не предоставляет вообще никаких средств для работы с идентификаторами, и их надо форматировать по-старинке, вручную (или посмотреть, все-таки, в сторону SafeMysql , в которой этот, как и многие другие вопросы, решены просто и элегантно).
    Следует помнить, что правила форматирования идентификаторов отличаются для разных БД.

    В mysql для ручного форматирования идентификатора необходимо выполнить два действия:
    - заключить его в обратные одинарные кавычки (backticks, "`").
    - проискейпить эти символы внутри идентификатора внутри путём удвоения.

    $field = "`" . str_replace ("`" , "``" , $_GET [ "field" ]). "`" ;
    $sql = $field " ;

    Однако, здесь есть один нюанс. Одного форматирования может быть недостаточно. приведенный выше код гарантирует нас от классической инъекции, но в некоторых случаях враг все равно может записать что-то нежелательное, если мы бездумно подставляем имена полей и таблиц прямиком в запрос. К примеру, есть в таблице users поле admin. Если входящие имена полей не фильтровать, то в это поле, при автоматическом формировании запроса из POST-а, любой дурак запишет любую гадость.

    Поэтому имена таблиц и полей, приходящие от юзера, желательно проверять на допустимость, как в приведённом ниже примере

    Любой код для вставки, который можно увидеть в многочисленных туториалах, навевает тоску и желание убиться апстену. Многокилометровые построения с повторением одних и тех же имен - в идексах $_POST-а, в именах переменных, в именах полей в запросе, в именах плейсхолдеров в запросе, в именах плейсходеров и именах переменных при привязке.
    Глядя на этот код, хочется кого-нибудь убить, или, по крайней мере, сделать его немного короче.

    Это можно сделать, если принять соглашение, по которому имена полей в форме будут соответствовать именам полей в таблице. Тогда эти имена можно будет перечислить только один раз (в целях защиты от подмены, о которой говорилось выше), и использовать небольшую функцию-хелпер для сборки запроса, которая, в силу особенностей mysql, годится как для INSERT, так и UPDATE запросов:

    function pdoSet ($allowed , & $values , $source = array()) {
    $set = "" ;
    $values = array();
    if (! $source ) $source = & $_POST ;
    foreach ($allowed as $field ) {
    if (isset($source [ $field ])) {
    $set .= "`" . str_replace ("`" , "``" , $field ). "`" . "=: $field , " ;
    $values [ $field ] = $source [ $field ];
    }
    }
    return substr ($set , 0 , - 2 );
    }

    Соответственно, для вставки код будет

    $allowed = array("name" , "surname" , "email" ); // allowed fields
    $sql = "INSERT INTO users SET " . pdoSet ($allowed , $values );
    $stm = $dbh -> prepare ($sql );
    $stm -> execute ($values );

    А для апдейта - такой:

    $allowed = array("name" , "surname" , "email" , "password" ); // allowed fields
    $_POST [ "password" ] = MD5 ($_POST [ "login" ]. $_POST [ "password" ]);
    $sql = "UPDATE users SET " . pdoSet ($allowed , $values ). " WHERE id = :id" ;
    $stm = $dbh -> prepare ($sql );
    $values [ "id" ] = $_POST [ "id" ];
    $stm -> execute ($values );

    Не слишком эффектно, но зато очень эффективно. Напомню, кстати, что если использовать Класс для безопасной и удобной работы с MySQL , то это всё делается в две строчки.

    PDO и ключевые слова
    Здесь кроме фильтрации ничего придумать невозможно. поэтому тупо прогонять все не прописанные в запросе напрямую операторы через белый список:

    $dirs = array("ASC" , "DESC" );
    $key = array_search ($_GET [ "dir" ], $dirs ));
    $dir = $orders [ $key ];
    $sql = "SELECT * FROM `table` ORDER BY $field $dir " ;

    Обеспечивает методы для подготовки выражений и работы с объектами, которые могут сделать Вашу работу более продуктивной!

    Введение в PDO

    "PDO - PHP Data Objects - это уровень для доступа к базам данных, который обеспечивает унифицированные методы для доступа к различным базам данных."

    Он не зависит от специфического синтаксиса базы данных и позволяет легко переключаться на другой тип баз данных и платформу простым изменением строки подключения в большинстве случаев.

    Данный урок не является описанием процесса работы с SQL . Он предназначен для тех, кто использует расширения mysql или mysqli , чтобы помочь им перейти к более мощному и портируемому PDO.

    Поддержка баз данных

    Расширение поддерживает любую базу данных, для которой есть PDO драйвер. На текущий момент доступны драйвера для следующих типов баз данных:

    • PDO_DBLIB (FreeTDS / Microsoft SQL Server / Sybase)
    • PDO_FIREBIRD (Firebird/Interbase 6)
    • PDO_IBM (IBM DB2)
    • PDO_INFORMIX (IBM Informix Dynamic Server)
    • PDO_MYSQL (MySQL 3.x/4.x/5.x)
    • PDO_OCI (Oracle Call Interface)
    • PDO_ODBC (ODBC v3 (IBM DB2, unixODBC и win32 ODBC))
    • PDO_PGSQL (PostgreSQL)
    • PDO_SQLITE (SQLite 3 и SQLite 2)
    • PDO_4D (4D)

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

    Print_r(PDO::getAvailableDrivers());

    Подключение

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


    try { # MS SQL Server и Sybase с PDO_DBLIB $DBH = new PDO("mssql:host=$host;dbname=$dbname, $user, $pass"); $DBH = new PDO("sybase:host=$host;dbname=$dbname, $user, $pass"); # MySQL с PDO_MYSQL $DBH = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass); # SQLite $DBH = new PDO("sqlite:my/database/path/database.db"); } catch(PDOException $e) { echo $e->getMessage(); }

    Обратите внимание на блок try/catch - всегда нужно оборачивать операции PDO в блок try/catch и использовать механизм исключений. Обычно выполняется только одно подключение, в нашем примере показаны несколько подключений для отображения синтаксиса. $DBH содержит дескриптор базы данных и будет использоваться на протяжении всего нашего урока.

    Вы можете закрыть любое соединение установкой дескриптора в null .

    # Закрываем соединение $DBH = null;

    Вы можете узнать больше о специфических опциях и строках подключения для различных баз данных из документов с сайта PHP.net .

    Исключения и PDO

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

    $DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT); $DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING); $DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    Вне зависимости от установленного уровня контроля ошибка соединения всегда вызывает исключение и поэтому всегда должна быть заключена в блок try/catch .

    PDO::ERRMODE_SILENT

    Уровень контроля ошибок, устанавляваемы по умолчанию. На этом уровене ошибки генерируются по такому же принципу, как в расширениях mysql или mysqli . Два других уровня контроля ошибок более подходят для стиля програмирования в стиле DRY (Don"t Repeat Youself - не повторяй сам себя).

    PDO::ERRMODE_WARNING

    На данном уровне контроля ошибок генеррируются стандартные предупреждения PHP, при этом программа может продолжать выполение. Данный уровень удобен для отладки.

    PDO::ERRMODE_EXCEPTION

    Данный уровень контроля ошибок следует использовать в большинстве ситуаций. Генерируются исключения, которые позволяют аккуратно обрабатывать ошибки и скрывать данные, которые могут помочь кому-нибудь взломать Вашу систему. Ниже приведен пример, демонстрирующий преимущества исключений:

    # Подключаемся к базе данных try { $DBH = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass); $DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); # Ошибочно набираем DELECT вместо SELECT! $DBH->prepare("DELECT name FROM people"); } catch(PDOException $e) { echo " Извините. Но операция не может быть выполнена."; file_put_contents("PDOErrors.txt", $e->getMessage(), FILE_APPEND); }

    Здесь сделана преднамеренная ошибка в выражении SELECT. Это вызовет исключение. Исключение отправит описание ошибки в log файл и выдаст сообщение пользователю.

    Вставка и обновление данных

    Вставка новых данных или обновление существующих - одна из наиболее часто используемых общих операций баз данных. При использовании PDO, она раскладывается на два этапа. Все, что описана в данной главе применимо и к обоим операциям UPDATE и INSERT .


    Здесь приведен пример наиболее используемого типа вставки данных:

    # STH - это "дескриптор состояния" $STH = $DBH->prepare("INSERT INTO folks (first_name) values ("Cathy")"); $STH->execute();

    Конечно, вы можете выполнить данную операцию с использованием метода exec() , при этом количество вызовов будет меньше на один. Но лучше использовать более длинный метод для получения преимуществ подготовленных выражений. Даже если Вы собираетесь использовть их один единственный раз, подготовленные выражения помогут Вам защититься от атак на Вашу систему.

    Подготовленные выражения

    Подготовленные выражения - это предварительно скомпилированные выражения SQL, которые могут быть выполнены много раз с помощью пересылки только данных на сервер. Они имеют дополнительное преимущество при автоматическом заполнении шаблона данными в виде защиты от атаки посредством вложений SQL кода.

    Вы можете использовать подготовленные выражения с помощью включения шаблонов в ваш код SQL. Ниже приводятся 3 примера: один без шаблонов, один с неименованными шаблонами, один с именоваными шаблонами.

    # нет шаблонов - открыто для атак путем внедрения SQL кода! $STH = $DBH->("INSERT INTO folks (name, addr, city) values ($name, $addr, $city)"); # неименованые шаблоны $STH = $DBH->("INSERT INTO folks (name, addr, city) values (?, ?, ?); # именованые шаблоны $STH = $DBH->("INSERT INTO folks (name, addr, city) value (:name, :addr, :city)");

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

    Неименованные шаблоны

    # назначение переменных каждому шаблону, индексируются от 1 до 3 $STH->bindParam(1, $name); $STH->bindParam(2, $addr); $STH->bindParam(3, $city); # Вставляем одну строку $name = "Дима" $addr = "ул. Лизюкова"; $city = "Москва"; $STH->execute(); # Вставляем другую строку $name = "Сеня" $addr = "Коммунистический тупик"; $city = "Питер"; $STH->execute();

    Операция проходит в два этапа. На первом этапе шаблонам назначаются переменные. Затем, пременным присваиваются значения и выполняем выражение. Чтобы послать следующую порцию данных, нужно изменить значения переменных и выполнить выражение снова.

    Выглядит несколько громоздко для выражений с большим количеством параметров? Конечно. Однако, если Ваши данные храняться в массиве, то все будет очень коротко:

    # Данные, которые надо вставить $data = array("Моня", "проспект Незабудок", "Закутайск"); $STH = $DBH->("INSERT INTO folks (name, addr, city) values (?, ?, ?)"); $STH->execute($data);

    Данные в массиве подставляются в шаблоны в порядке следования. $data идет в первый шаблон, $data - во второй, и так далее. Однако, если массив проиндексирован в другом порядке, то такая операция будет выполняться некорректно. Вам нужно следить за соответствием порядка следования шаблонов и порядком расположения данных в массиве.

    Именованные шаблоны

    Вот пример использования именованного шаблона:

    # Первый аргумент функции - имя именованного шаблона # Именованный шаблон всегда начинается с двоеточия $STH->bindParam(":name", $name);

    Вы можете использовать сокращения, но они работают с ассоциированными массивами. Пример:

    # Данные, которые надо вставить $data = array("name" => "Мишель", "addr" => "переулок Кузнечный", "city" => "Cnjkbwf"); # Сокращение $STH = $DBH->("INSERT INTO folks (name, addr, city) value (:name, :addr, :city)"); $STH->execute($data);

    Ключи Вашей таблицы не нуждаются в двоеточии, но тем не менее должны соответствовать именам шаблонов. Если Вы используете массив массивов, то можно проходить по нему и просто вызывать execute для каждого массива данных.

    Другая приятная особенность именованых шаблонов - способность вставлять объекты прямо в вашу базу данных, при совпадении свойств и имен полей. Пример:

    # Простой объект class person { public $name; public $addr; public $city; function __construct($n,$a,$c) { $this->name = $n; $this->addr = $a; $this->city = $c; } # и т.д. ... } $cathy = new person("Катя","проспект Ленина","Можайск"); # Выполняем: $STH = $DBH->("INSERT INTO folks (name, addr, city) value (:name, :addr, :city)"); $STH->execute((array)$cathy);

    Преобразование типа объекта к array в execute приводит к обработке свойств как ключей массива.

    Получение данных


    Для получения данных используется метод идентификатора состояния ->fetch() . Перед вызовом метода fetch() нужно указать PDO как Вы будете доставать данные из базы. Можно выбрать следующие опции:

    • PDO::FETCH_ASSOC : возвращает массив, индексированный по именам столбцов
    • PDO::FETCH_BOTH (default) : возвращает массив, индексированный по именам столбцов и по номерам
    • PDO::FETCH_BOUND : назначает значения ваших столбцов набору переменных с использованием метода ->bindColumn()
    • PDO::FETCH_CLASS : назначает значения столбцов свойствам именованного класса, если соответствующего свойства не существует - оно создается
    • PDO::FETCH_INTO : обновляет существующий экземпляр именованного класса
    • PDO::FETCH_LAZY : комбинация PDO::FETCH_BOTH/PDO::FETCH_OBJ , создает имена переменных объекта так как они используются
    • PDO::FETCH_NUM : возвращает массив, индексированный по номерам столбцов
    • PDO::FETCH_OBJ : возвращает анонимный объект с именами свойств, соответствующих именам столбцов

    В действительности основные ситуации разрешаются с помощью трех опций: FETCH_ASSOC , FETCH_CLASS и FETCH_OBJ . Для установки метода извлечения данных используется:

    $STH->setFetchMode(PDO::FETCH_ASSOC);

    Также можно устанавливать метод извлечения данных непосредственно в вызове метода ->fetch() .

    FETCH_ASSOC

    Данный тип извлечения данных создает ассоциативный массив, индексированный по именам столбцов. Он должен быть достаточно хорошо известен тем, кто пользуется расширениями mysql/mysqli . Пример выборки данных:

    $STH = $DBH->query("SELECT name, addr, city from folks"); # Устанавливаем режим извлечения данных $STH->setFetchMode(PDO::FETCH_ASSOC); while($row = $STH->fetch()) { echo $row["name"] . "\n"; echo $row["addr"] . "\n"; echo $row["city"] . "\n"; }

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

    FETCH_OBJ

    При данном типе извлечения данных создается объект класса std для каждой строки полученных данных:

    $STH = $DBH->query("SELECT name, addr, city from folks"); # Устанавливаем режим извлечения данных $STH->setFetchMode(PDO::FETCH_OBJ); # показываем результат while($row = $STH->fetch()) { echo $row->name . "\n"; echo $row->addr . "\n"; echo $row->city . "\n"; }

    FETCH_CLASS

    При данном типе извлечения данные помещаются прямо в класс, который Вы выбирете. При использовании FETCH_CLASS свойства вашего объекта устанавливаются ДО вызова конструктора. Это очень важно. Если свойства соответствующего имени столбца не существует, то такое свойство будет создано (как public ) для Вас.

    Это означает, что если данные нуждаются в трансформации после извлечения из базы данных, то она может быть выполнена автоматически Вашим объектом, как только таковой будет создан.

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

    Class secret_person { public $name; public $addr; public $city; public $other_data; function __construct($other = "") { $this->address = preg_replace("//", "x", $this->address); $this->other_data = $other; } }

    Как только данные извлечены в класс, все символы a-z в нижнем регистре в адресе будут заменены символом x. Теперь с использованием класса и получением данных трансформация происходит полностью прозрачно:

    $STH = $DBH->query("SELECT name, addr, city from folks"); $STH->setFetchMode(PDO::FETCH_CLASS, "secret_person"); while($obj = $STH->fetch()) { echo $obj->addr; }

    Если адрес был ’Ленинский пр-т 5’ Вы увидите ’Лхххххххх хх-х 5’. Конечно, существуют ситуации, когда Вы хотите, чтобы конструктор был вызван перед тем, как будут назначены данные. PDO имеет средства реализовать это:

    $STH->setFetchMode(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, "secret_person");

    Теперь, когда Вы повторите предыдущий пример при установленом режиме PDO::FETCH_PROPS_LATE адрес не будет скрыт, так как конструктор был вызван и свойства назначены.

    Если Вам нужно, то можно передавать аргументы конструктору при извлечении данных в объект:

    $STH->setFetchMode(PDO::FETCH_CLASS, "secret_person", array("stuff"));

    Если Вам нужно передать различные данные в конструктор для каждого объекта, Вы можете устанавливать режим извлечения данных внутри метода fetch :

    $i = 0; while($rowObj = $STH->fetch(PDO::FETCH_CLASS, "secret_person", array($i))) { // do stuff $i++ }

    Некоторые другие полезные методы

    Так как в короткой статье нельзя описать PDO полностью, то представим несколько полезных методов для выполнения базовых операций.

    $DBH->lastInsertId();

    Метод ->lastInsertId() всегда вызывается дескриптором базы данных (а не дескриптором состояния) и возвращает значение автоматически увеличивающегося идентификатора последней вставленной строки для данного соединения.

    $DBH->exec("DELETE FROM folks WHERE 1"); $DBH->exec("SET time_zone = "-8:00"");

    Метод ->exec() используется для различных вспомогательных операций.

    $safe = $DBH->quote($unsafe);

    Метод ->quote() квотирует строки, так что они могут быть использованы в запросах. Это Ваш резерв на случай, если подготовленные выражения не используются.

    $rows_affected = $STH->rowCount();

    Метод ->rowCount() возвращает значение integer , указывающее количество строк, которые обрабатываются операцией. В последней версии PDO, в соответствии с отчетом об ошибках(http://bugs.php.net/40822) данный метод не работает с выражениями SELECT . Если у Вас возникли проблемы и Вы не можете обновить PHP, получить количество строк можно следующим способом:

    $sql = "SELECT COUNT(*) FROM folks"; if ($STH = $DBH->query($sql)) { # Проверка количества строк if ($STH->fetchColumn() > 0) { # Здесь должен быть код SELECT } else { echo "Нет строк соответствующих запросу."; } }

    Надеюсь, что урок Вам понравился!