Sådan besvarer du dine bekymringer:
-
MySQL>=5.1.17 (eller>=5.1.21 for
PREPARE
ogEXECUTE
udsagn) kan bruge forberedte udsagn i forespørgselscachen . Så din version af MySQL+PHP kan bruge forberedte sætninger med forespørgselscachen. Vær dog opmærksom på forbeholdene for cache-forespørgselsresultater i MySQL-dokumentationen. Der er mange slags forespørgsler, som ikke kan cachelagres, eller som er ubrugelige, selvom de er cachelagret. Efter min erfaring er forespørgselscachen alligevel ikke ofte en særlig stor gevinst. Forespørgsler og skemaer kræver en speciel konstruktion for at udnytte cachen maksimalt. Ofte ender caching på applikationsniveau alligevel med at være nødvendig i det lange løb. -
Native forbereder gør ikke nogen forskel for sikkerheden. De pseudo-forberedte sætninger vil stadig undslippe forespørgselsparameterværdier, det vil bare blive gjort i PDO-biblioteket med strenge i stedet for på MySQL-serveren ved hjælp af den binære protokol. Med andre ord vil den samme PDO-kode være lige så sårbar (eller ikke-sårbar) over for injektionsangreb uanset din
EMULATE_PREPARES
indstilling. Den eneste forskel er, hvor parameterudskiftningen finder sted - medEMULATE_PREPARES
, det forekommer i PDO-biblioteket; udenEMULATE_PREPARES
, forekommer det på MySQL-serveren. -
Uden
EMULATE_PREPARES
du kan få syntaksfejl ved forberedelsestidspunktet i stedet for ved udførelsestidspunkt; medEMULATE_PREPARES
du vil kun få syntaksfejl ved udførelsestidspunktet, fordi PDO ikke har en forespørgsel at give til MySQL før udførelsestidspunktet. Bemærk, at dette påvirker den kode, du vil skrive ! Især hvis du brugerPDO::ERRMODE_EXCEPTION
!
En yderligere overvejelse:
- Der er en fast pris for en
prepare()
(ved at bruge native forberedte sætninger), så enprepare();execute()
med native forberedte sætninger kan være lidt langsommere end at udstede en almindelig tekstforespørgsel ved hjælp af emulerede forberedte sætninger. På mange databasesystemer planlægger forespørgslen for enprepare()
er også cachelagret og kan deles med flere forbindelser, men jeg tror ikke, MySQL gør dette. Så hvis du ikke genbruger dit forberedte sætningsobjekt til flere forespørgsler, kan din samlede udførelse være langsommere.
Som en endelig anbefaling , Jeg tror, at du med ældre versioner af MySQL+PHP bør efterligne forberedte udsagn, men med dine helt nyere versioner bør du slå emulering fra.
Efter at have skrevet et par apps, der bruger PDO, har jeg lavet en PDO forbindelsesfunktion, som har, hvad jeg synes er de bedste indstillinger. Du bør sandsynligvis bruge noget som dette eller justere til dine foretrukne indstillinger:
/**
* 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;
}