Réponses:
query
exécute une instruction SQL standard et vous oblige à échapper correctement toutes les données pour éviter les injections SQL et d'autres problèmes.
execute
exécute une instruction préparée qui vous permet de lier des paramètres pour éviter d'avoir à échapper ou à citer les paramètres. execute
fonctionnera également mieux si vous répétez une requête plusieurs fois. Exemple d'instructions préparées:
$sth = $dbh->prepare('SELECT name, colour, calories FROM fruit
WHERE calories < :calories AND colour = :colour');
$sth->bindParam(':calories', $calories);
$sth->bindParam(':colour', $colour);
$sth->execute();
// $calories or $color do not need to be escaped or quoted since the
// data is separated from the query
La meilleure pratique est de s'en tenir aux déclarations préparées et execute
pour une sécurité accrue .
Voir aussi: Les instructions préparées PDO sont-elles suffisantes pour empêcher l'injection SQL?
: calories
est-ce que cela équivaut mysql_real_escape_string()
à arrêter les injections ou avez-vous besoin de plus que simplement $sth->bindParam(':calories', $calories);
pour renforcer la sécurité?
query
retourne- t-il un PDOStatement , au lieu d'un booléen comme execute
?
Non, ce ne sont pas les mêmes. En plus de l'échappement côté client qu'il fournit, une instruction préparée est compilée une fois côté serveur, puis peut recevoir différents paramètres à chaque exécution. Ce qui signifie que vous pouvez faire:
$sth = $db->prepare("SELECT * FROM table WHERE foo = ?");
$sth->execute(array(1));
$results = $sth->fetchAll(PDO::FETCH_ASSOC);
$sth->execute(array(2));
$results = $sth->fetchAll(PDO::FETCH_ASSOC);
Ils vous apporteront généralement une amélioration des performances, bien que cela ne soit pas perceptible à petite échelle. En savoir plus sur les instructions préparées (version MySQL) .
La réponse de Gilean est excellente, mais je voulais juste ajouter qu'il existe parfois de rares exceptions aux meilleures pratiques, et vous voudrez peut-être tester votre environnement dans les deux sens pour voir ce qui fonctionnera le mieux.
Dans un cas, j'ai trouvé que cela query
fonctionnait plus rapidement pour mes besoins car je transférais en masse des données de confiance à partir d'une machine Ubuntu Linux exécutant PHP7 avec le pilote Microsoft ODBC mal pris en charge pour MS SQL Server .
Je suis arrivé à cette question parce que j'avais un script de longue durée pour un ETL que j'essayais de presser pour la vitesse. Cela m'a semblé intuitif qui query
pourrait être plus rapide que prepare
& execute
parce qu'il n'appelait qu'une seule fonction au lieu de deux. L'opération de liaison de paramètres offre une excellente protection, mais elle peut être coûteuse et peut-être évitée si elle n'est pas nécessaire.
Compte tenu de quelques conditions rares :
Si vous ne pouvez pas réutiliser une instruction préparée car elle n'est pas prise en charge par le pilote ODBC Microsoft .
Si vous ne vous inquiétez pas de la désinfection des entrées, une simple évacuation est acceptable. Cela peut être le cas car la liaison de certains types de données n'est pas prise en charge par le pilote ODBC Microsoft .
PDO::lastInsertId
n'est pas pris en charge par le pilote ODBC Microsoft.
Voici une méthode que j'ai utilisée pour tester mon environnement, et j'espère que vous pourrez le reproduire ou quelque chose de mieux dans le vôtre:
Pour commencer, j'ai créé une table de base dans Microsoft SQL Server
CREATE TABLE performancetest (
sid INT IDENTITY PRIMARY KEY,
id INT,
val VARCHAR(100)
);
Et maintenant, un test chronométré de base pour les mesures de performance.
$logs = [];
$test = function (String $type, Int $count = 3000) use ($pdo, &$logs) {
$start = microtime(true);
$i = 0;
while ($i < $count) {
$sql = "INSERT INTO performancetest (id, val) OUTPUT INSERTED.sid VALUES ($i,'value $i')";
if ($type === 'query') {
$smt = $pdo->query($sql);
} else {
$smt = $pdo->prepare($sql);
$smt ->execute();
}
$sid = $smt->fetch(PDO::FETCH_ASSOC)['sid'];
$i++;
}
$total = (microtime(true) - $start);
$logs[$type] []= $total;
echo "$total $type\n";
};
$trials = 15;
$i = 0;
while ($i < $trials) {
if (random_int(0,1) === 0) {
$test('query');
} else {
$test('prepare');
}
$i++;
}
foreach ($logs as $type => $log) {
$total = 0;
foreach ($log as $record) {
$total += $record;
}
$count = count($log);
echo "($count) $type Average: ".$total/$count.PHP_EOL;
}
J'ai joué avec plusieurs essais et comptages différents dans mon environnement spécifique, et j'obtiens constamment des résultats 20 à 30% plus rapides avec query
que prepare
/execute
5,8128969669342 préparer
5,8688418865204 préparer
4,2948560714722 requête
4,9533629417419 requête
5,9051351547241 préparer
4,332102060318 requête
5,9672858715057 préparer
5,0667371749878 requête
3,8260300159454 requête
4,0791549682617 requête
4,3775160312653 requête
3,6910600662231 requête
5,2708210945129 préparer
6,2671611309052 préparer
7,3791449069977 préparer
(7) préparer moyenne: 6,0673267160143
(8) requête moyenne: 4,3276024162769
Je suis curieux de voir comment ce test se compare dans d'autres environnements, comme MySQL.