Confronto delle funzioni di esecuzione

Download del driver PHP

Entrambi i driver possono eseguire un'istruzione una volta o prepararne una per l'esecuzione ripetuta. Usa parametri per i valori forniti dagli utenti, anche quando esegui una query solo una volta.

Scegli l'API di esecuzione separatamente da come ottieni i risultati. Preparare una query non recupera le sue righe, e il buffering di un risultato non rende una query parametrizzata. I seguenti esempi preparano una query di sola lettura una volta, la eseguono due volte con valori diversi e consumano ogni risultato prima della successiva esecuzione.

Stile di esecuzione SQLSRV PDO_SQLSRV
Esegui una query una volta, senza parametri sqlsrv_query PDO::query per i risultati, oppure PDO::exec per i conteggi delle righe interessate
Esegui una query una volta, con parametri sqlsrv_query($conn, $sql, $params) PDO::prepare() seguito da PDOStatement::execute()
Prepara una volta, esegue ripetutamente con parametri diversi sqlsrv_prepare + sqlsrv_execute PDO::prepare + PDOStatement::execute

sqlsrv_query() prepara ed esegue in un'unica chiamata e restituisce una risorsa di istruzioni. sqlsrv_prepare() restituisce una risorsa di istruzione senza eseguirla; chiama sqlsrv_execute() per ogni esecuzione. Il query() di PDO esegue e restituisce PDOStatement, mentre exec() restituisce un conteggio di righe interessate invece di un oggetto risultato. Una chiamata riuscita exec() può restituire 0, quindi confronta un ritorno fallito con === false, non if (!$count).

PDO::query() Non accetta un array di valori di parametri. I suoi argomenti opzionali configurano il recupero dei dati. Per query PDO_SQLSRV parametrizzate, usare prepare() e execute().

Preparare una volta ti permette di riutilizzare un handle di istruzione con valori diversi. Questo non garantisce che il server non ricompili mai il proprio piano di esecuzione. PDO_SQLSRV utilizza l'esecuzione preparata per impostazione predefinita, inclusa per PDO::query(); il attributo direct-query controlla tale scelta separata.

Prepara una volta ed esegui ripetutamente

Si tratta di programmi separati e completi a riga di comando. Installa e carica l'estensione selezionata, imposta SQL_SERVER, SQL_DATABASE, SQL_USER, e SQL_PASSWORD nell'ambiente di processo PHP. Usa un database di test SQL Server e un certificato server considerato attendibile dal client. Per la configurazione dell'ambiente e le alternative senza password, vedi Connessione al server.

Memorizza il nome effettivo del database, il nome utente e la password nelle variabili ambientali. Entrambi i programmi eseguono l'escape di questi valori una volta raddoppiando le parentesi graffe di chiusura e racchiudendo ogni valore tra parentesi graffe, come richiesto dalla gestione delle connessioni in stile ODBC del driver PHP. Scappare dai valori di connessione è separato dal binding dei parametri di query.

I programmi eseguono una query Transact-SQL (T-SQL) su due righe inline senza creare una tabella o modificare i dati. Salva ogni programma nel proprio file .php e eseguilo con php <file>. Non è richiesto alcun database di campioni.

SQLSRV

Passa $productId per riferimento con &$productId. Ciascuno sqlsrv_execute() utilizza quindi il suo valore corrente. SQLSRV_FETCH_ASSOC restituisce un array codificato per nome di colonna. Un null risultato significa che non ci sono più righe; false indica un errore.

<?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

Associa $productId una volta con bindParam(). Ciascun execute() legge il proprio valore corrente. PDO::PARAM_INT specifica il tipo di binding PHP/PDO del parametro; non controlla il tipo PHP delle colonne recuperate dal risultato. Imposta la modalità eccezione in modo che un errore del database interrompa l'esecuzione invece di essere scambiato per un risultato vuoto.

<?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;
}

Ogni esempio stampa:

Bike
Helmet

I valori in un array passati ai PDO execute() sono trattati come PDO::PARAM_STR. Quando SQL richiede un parametro integer, ad esempio un conteggio TOP parametrizzato, chiamare bindValue() con PDO::PARAM_INT e quindi chiamare execute() senza passare un array.

Associare i valori senza modificare la query

Un marcatore di parametro rappresenta un valore, non un nome di tabella, un nome di colonna, una parola chiave o una direzione di ordinamento. Non mettere preventivi in giro ?. Per un identificatore dinamico o ASC/DESC, seleziona da una lista di permessi controllata dall'applicazione invece di concatenare testo non affidabile. Per una IN lista, fornisci un marcatore per ogni valore.

Requirement SQLSRV PDO_SQLSRV
Valori di associazione per una singola esecuzione Passa l'array di parametri a sqlsrv_query(). Passa un array a execute() dopo prepare(), oppure assegna prima i valori.
Riutilizzare il valore corrente di una variabile Includere &$variable nell'array fornito a sqlsrv_prepare(). Chiama bindParam() con la variabile, poi execute() senza un array. PHP passa la variabile per riferimento; non aggiungere & al sito di chiamata.
Assegna un valore al momento del binding Usa un valore nell'array di parametri per l'esecuzione. Chiama bindValue(); le modifiche successive alla variabile originale non modificano quel valore limitato.
Specificare un ingresso intero Usa un descrittore di parametro con SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_INT, e SQLSRV_SQLTYPE_INT quando è necessario un tipo esplicito. Lega con PDO::PARAM_INT. Le posizioni bindParam() e gli indici iniziano da 1, non 0bindValue() .
Invia SQL NULL Associare PHP null, con un tipo SQL esplicito quando richiesto dall'operazione. Lega con PDO::PARAM_NULL.
Ricevi parametri di output Usa una variabile di riferimento con SQLSRV_PARAM_OUT o SQLSRV_PARAM_INOUT. Usa bindParam() con PDO::PARAM_INPUT_OUTPUT e il tipo e la lunghezza richiesti.

Mantieni attive le variabili referenziate durante l'esecuzione dell'istruzione preparata. Il programma SQLSRV modifica la variabile associata invece di sostituire l'array di parametri. Il programma PDO chiama execute() deliberatamente senza un array dopo il binding; non mescolare quel pattern con l'esecuzione basata su array.

I valori di output delle stored procedure richiedono una gestione autonoma, incluso il completamento dei risultati della procedura. Non dedurre il comportamento dei parametri di output da questi esempi basati solo sull'input. Per maggiori informazioni, vedi Utilizzo dei parametri direzionali.

Configurare il comportamento di esecuzione e fetch

Impostazione SQLSRV PDO_SQLSRV
Timeout di esecuzione QueryTimeout nell'array delle opzioni dello statement. PDO::SQLSRV_ATTR_QUERY_TIMEOUT sulla connessione o sull'istruzione.
Chiavi dei risultati denominate SQLSRV_FETCH_ASSOC passato a sqlsrv_fetch_array(). PDO::FETCH_ASSOC passato a un metodo di recupero o impostato come modalità di recupero predefinita della connessione.
Risultati solo in attacco Cursore predefinito; recupero in ordine. Cursore predefinito; recupero in ordine.
Risultati memorizzati nel buffer del client Scrollable => SQLSRV_CURSOR_CLIENT_BUFFERED. PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL con PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE => PDO::SQLSRV_CURSOR_BUFFERED.
Esecuzione diretta contro predefinita Nessun attributo PDO di query diretta. Scegli la chiamata combinata sqlsrv_query() o la coppia esplicita prepara/esegui. PDO::SQLSRV_ATTR_DIRECT_QUERY seleziona l'esecuzione diretta anziché l'esecuzione preparata predefinita del driver.
Emulazione dei parametri Nessun attributo di emulazione di PDO. PDO::ATTR_EMULATE_PREPARES è separato dall'attributo di consulta diretta. Non usarlo in sostituzione dell'associazione dei tipi corretti.

Gli esempi restituiscono risultati brevi. fetchAll() carica ogni riga nella memoria PHP; usa un ciclo di fetch per un set di risultati di grandi dimensioni. Una query che non restituisce corrispondenze non è un errore di esecuzione. SQLSRV riporta la fine del risultato come null da sqlsrv_fetch_array(); PDO lo riporta come false da fetch(). Un SQL NULL all'interno di una riga estratta rimane PHP null.

Non usare il SELECT numero di righe come unico controllo di successo. I cursori solo in avanti non offrono le stesse capacità di conteggio righe dei cursori bufferizzati o scorribili. Recupera e conta le righe di cui hai bisogno, oppure usa una query separata COUNT . Per opzioni e limitazioni specifiche per cursore, vedi Specificare un tipo di cursore e selezionare righe.

Gestire gli errori e finalizzare i risultati

Controlla separatamente le operazioni SQLSRV di preparazione, esecuzione e recupero. Un'operazione di prepare riuscita non dimostra che l'esecuzione avrà successo: il server può rifiutare valori di parametri, permessi o l'istruzione al momento dell'esecuzione. Cattura sqlsrv_errors() immediatamente quando un'operazione ritorna false. SQLSRV considera molti avvisi come errori di default, quindi ispeziona l'intera collezione.

Con PDO, i fallimenti di connessione e gli errori del database in modalità eccezioni generano PDOException. Ispezionare le informazioni sullo stato SQLSTATE e sugli errori del driver nelle diagnostiche di applicazione protetta; non restituire testo o credenziali di eccezione in una risposta HTTP. prepare() Avere successo non è la prova che l'istruzione sia già stata eseguita.

Sintomo Action
Ogni esecuzione utilizza il primo valore Per SQLSRV, associa una variabile per riferimento. Per il PDO, usa bindParam() per una variabile che cambia o chiama bindValue() per ogni nuovo valore.
Un parametro numerico viene rifiutato, come un numero di elementi TOP Associa esplicitamente il tipo intero richiesto. PDO execute([$value]) utilizza parametri stringa anche se il valore PHP è un intero.
Un secondo comando riporta risultati in sospeso Consuma i risultati o rilasciali prima di riutilizzare la connessione. Per il PDO, usa closeCursor() quando non hai bisogno del risultato residuo.
I parametri di output attesi non sono cambiati Completare tutti i risultati delle procedure e verificare la direzione dei parametri, il tipo PHP e la lunghezza del buffer di output.
L'uso della memoria cresce con la dimensione del risultato Sostituire fetchAll() o il buffering client non necessario con il recupero sequenziale.

Gli esempi liberano le istruzioni e chiudono le connessioni in finally. Non viene avviata alcuna transazione. Usa una transazione esplicita quando più scritture devono o essere confermate insieme o tutte essere annullate. Riutilizzare un'istruzione preparata non raggruppa le scritture in una transazione.

Differenze tra obiettivi e implementazione

Le API prepare/execute e le regole di riferimento di PHP appartengono alle estensioni e a PHP/PDO. Il target SQL decide quali istruzioni e tipi T-SQL sono supportati, e ODBC esegue la comunicazione sottostante. Preparare una volta può ridurre il lavoro ripetuto, ma non garantisce un determinato piano di esecuzione del server o una velocità specifica.

I pattern di input-binding si applicano a SQL Server, database SQL di Azure, Istanza gestita di SQL di Azure, Azure Synapse Analytics, database SQL in Microsoft Fabric e Warehouse in Microsoft Fabric. Questi programmi utilizzano l'autenticazione SQL per SQL Server. Per l'onboarding Azure, preferisci l'autenticazione Microsoft Entra. Entrambi i prodotti Fabric lo richiedono, e Warehouse richiede anche di disabilitare i Multiple Active Result Sets (MARS). Controlla il supporto del target selezionato per modifiche di schema, transazioni e stored procedure prima di riutilizzare il codice SQL Server. Per le differenze tra endpoint e autenticazione, vedi connessioni di Azure e Fabric.