Comparación de las funciones de ejecución

Descargar controlador PHP

Ambos controladores pueden ejecutar una sentencia una vez o preparar una sentencia para su ejecución repetida. Usa parámetros para los valores proporcionados por los usuarios, incluso cuando ejecutas una consulta solo una vez.

Elige la API de ejecución por separado de cómo obtienes los resultados. Preparar una consulta no recupera sus filas, y almacenar un resultado en búfer no hace que una consulta esté parametrizada. Los siguientes ejemplos preparan una consulta de solo lectura una vez, la ejecutan dos veces con valores diferentes y consumen cada resultado antes de la siguiente ejecución.

Estilo de ejecución SQLSRV PDO_SQLSRV
Ejecuta una consulta una vez, sin parámetros sqlsrv_query PDO::query para resultados, o PDO::exec para conteos de filas afectadas
Ejecuta una consulta una vez, con parámetros sqlsrv_query($conn, $sql, $params) PDO::prepare() seguido de PDOStatement::execute()
Prepara una vez, ejecuta repetidamente con diferentes parámetros sqlsrv_prepare + sqlsrv_execute PDO::prepare + PDOStatement::execute

sqlsrv_query() se prepara y ejecuta en una sola llamada y devuelve un recurso de instrucción. sqlsrv_prepare() devuelve un recurso de instrucción sin ejecutarlo; llama a sqlsrv_execute() en cada ejecución. El query() de PDO ejecuta y devuelve PDOStatement, mientras que exec() devuelve un conteo de filas afectadas en lugar de un objeto de resultado. Una llamada correcta a exec() puede devolver 0, así que compare un valor devuelto en caso de error con === false, no con if (!$count).

PDO::query() no acepta un array de valores de parámetros. Sus argumentos opcionales configuran la obtención. Para consultas PDO_SQLSRV parametrizadas, use prepare() y execute().

Preparar una vez te permite reutilizar un controlador de sentencia con valores diferentes. Esto no garantiza que el servidor nunca recompile su plan de ejecución. PDO_SQLSRV utiliza ejecución preparada por defecto, incluyendo para PDO::query(); su atributo de consulta directa controla esa elección separada.

Prepara una vez y ejecuta repetidamente

Estos son programas de línea de comandos completos y separados. Instala y carga la extensión seleccionada, y establece SQL_SERVER, SQL_DATABASE, SQL_USER, y SQL_PASSWORD en el entorno de proceso PHP. Utiliza una base de datos de prueba de SQL Server y un certificado de servidor en el que el cliente confíe. Para la configuración del entorno y alternativas sin contraseña, véase Conectarse al servidor.

Almacena el nombre real de la base de datos, nombre de usuario y contraseña en las variables de entorno. Ambos programas escapan estos valores una vez duplicando las llaves de cierre y encerrando cada valor entre llaves, como requiere el manejo de conexiones de estilo ODBC del controlador PHP. El escape de los valores de conexión es independiente de vincular los parámetros de consulta.

Los programas ejecutan una consulta Transact-SQL (T-SQL) sobre dos filas en línea sin crear una tabla ni cambiar datos. Guarda cada programa en su propio .php archivo y ejecútalo con php <file>. No se requiere ninguna base de datos de muestras.

SQLSRV

Pasar $productId por referencia con &$productId. Cada sqlsrv_execute() utiliza entonces su valor actual. SQLSRV_FETCH_ASSOC devuelve un array indexado por nombre de columna. Un resultado null significa que no hay más filas; false indica un error.

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

Vincula $productId una vez con bindParam(). Cada execute() lee su valor actual. PDO::PARAM_INT especifica el tipo de enlace PHP/PDO del parámetro; no controla el tipo PHP de columnas obtenidas del resultado. Establece el modo de excepción para que un error de base de datos interrumpa la ejecución en lugar de confundirse con un resultado vacío.

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

Cada ejemplo imprime:

Bike
Helmet

Los valores en un array que se pasan a execute() de PDO se tratan como PDO::PARAM_STR. Cuando SQL requiere un parámetro entero, como un recuento parametrizado TOP, llame a bindValue() con PDO::PARAM_INT y luego llame a execute() sin un array.

Vincular valores sin cambiar la consulta

Un marcador de parámetro representa un valor, no un nombre de tabla, nombre de columna, palabra clave o dirección de ordenación. No pongas comillas alrededor ?. Para un identificador dinámico o ASC/DESC, selecciona de una lista de elementos permitidos controlada por la aplicación en lugar de concatenar texto no confiable. Para una IN lista, proporciona un marcador por valor.

Requirement SQLSRV PDO_SQLSRV
Vincular valores para una ejecución Pasa el array de parámetros a sqlsrv_query(). Pasa un array a execute() después de prepare(), o asigna valores primero.
Reutilizar el valor actual de una variable Incluye &$variable en el array suministrado a sqlsrv_prepare(). Llama bindParam() con la variable, luego execute() sin un array. PHP pasa la variable por referencia; no añadas & en el sitio de llamada.
Vincular un valor al realizar la vinculación Usa un valor en el array de parámetros para la ejecución. Llama bindValue(); los cambios posteriores a la variable original no cambian ese valor vinculado.
Especificar una entrada entera Utiliza un descriptor de parámetro con SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_INT, y SQLSRV_SQLTYPE_INT cuando se necesite un tipo explícito. Vincule con PDO::PARAM_INT. Los índices posicionales bindParam() y bindValue() comienzan en 1, no 0.
Enviar SQL NULL Asigna PHP nullcon un tipo SQL explícito cuando la operación lo requiera. Vincule con PDO::PARAM_NULL.
Recibir parámetros de salida Utiliza una variable referenciada con SQLSRV_PARAM_OUT o SQLSRV_PARAM_INOUT. Usa bindParam() con PDO::PARAM_INPUT_OUTPUT y el tipo y longitud requeridos.

Mantén activas las variables de referencia al ejecutar la sentencia preparada. El programa SQLSRV cambia la variable vinculada en lugar de reemplazar el array de parámetros. El programa PDO llama execute() deliberadamente sin un array tras el enlace; no mezcles ese patrón con la ejecución basada en array.

Los valores de salida de los procedimientos almacenados requieren su propio manejo, incluida la finalización del procesamiento de los resultados del procedimiento. No infieras comportamiento de parámetros de salida a partir de estos ejemplos solo de entrada. Para más información, véase Uso de los parámetros direccionales.

Configurar el comportamiento de ejecución y recuperación

Setting SQLSRV PDO_SQLSRV
Tiempo de espera de ejecución QueryTimeout en el conjunto de opciones de sentencias. PDO::SQLSRV_ATTR_QUERY_TIMEOUT en la conexión o instrucción.
Claves de resultado con nombre SQLSRV_FETCH_ASSOC se pasó a sqlsrv_fetch_array(). PDO::FETCH_ASSOC pasada a un método de búsqueda o establecida como modo de búsqueda predeterminada de la conexión.
Resultados solo en delanteros Cursor por defecto; buscar en orden. Cursor por defecto; obtener en orden.
Resultados almacenados en búfer en el cliente Scrollable => SQLSRV_CURSOR_CLIENT_BUFFERED. PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL con PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE => PDO::SQLSRV_CURSOR_BUFFERED.
Ejecución directa frente a ejecución preparada No existe el atributo de consulta directa de PDO. Elige la llamada combinada sqlsrv_query() o el par explícito prepare/execute. PDO::SQLSRV_ATTR_DIRECT_QUERY selecciona la ejecución directa frente a la ejecución preparada por defecto del controlador.
Emulación de parámetros Sin atributo de emulación de PDO. PDO::ATTR_EMULATE_PREPARES es independiente del atributo de consulta directa. No lo uses como sustituto de encuadernar los tipos correctos.

Los ejemplos demuestran resultados pequeños. fetchAll() carga cada fila en memoria PHP; utiliza un bucle de búsqueda para un conjunto de resultados grande. Una consulta que no devuelve coincidencias no es un error de ejecución. SQLSRV informa del final del resultado como null de sqlsrv_fetch_array(); PDO lo informa como false de fetch(). Un SQL NULL dentro de una fila obtenida sigue siendo PHP null.

No utilices el conteo SELECT de filas como única comprobación de éxito. Los cursores solo hacia adelante no ofrecen las mismas capacidades de conteo de filas que los cursores con búfer o desplazables. Busca y cuenta las filas que necesitas, o usa una consulta aparte COUNT . Para opciones y limitaciones específicas del cursor, consulte Especificar un tipo de cursor y seleccionar filas.

Gestionar fallos y resultados finales

Comprueba las operaciones de preparación SQLSRV, ejecución y obtención por separado. Una preparación exitosa no demuestra que la ejecución tendrá éxito: el servidor puede rechazar valores de parámetros, permisos o la sentencia en el momento de ejecución. Captura sqlsrv_errors() inmediatamente cuando una operación devuelva false. SQLSRV trata muchas advertencias como errores por defecto, así que inspecciona la colección completa.

Para PDO, los fallos de conexión y errores de base de datos en modo excepción lanzan PDOException. Inspeccionar su estado SQLSTATE y la información de error del controlador en el diagnóstico de aplicación protegida; no devolver el texto de excepción ni las credenciales en una respuesta HTTP. prepare() Tener éxito no es prueba de que la instrucción ya se haya ejecutado.

Síntoma Action
Cada ejecución utiliza el primer valor Para SQLSRV, vincula una variable por referencia. Para PDO, usa bindParam() para una variable cambiante o llama a bindValue() para cada nuevo valor.
Se rechaza un parámetro numérico, como un recuento TOP Vincula explícitamente el tipo entero requerido. PDO execute([$value]) utiliza parámetros de cadena incluso si el valor de PHP es un entero.
Un segundo comando informa de resultados pendientes Consume los resultados o libéralos antes de reutilizar la conexión. Para PDO, usa closeCursor() cuando no necesites el resultado restante.
Los parámetros de salida esperados no han cambiado Completar todos los resultados del procedimiento y verificar la dirección del parámetro, el tipo de PHP y la longitud del búfer de salida.
El uso de memoria crece con el tamaño del resultado Sustituye fetchAll() o el buffering innecesario del cliente por la obtención secuencial.

Los ejemplos cierran sus instrucciones y cierran sus conexiones en finally. No inician una transacción. Utiliza una transacción explícita cuando varias escrituras deben hacer commit juntas o revertir todas. Reutilizar una sentencia preparada no agrupa las operaciones de escritura en una transacción.

Diferencias entre objetivo e implementación

Las APIs de preparación/ejecución y las reglas de referencia de PHP pertenecen a las extensiones y a PHP/PDO. El destino SQL decide qué sentencias y tipos de T-SQL son compatibles, y ODBC realiza la comunicación subyacente. Prepararlo una vez puede reducir el trabajo repetido, pero no garantiza un plan de ejecución del servidor específico ni una aceleración.

Los patrones de enlace de entrada se aplican a SQL Server, Azure SQL Database, Azure SQL Managed Instance, Azure Synapse Analytics, base de datos SQL en Microsoft Fabric y Warehouse en Microsoft Fabric. Estos programas utilizan autenticación SQL para SQL Server. Para la incorporación en Azure, prefiero la autenticación Microsoft Entra. Ambos productos Fabric lo requieren, y Warehouse también requiere desactivar los Múltiples Conjuntos Activos de Resultados (MARS). Comprueba el soporte del destino seleccionado para cambios de esquema, transacciones y procedimientos almacenados antes de reutilizar el código de SQL Server. Para diferencias entre endpoint y autenticación, véase conexiones Azure y Fabric.