Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Les deux pilotes peuvent exécuter une instruction une fois ou préparer une instruction pour une exécution répétée. Utilisez des paramètres pour les valeurs fournies par les utilisateurs, même lorsque vous ne lancez une requête qu’une seule fois.
Choisissez l’API d’exécution séparément de la manière dont vous récupérez les résultats. Préparer une requête ne récupère pas ses lignes, et mettre un résultat en mémoire tampon ne paramétrerait pas une requête. Les exemples suivants préparent une requête en lecture seule une fois, l’exécutent deux fois avec des valeurs différentes, et consomment chaque résultat avant l’exécution suivante.
| Style d’exécution | SQLSRV | PDO_SQLSRV |
|---|---|---|
| Exécutez une requête une fois, sans paramètres | sqlsrv_query | PDO::query pour les résultats, ou PDO ::exec pour les comptes de lignes affectées |
| Lancer une requête une fois, avec des paramètres | sqlsrv_query($conn, $sql, $params) |
PDO::prepare() suivi de PDOStatement::execute() |
| Préparez-vous une fois, exécutez à répétition avec différents paramètres | sqlsrv_prepare + sqlsrv_execute | PDO::prepare + PDOStatement ::execute |
sqlsrv_query() prépare et exécute en un seul appel et renvoie une ressource de requête.
sqlsrv_prepare() retourne une ressource d’instruction sans l’exécuter ; appelle sqlsrv_execute() chaque exécution. Les query() EDO exécutent et retournent PDOStatement, tandis exec() qu’ils retournent un compte de lignes affectées au lieu d’un objet résultat. Un appel exec() réussi peut retourner 0, comparez donc un retour d’échec avec === false, non if (!$count).
PDO::query() n’accepte pas un tableau de valeurs de paramètres. Ses arguments optionnels configurent la récupération. Pour les requêtes PDO_SQLSRV paramétrées, utilisez prepare() et execute().
Préparer une fois vous permet de réutiliser un handle de déclaration avec des valeurs différentes. Cela ne garantit pas que le serveur ne recompile jamais son plan d’exécution. PDO_SQLSRV utilise par défaut l’exécution préparée, y compris pour PDO::query(); son attribut de requête directe contrôle ce choix séparé.
Préparez-vous une fois et exécutez à plusieurs reprises
Ce sont des programmes en ligne de commande distincts et complets. Installez et chargez l’extension sélectionnée, puis définissez SQL_SERVER, SQL_DATABASE, SQL_USER, et SQL_PASSWORD dans l’environnement de processus PHP. Utilisez une base de données de test SQL Server et un certificat serveur fiable par le client. Pour la configuration de l’environnement et les alternatives sans mot de passe, voir Se connecter au serveur.
Stockez le nom réel de la base de données, le nom d’utilisateur et le mot de passe dans les variables d’environnement. Les deux programmes échappent à ces valeurs une fois en doublant les entretoises de fermeture et en encadrant chaque valeur dans des entretoises, comme l’exige la gestion de connexion de type ODBC du pilote PHP. S’échapper des valeurs de connexion est distinct de la liaison des paramètres de requête.
Les programmes exécutent une requête Transact-SQL (T-SQL) sur deux lignes en ligne sans créer de table ni modifier les données. Sauvegardez chaque programme dans son propre fichier .php et exécutez-le avec php <file>. Aucune base de données d’échantillons n’est requise.
SQLSRV
Transmettez $productId par référence avec &$productId. Chaque sqlsrv_execute() utilise alors sa valeur actuelle.
SQLSRV_FETCH_ASSOC renvoie un tableau indexé par nom de colonne. Un null résultat signifie qu’il n’y a plus de lignes ; false indique une erreur.
<?php
$config = [];
foreach (['SQL_SERVER', 'SQL_DATABASE', 'SQL_USER', 'SQL_PASSWORD'] as $name) {
$value = getenv($name);
if ($value === false || $value === '') {
throw new RuntimeException("Set $name before running this example.");
}
$config[$name] = $value;
}
foreach (['SQL_DATABASE', 'SQL_USER', 'SQL_PASSWORD'] as $name) {
$config[$name] = '{' . str_replace('}', '}}', $config[$name]) . '}';
}
$conn = sqlsrv_connect($config['SQL_SERVER'], [
'Database' => $config['SQL_DATABASE'],
'UID' => $config['SQL_USER'],
'PWD' => $config['SQL_PASSWORD'],
'Encrypt' => true,
'TrustServerCertificate' => false,
'LoginTimeout' => 30,
'CharacterSet' => 'UTF-8',
]);
if ($conn === false) {
throw new RuntimeException(print_r(sqlsrv_errors(), true));
}
$sql = "SELECT Name FROM (VALUES (1, 'Bike'), (2, 'Helmet')) AS Product(ProductId, Name) WHERE ProductId = ?";
$productId = 1;
$stmt = null;
try {
$stmt = sqlsrv_prepare($conn, $sql, [&$productId], ['QueryTimeout' => 30]);
if ($stmt === false) {
throw new RuntimeException(print_r(sqlsrv_errors(), true));
}
foreach ([1 => 'Bike', 2 => 'Helmet'] as $productId => $expected) {
if (!sqlsrv_execute($stmt)) {
throw new RuntimeException(print_r(sqlsrv_errors(), true));
}
$names = [];
while (($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) !== null) {
if ($row === false) {
throw new RuntimeException(print_r(sqlsrv_errors(), true));
}
$names[] = $row['Name'];
}
if ($names !== [$expected]) {
throw new RuntimeException('Expected exactly one matching product.');
}
echo $names[0], PHP_EOL;
}
} finally {
if (is_resource($stmt)) {
sqlsrv_free_stmt($stmt);
}
sqlsrv_close($conn);
}
PDO_SQLSRV
Fixez $productId une fois avec bindParam(). Chaque execute() lit sa valeur actuelle.
PDO::PARAM_INT spécifie le type de liaison PHP/PDO du paramètre ; il ne contrôle pas le type PHP des colonnes récupérées à partir du résultat. Régler le mode exception pour qu’une erreur de base de données interrompe l’exécution plutôt que d’être prise pour un résultat vide.
<?php
$config = [];
foreach (['SQL_SERVER', 'SQL_DATABASE', 'SQL_USER', 'SQL_PASSWORD'] as $name) {
$value = getenv($name);
if ($value === false || $value === '') {
throw new RuntimeException("Set $name before running this example.");
}
$config[$name] = $value;
}
foreach (['SQL_DATABASE', 'SQL_USER', 'SQL_PASSWORD'] as $name) {
$config[$name] = '{' . str_replace('}', '}}', $config[$name]) . '}';
}
$server = $config['SQL_SERVER'];
$database = $config['SQL_DATABASE'];
$pdo = new PDO(
"sqlsrv:Server=$server;Database=$database;Encrypt=true;"
. "TrustServerCertificate=false;LoginTimeout=30",
$config['SQL_USER'],
$config['SQL_PASSWORD'],
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::SQLSRV_ATTR_ENCODING => PDO::SQLSRV_ENCODING_UTF8,
]
);
$sql = "SELECT Name FROM (VALUES (1, 'Bike'), (2, 'Helmet')) AS Product(ProductId, Name) WHERE ProductId = ?";
$stmt = null;
try {
$stmt = $pdo->prepare($sql, [PDO::SQLSRV_ATTR_QUERY_TIMEOUT => 30]);
$productId = 1;
$stmt->bindParam(1, $productId, PDO::PARAM_INT);
foreach ([1 => 'Bike', 2 => 'Helmet'] as $productId => $expected) {
$stmt->execute();
$names = $stmt->fetchAll(PDO::FETCH_COLUMN);
if ($names !== [$expected]) {
throw new RuntimeException('Expected exactly one matching product.');
}
echo $names[0], PHP_EOL;
$stmt->closeCursor();
}
} finally {
$stmt = null;
$pdo = null;
}
Chaque exemple s’imprime :
Bike
Helmet
Les valeurs d’un tableau passées à execute() de PDO sont traitées comme PDO::PARAM_STR. Lorsque SQL nécessite un paramètre entier, comme un comptage paramétré TOP, appelez bindValue() avec PDO::PARAM_INT puis appelez execute() sans tableau.
Liez des valeurs sans modifier la requête
Un marqueur de paramètre représente une valeur, et non un nom de table, un nom de colonne, un mot-clé ou une direction de tri. Ne mettez pas de guillemets autour de ?. Pour un identifiant dynamique ou ASC/DESC, sélectionnez à partir d’une liste d’autorisation contrôlée par l’application au lieu de concaténer du texte non fiable. Pour une IN liste, indiquez un marqueur par valeur.
| Requirement | SQLSRV | PDO_SQLSRV |
|---|---|---|
| Liez les valeurs pour une exécution | Passez le tableau de paramètres à sqlsrv_query(). |
Passez un tableau à execute() après prepare(), ou liez d’abord les valeurs. |
| Réutiliser la valeur actuelle d’une variable | Inclure &$variable dans le tableau fourni à sqlsrv_prepare(). |
Appelez bindParam() avec la variable, puis execute() sans tableau de données. PHP transmet la variable par référence ; ne l’ajoutez & pas au site d’appel. |
| Liez une valeur au moment de la liaison | Utilisez une valeur dans le tableau de paramètres pour l’exécution. | Appelez bindValue(); les modifications ultérieures de la variable originale ne modifient pas cette valeur limitée. |
| Spécifier une entrée entière | Utilisez un descripteur de paramètre avec SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_INT, et SQLSRV_SQLTYPE_INT lorsqu’un type explicite est nécessaire. |
Liez avec PDO::PARAM_INT. Les index positionnels bindParam() et 1 commencent à 0, non bindValue(). |
Envoyer SQL NULL |
Liez PHP null, avec un type SQL explicite lorsque l’opération l’exige. |
Liez avec PDO::PARAM_NULL. |
| Paramètres de sortie de réception | Utilisez une variable référencée avec SQLSRV_PARAM_OUT ou SQLSRV_PARAM_INOUT. |
Utilisez bindParam() avec PDO::PARAM_INPUT_OUTPUT et le type et la longueur requis. |
Gardez les variables référencées en vie lors de l’exécution de la requête préparée. Le programme SQLSRV modifie la variable borne plutôt que de remplacer le tableau de paramètres. Le programme PDO appelle execute() délibérément sans tableau après la liaison ; ne mélangez pas ce schéma avec l’exécution basée sur un tableau.
Les valeurs de sortie des procédures stockées nécessitent leur propre gestion, y compris la complétion des résultats de la procédure. N’inférez pas le comportement des paramètres de sortie à partir de ces exemples uniquement en entrée. Pour plus d’informations, voir Utilisation des paramètres directionnels.
Configurer le comportement d’exécution et de récupération
| Setting | SQLSRV | PDO_SQLSRV |
|---|---|---|
| Temps d’exécution |
QueryTimeout dans la liste des options de déclaration. |
PDO::SQLSRV_ATTR_QUERY_TIMEOUT sur la connexion ou l’instruction. |
| Clés de résultat nommées |
SQLSRV_FETCH_ASSOC transmis à sqlsrv_fetch_array(). |
PDO::FETCH_ASSOC transmis à une méthode de récupération ou défini comme mode de récupération par défaut de la connexion. |
| Résultats uniquement en attaque | Curseur par défaut ; chercher dans l’ordre. | Curseur par défaut ; extraire dans l'ordre. |
| Résultats mis en mémoire tampon côté client |
Scrollable => SQLSRV_CURSOR_CLIENT_BUFFERED. |
PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL avec PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE => PDO::SQLSRV_CURSOR_BUFFERED. |
| Exécution directe versus exécution préparée | Aucun attribut de requête directe PDO. Choisissez l’appel combiné sqlsrv_query() ou la paire explicite préparer/exécuter. |
PDO::SQLSRV_ATTR_DIRECT_QUERY sélectionne l’exécution directe plutôt que l’exécution préparée par défaut du pilote. |
| Émulation des paramètres | Pas d’attribut d’émulation PDO. |
PDO::ATTR_EMULATE_PREPARES est distinct de l’attribut de requête directe. Ne l’utilisez pas comme substitut à la liaison des bons types. |
Les exemples donnent de petits résultats.
fetchAll() charge chaque ligne dans la mémoire PHP ; utilise une boucle de récupération pour un résultat volumineux. Une requête qui ne retourne aucune correspondance n’est pas une erreur d’exécution. SQLSRV rapporte la fin du résultat comme null depuis sqlsrv_fetch_array(); PDO la rapporte comme false depuis fetch(). Une requête SQL NULL dans une ligne extraite reste PHP null.
N’utilisez pas le nombre de lignes SELECT comme seul test de réussite. Les curseurs avant uniquement ne fournissent pas les mêmes capacités de comptage des lignes que les curseurs avec tampon ou défilables. Récupérez et comptez les lignes dont vous avez besoin, ou utilisez une requête séparée COUNT . Pour les options et limitations spécifiques au curseur, voir Spécifier un type de curseur et sélectionner des lignes.
Gérer les échecs et finaliser les résultats
Vérifiez séparément les opérations de préparation SQLSRV, exécution et récupération. Une préparation réussie ne prouve pas que l’exécution réussira : le serveur peut rejeter les valeurs des paramètres, les permissions ou l’instruction au moment de l’exécution. Capturez sqlsrv_errors() immédiatement dès qu’une opération renvoie false. SQLSRV traite de nombreux avertissements comme des erreurs par défaut, donc inspectez la collection complète.
Pour PDO, les échecs de connexion et les erreurs de base de données en mode exception lèvent PDOException. Inspectez ses informations d’état SQLSTATE et d’erreur de pilote dans les diagnostics d’application protégés ; ne retournez pas de texte d’exception ni d’identifiants dans une réponse HTTP.
prepare() Réussir n’est pas la preuve que l’instruction a déjà été exécutée.
| Symptôme | Action |
|---|---|
| Chaque exécution utilise la première valeur | Pour SQLSRV, associez une variable par référence. Pour PDO, utilisez bindParam() pour une variable dont la valeur change ou appelez bindValue() pour chaque nouvelle valeur. |
Un paramètre numérique est rejeté, comme un TOP nombre |
Liez explicitement le type entier requis. PDO execute([$value]) utilise des paramètres de chaîne même si la valeur PHP est un entier. |
| Une seconde commande rapporte les résultats en attente | Consommez les résultats ou libérez-les avant de réutiliser la connexion. Pour le PDO, utilisez closeCursor() quand vous n’avez pas besoin du résultat restant. |
| Les paramètres de sortie attendus n’ont pas changé | Complétez tous les résultats de la procédure et vérifiez la direction des paramètres, le type PHP et la longueur du tampon de sortie. |
| L’utilisation de la mémoire augmente avec la taille du résultat | Remplacez fetchAll() ou la mise en mémoire tampon client inutile par la récupération séquentielle. |
Les exemples libèrent leurs instructions et leurs connexions dans finally. Ils ne commencent pas une transaction. Utilisez une transaction explicite lorsque plusieurs écritures doivent soit valider ensemble, soit toutes être annulées. Réutiliser une instruction préparée ne regroupe pas les écritures dans une transaction.
Différences entre objectif et mise en œuvre
Les API prepare/execute et les règles de passage par référence de PHP appartiennent aux extensions et à PHP/PDO. La cible SQL décide quelles instructions et types T-SQL sont pris en charge, et ODBC effectue la communication sous-jacente. Préparer une seule fois peut réduire le travail répété, mais cela ne garantit ni un plan d’exécution précis côté serveur ni un gain de performances particulier.
Les modèles de liaison d’entrée s’appliquent à SQL Server, Azure SQL Database, Azure SQL Managed Instance, Azure Synapse Analytics, SQL database dans Microsoft Fabric et Warehouse dans Microsoft Fabric. Ces programmes utilisent l’authentification SQL pour SQL Server. Pour l’intégration Azure, privilégiez l’authentification Microsoft Entra. Les deux produits Fabric l’exigent, et Warehouse exige également de désactiver les ensembles de résultats actifs multiples (MARS). Vérifiez le support de la cible sélectionnée pour les modifications de schéma, les transactions et les procédures stockées avant de réutiliser le code SQL Server. Pour les différences de points de terminaison et d’authentification, voir connexions Azure et Fabric.