Чтобы ответить на ваши вопросы:
MySQL> = 5.1.17 (или> = 5.1.21 для PREPAREи EXECUTEзаявления) могут использовать подготовленные заявления в кэше запросов . Таким образом, ваша версия MySQL + PHP может использовать подготовленные операторы с кешем запросов. Однако обратите внимание на предостережения относительно кеширования результатов запросов в документации MySQL. Есть много видов запросов, которые нельзя кэшировать или которые бесполезны, даже если они кэшированы. По моему опыту, кеш запросов в любом случае не очень важен. Запросы и схемы требуют специальной конструкции, чтобы максимально использовать кеш. Часто кеширование на уровне приложения в конечном итоге все равно необходимо.
Собственная подготовка не имеет никакого значения для безопасности. Псевдо-подготовленные операторы по-прежнему будут экранировать значения параметров запроса, это будет просто выполняться в библиотеке PDO со строками, а не на сервере MySQL с использованием двоичного протокола. Другими словами, один и тот же код PDO будет одинаково уязвим (или не уязвим) для атак путем внедрения, независимо от ваших EMULATE_PREPARESнастроек. Единственная разница в том, где происходит замена параметра - с EMULATE_PREPARES, это происходит в библиотеке PDO; без EMULATE_PREPARES, это происходит на сервере MySQL.
Без этого EMULATE_PREPARESвы можете получить синтаксические ошибки во время подготовки, а не во время выполнения; with EMULATE_PREPARESвы получите синтаксические ошибки только во время выполнения, потому что PDO не имеет запроса для передачи MySQL до времени выполнения. Обратите внимание, что это влияет на код, который вы напишете ! Особенно если пользуетесь PDO::ERRMODE_EXCEPTION!
Дополнительное соображение:
- Существует фиксированная стоимость для
prepare()(с использованием собственных подготовленных операторов), поэтому prepare();execute()запрос с собственными подготовленными операторами может быть немного медленнее, чем выдача простого текстового запроса с использованием эмулированных подготовленных операторов. Во многих системах баз данных план запроса для a также prepare()кэшируется и может использоваться несколькими соединениями, но я не думаю, что MySQL делает это. Поэтому, если вы не используете повторно подготовленный объект оператора для нескольких запросов, ваше общее выполнение может быть медленнее.
В качестве последней рекомендации я думаю, что для более старых версий MySQL + PHP вы должны эмулировать подготовленные операторы, но в ваших самых последних версиях вы должны отключить эмуляцию.
После написания нескольких приложений, использующих PDO, я создал функцию подключения PDO, которая, по моему мнению, имеет лучшие настройки. Вероятно, вам следует использовать что-то подобное или настроить свои предпочтительные настройки:
/**
* Return PDO handle for a MySQL connection using supplied settings
*
* Tries to do the right thing with different php and mysql versions.
*
* @param array $settings with keys: host, port, unix_socket, dbname, charset, user, pass. Some may be omitted or NULL.
* @return PDO
* @author Francis Avila
*/
function connect_PDO($settings)
{
$emulate_prepares_below_version = '5.1.17';
$dsndefaults = array_fill_keys(array('host', 'port', 'unix_socket', 'dbname', 'charset'), null);
$dsnarr = array_intersect_key($settings, $dsndefaults);
$dsnarr += $dsndefaults;
// connection options I like
$options = array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
);
// connection charset handling for old php versions
if ($dsnarr['charset'] and version_compare(PHP_VERSION, '5.3.6', '<')) {
$options[PDO::MYSQL_ATTR_INIT_COMMAND] = 'SET NAMES '.$dsnarr['charset'];
}
$dsnpairs = array();
foreach ($dsnarr as $k => $v) {
if ($v===null) continue;
$dsnpairs[] = "{$k}={$v}";
}
$dsn = 'mysql:'.implode(';', $dsnpairs);
$dbh = new PDO($dsn, $settings['user'], $settings['pass'], $options);
// Set prepared statement emulation depending on server version
$serverversion = $dbh->getAttribute(PDO::ATTR_SERVER_VERSION);
$emulate_prepares = (version_compare($serverversion, $emulate_prepares_below_version, '<'));
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, $emulate_prepares);
return $dbh;
}