Ce comportement est reproductible avec le PHP actuel (5.6.13), et la requête n'est même pas envoyée au serveur.
Votre cas est décrit dans la doc comme :
0 valeur est attendue, 1 valeur est donnée et l'instruction échoue, false
étant retourné. Jusqu'à présent, fonctionne comme documenté.
Vous pouvez argumenter que "une erreur est émise " impliquerait que lorsque ERRMODE_EXCEPTION
est activé, une exception serait levée. C'est un argument, mais il n'est pas évident que les développeurs de PDO seraient d'accord.
Mise à jour :
Pourquoi SQLCode
pas défini ?
En regardant le code source PDO, en particulier static PHP_METHOD(PDOStatement, execute)
qui gère PDO::execute(), vous pouvez voir que toutes les erreurs sont gérées par une macro :PDO_HANDLE_STMT_ERR()
#define PDO_HANDLE_STMT_ERR() if (strcmp(stmt->error_code, PDO_ERR_NONE)) { pdo_handle_error(stmt->dbh, stmt TSRMLS_CC); }
Le fait est que, lors du passage d'un paramètre lié alors que PDO n'en attendait aucun, la requête n'arrive jamais au moteur SQL, de sorte que le moteur SQL n'a jamais la possibilité de signaler une erreur accompagnée d'un SQLSTATE
PDO lui-même ne crée pas un faux SQLSTATE
tout seul, du moins non dans ce cas, doncstmt->error_code
reste à PDO_ERR_NONE
qui est "00000"
.
Il est compréhensible que vous préfériez qu'une exception soit déclenchée, mais vous devriez alors le suggérer à https://bugs.php. net
Est-ce la même chose avec MySQL ?
Oui, le comportement root est le même sauf qu'avec le pilote MySQL, le prepare
est envoyé immédiatement au moteur SQL donc s'il est incorrect à cause d'une mauvaise colonne, il échoue plus tôt et avec une vraie erreur SQL. D'autre part, le pilote PgSQL a une implémentation différente qui lui fait différer la prepare
côté serveur . Ce comportement particulier est discuté en détail sur Le pilote PHP Postgres PDO ne prend pas en charge l'instruction préparée ?
Quoi qu'il en soit, voici un cas avec MySQL qui démontre mon explication, c'est-à-dire :
- la requête attend 0 paramètre, 1 est donné
$stmt->execute
renvoie faux- aucune exception n'est déclenchée
- PDO::errorCode est
00000
Code :
$link = new PDO('mysql:dbname=' . $name . ';host=' . $host, $user, $password);
$link->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$link->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
try {
$stmt = $link->prepare("SELECT 1");
$rc=$stmt->execute(array(1));
if ($rc===false)
echo "query failed, errorCode=", $link->errorCode(), "\n";
else
echo "query succeeded, errorCode=", $link->errorCode(), "\n";
}
catch (PDOException $e) {
print "A PDOException has occurred";
print $e->getMessage();
}
Résultat :
Ce qui se passe sous le capot, c'est que le prepare
est envoyé au serveur et réussit, mais le execute
l'étape est annulée par PDO en raison de la non-concordance des paramètres.
Voici un cas qui diffère par le fait que la requête fait référence à une colonne inexistante. J'ajoute une impression pour montrer que $stmt->execute
n'est même pas appelé, car l'exception est levée par $stmt->prepare
Code :
$link = new PDO('mysql:dbname=' . $name . ';host=' . $host, $user, $password);
$link->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$link->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
try {
$stmt = $link->prepare("SELECT nonexisting");
echo "Executing query\n";
$rc=$stmt->execute(array(1));
if ($rc===false)
echo "query failed, errorCode=", $link->errorCode(), "\n";
else
echo "query succeeded, errorCode=", $link->errorCode(), "\n";
}
catch (PDOException $e) {
print "A PDOException has occurred";
print $e->getMessage();
}
Résultat :
Notez que l'étape "Exécution de la requête" ne se produit jamais, car il s'agit de la prepare
qui échoue, côté serveur.
Conclusion
-
lorsque la requête est envoyée au serveur, que ce soit dans prepare() ou execute(), et que c'est le serveur qui génère une erreur, alors nous pouvons nous attendre à ce qu'une PDOException soit levée.
-
lorsque la requête n'est pas envoyée au serveur pour une étape d'exécution, alors PDO execute() peut échouer (retourne false) mais aucune exception n'est levée et
errorCode()
reste à00000