Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Ambos os controladores podem executar uma instrução uma vez ou preparar uma instrução para execução repetida. Utilize parâmetros para os valores fornecidos pelos utilizadores, mesmo quando executa uma consulta apenas uma vez.
Escolha a API de execução separadamente de como obtém resultados. Preparar uma consulta não recupera as suas linhas, e armazenar um resultado em buffer não faz com que a consulta seja parametrizada. Os exemplos seguintes preparam uma consulta somente de leitura uma vez, executam-na duas vezes com valores diferentes e consomem cada resultado antes da próxima execução.
| Estilo de execução | SQLSRV | PDO_SQLSRV |
|---|---|---|
| Execute uma consulta uma vez, sem parâmetros | sqlsrv_query | PDO::query para resultados, ou PDO::exec para contagens de linhas afetadas |
| Execute uma consulta uma vez, com parâmetros | sqlsrv_query($conn, $sql, $params) |
PDO::prepare() seguido de PDOStatement::execute() |
| Preparar uma vez, executar repetidamente com diferentes parâmetros | sqlsrv_prepare + sqlsrv_execute | PDO::prepare + PDOStatement::execute |
sqlsrv_query() prepara e executa numa única chamada e devolve um recurso de instrução SQL.
sqlsrv_prepare() retorna um recurso de statement sem o executar; chama sqlsrv_execute() para cada execução. Os query() PDO executam e devolvem PDOStatement, enquanto exec() devolvem uma contagem de linhas afetadas em vez de um objeto de resultado. Um bem-sucedido exec() pode devolver 0, por isso compare um retorno de falha com === false, não if (!$count).
PDO::query() não aceita um array de valores de parâmetros. Os argumentos opcionais configuram o fetching. Para consultas PDO_SQLSRV parametrizadas, use prepare() e execute().
Preparar uma vez permite-te reutilizar um identificador de instrução com valores diferentes. Isto não garante que o servidor nunca recompile o seu plano de execução. PDO_SQLSRV usa a execução preparada por defeito, incluindo para PDO::query(); o seu atributo de consulta direta controla essa escolha separada.
Prepare uma vez e execute repetidamente
São programas de linha de comandos separados e completos. Instale e carregue a extensão selecionada, e defina SQL_SERVER, SQL_DATABASE, SQL_USER, e SQL_PASSWORD no ambiente de processo PHP. Use uma base de dados de teste SQL Server e um certificado de servidor confiável pelo cliente. Para a configuração do ambiente e alternativas sem palavra-passe, veja Ligação ao servidor.
Armazene o nome real da base de dados, nome de utilizador e palavra-passe nas variáveis de ambiente. Ambos os programas escapam estes valores uma vez, duplicando as chavetas de fecho e colocando cada valor entre chavetas, conforme exigido pelo tratamento de ligação ao estilo ODBC do controlador PHP. Escapar os valores de conexão é separado de associar parâmetros de consulta.
Os programas executam uma consulta Transact-SQL (T-SQL) sobre duas linhas inline sem criar uma tabela ou alterar dados. Guardar cada programa no seu próprio .php ficheiro e executá-lo com php <file>. Não é necessária nenhuma base de dados de exemplo.
SQLSRV
Passar $productId por referência com &$productId. Cada um sqlsrv_execute() utiliza então o seu valor atual.
SQLSRV_FETCH_ASSOC devolve um array indexado pelo nome da coluna. Um null resultado significa que não há mais linhas; false indica um erro.
<?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
Vincule $productId uma vez com bindParam(). Cada execute() lê o seu valor atual.
PDO::PARAM_INT especifica o tipo de ligação PHP/PDO do parâmetro; não controla o tipo PHP de colunas obtidas do resultado. Defina o modo de exceção para que um erro na base de dados interrompa a execução em vez de ser confundido com um resultado vazio.
<?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 exemplo imprime:
Bike
Helmet
Os valores num array passados para PDO execute() são tratados como PDO::PARAM_STR. Quando o SQL requer um parâmetro inteiro, como uma contagem parametrizada TOP , chame bindValue() com PDO::PARAM_INT e depois chame execute() sem um array.
Associe valores sem alterar a consulta
Um marcador de parâmetro representa um valor, não um nome de tabela, nome de coluna, palavra-chave ou direção de ordenação. Não coloque aspas à volta de ?. Para um identificador dinâmico ou ASC/DESC, selecione a partir de uma lista de permissão controlada pela aplicação em vez de concatenar texto não confiável. Para uma IN lista, fornece um marcador por valor.
| Requirement | SQLSRV | PDO_SQLSRV |
|---|---|---|
| Associar valores para uma execução | Passe o array de parâmetros para sqlsrv_query(). |
Passa um array para execute() depois de prepare(), ou atribui valores primeiro. |
| Reutilizar o valor atual de uma variável | Inclua &$variable no array fornecido a sqlsrv_prepare(). |
Chamar bindParam() com a variável, depois execute() sem um array. O PHP passa a variável por referência; não adicione & no local da chamada. |
| Associe um valor no momento da associação | Utilize um valor no array de parâmetros para a execução. | Chame bindValue(); alterações posteriores à variável original não alteram esse valor limitado. |
| Especifique uma entrada inteira | Utilize um descritor de parâmetro com SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_INT e SQLSRV_SQLTYPE_INT quando for necessário um tipo explícito. |
Vincular com PDO::PARAM_INT. Os índices posicionais bindParam() e bindValue() começam em 1, não 0. |
Enviar SQL NULL |
Vincule PHP null, com um tipo SQL explícito quando exigido pela operação. |
Associar a PDO::PARAM_NULL. |
| Receber parâmetros de saída | Utilize uma variável referenciada com SQLSRV_PARAM_OUT ou SQLSRV_PARAM_INOUT. |
Utilize bindParam() com PDO::PARAM_INPUT_OUTPUT e o tipo e comprimento necessários. |
Mantenha as variáveis referenciadas ativas durante a execução da instrução preparada. O programa SQLSRV altera a variável vinculada em vez de substituir o array de parâmetros. O programa PDO chama execute() deliberadamente sem array após a associação; não misture esse padrão com execução baseada em array.
Os valores de saída dos procedimentos armazenados requerem o seu próprio tratamento, incluindo a finalização dos resultados do procedimento. Não infiras comportamento dos parâmetros de saída a partir destes exemplos apenas de entrada. Para mais informações, veja Utilizar parâmetros direcionais.
Configurar o comportamento de execução e de busca
| Setting | SQLSRV | PDO_SQLSRV |
|---|---|---|
| Tempo limite de execução |
QueryTimeout no array de opções da instrução. |
PDO::SQLSRV_ATTR_QUERY_TIMEOUT na ligação ou instrução. |
| Chaves de resultado nomeadas |
SQLSRV_FETCH_ASSOC transmitido para sqlsrv_fetch_array(). |
PDO::FETCH_ASSOC passado para um método de fetch ou definido como modo de fetch predefinido da conexão. |
| Resultados só de avanço | Cursor padrão; buscar por ordem. | Cursor padrão; buscar por ordem. |
| Resultados em buffer do cliente |
Scrollable => SQLSRV_CURSOR_CLIENT_BUFFERED. |
PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL com PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE => PDO::SQLSRV_CURSOR_BUFFERED. |
| Execução direta versus preparada | Sem atributo de consulta direta do PDO. Escolha a chamada combinada sqlsrv_query() ou o par explícito preparar/executar. |
PDO::SQLSRV_ATTR_DIRECT_QUERY seleciona execução direta contra a execução preparada padrão do driver. |
| Emulação de parâmetro | Sem atributo de emulação PDO. |
PDO::ATTR_EMULATE_PREPARES é separado do atributo de consulta direta. Não o uses como substituto para associar os tipos corretos. |
Os exemplos devolvem pequenos resultados.
fetchAll() carrega cada linha na memória PHP; usa um loop de busca para um resultado grande. Uma consulta que não retorna correspondências não é um erro de execução. O SQLSRV reporta o final do resultado como null a partir de sqlsrv_fetch_array(); O PDO reporta como false a partir de fetch(). Um SQL NULL dentro de uma linha obtida mantém-se em PHP null.
Não uses a contagem SELECT de linhas como o teu único teste de sucesso. Os cursores apenas para avançar não oferecem as mesmas capacidades de contagem de linhas que os cursores em buffer ou scrolláveis. Busca e conta as linhas que precisas, ou usa uma consulta separada COUNT . Para opções e limitações específicas do cursor, consulte Especificar um tipo de cursor e selecionar linhas.
Lidar com falhas e resultados finais
Verifique separadamente as operações de preparação, execução e obtenção do SQLSRV. Um prepare bem-sucedido não prova que a execução será bem-sucedida: o servidor pode rejeitar valores de parâmetros, permissões ou a instrução no momento da execução. Capture sqlsrv_errors() imediatamente quando uma operação regressar false. O SQLSRV trata muitos avisos como erros por defeito, por isso inspecione a coleção completa.
Para PDO, falhas de ligação e erros de base de dados no modo de exceção lançam PDOException. Inspecionar o seu SQLSTATE e a informação de erro do driver nos diagnósticos de aplicação protegida; não devolver texto de exceção ou credenciais numa resposta HTTP.
prepare() Ter sucesso não é prova de que a declaração já tenha sido executada.
| Symptom | Action |
|---|---|
| Cada execução utiliza o primeiro valor | Para SQLSRV, atribui uma variável por referência. Para PDO, use bindParam() para uma variável variável ou chame bindValue() para cada novo valor. |
Um parâmetro numérico é rejeitado, como um número TOP |
Associe explicitamente o tipo inteiro necessário. O PDO execute([$value]) usa parâmetros de cadeia mesmo que o valor PHP seja um inteiro. |
| Um segundo comando reporta resultados pendentes | Consume os resultados ou liberte-os antes de reutilizar a ligação. Para PDO, usa closeCursor() quando não precisares do resultado restante. |
| Os parâmetros de saída esperados não mudaram | Complete todos os resultados do procedimento e verifique a direção dos parâmetros, o tipo PHP e o comprimento do buffer de saída. |
| O uso de memória aumenta com o tamanho do resultado | Substitua fetchAll() ou o buffering desnecessário do cliente por busca sequencial (fetching). |
Os exemplos libertam as suas instruções e libertam as suas conexões em finally. Eles não iniciam uma transação. Use uma transação explícita quando múltiplas escritas têm de fazer commit em conjunto ou todas ser revertidas. Reutilizar uma instrução preparada não agrupa as escritas numa transação.
Diferenças entre destinos e implementação
As APIs prepare/execute e as regras de referência de PHP/PDO pertencem às extensões e ao PHP/PDO. O destino SQL decide quais as instruções e tipos T-SQL suportados, e o ODBC executa a comunicação subjacente. Preparar uma vez pode reduzir o trabalho repetido, mas não garante um determinado plano de execução do servidor nem um aumento de desempenho.
Os padrões de ligação de entradas aplicam-se ao SQL Server, Base de Dados SQL do Azure, Azure SQL Managed Instance, Azure Synapse Analytics, base de dados SQL no Microsoft Fabric e Warehouse no Microsoft Fabric. Estes programas usam autenticação SQL para o SQL Server. Para integração no Azure, prefira autenticação Microsoft Entra. Ambos os produtos Fabric o exigem, e o Warehouse também exige desativar o Multiple Active Result Sets (MARS). Verifique o suporte do destino selecionado para alterações de esquema, transações e procedimentos armazenados antes de reutilizar o código do SQL Server. Para diferenças de endpoint e autenticação, veja Azure e Fabric ligações.