Перейти к содержимому
Поиск
Php Разработка

PHP: полный мануал с примерами, функциями и ООП

Практический мануал PHP: от переменных и читаемого кода до безопасных форм, интеграций, базы данных и ООП на примере магазина. Учебный маршрут, поиск функций, подробные примеры, разбор ошибок и исходники для скачивания.

Александр НекрасовИзменено:
Практический мануал PHP: от переменных и функций к объектной модели интернет-магазина
PHP 8.5.11468 глав6256 карточек справочника
Дерево руководства

Глава 50 · После массивов и первой SQL-выборки; каждый новый вызов объясняется перед полным файлом

SQL Server: соединение, накладная и понятная диагностика

Открыть отдельный SQL Server через SQLSRV, прочитать накладную, отличить неверную базу от ошибки столбца и показать неполную сумму платежей независимо от доступности предупреждений. Полные контракты семи функций соединения и настройки.

От накладной до правильного соединения

Поставщик хранит накладные в Microsoft SQL Server. PHP-странице нужна одна накладная: номер, получатель и сумма. Первый результат этой главы — прочитанный документ вместе с подтверждением выбранной базы. Затем разберём два реальных отказа — ошибочное имя базы и неверный столбец — так, чтобы первоначальная причина не терялась за вторичным сообщением «ожидался ресурс». Последний отчёт сохранит сумму и покажет, как не потерять сведения о NULL, даже если драйвер не вернул предупреждение.

От страницы к нужной накладной
  1. PHP вызывает sqlsrv_connect с именем сервера и Database
  2. Расширение SQLSRV обращается к Microsoft ODBC Driver
  3. ODBC устанавливает соединение с выбранным SQL Server
  4. sqlsrv_query передаёт запрос к одной собственной таблице
  5. sqlsrv_fetch_array получает нужную строку как массив PHP
  6. HTML показывает номер и сумму; ресурсы закрываются

Это цепочка из разных компонентов. PHP выполняет программу; SQLSRV даёт функции sqlsrv_*; ODBC связывает драйвер с сервером; SQL Server хранит таблицы и выполняет SQL. У каждого своя версия. База объединяет объекты, таблица задаёт столбцы, строка хранит одну накладную. Представьте адрес: экземпляр сервера → база → схема dbo → таблица → запись. Такая модель объясняет выбор имён; она не означает, что PHP открывает серверный файл базы как текст.

Первый шаг: увидеть, что соединение получилось

Предположим, учебный экземпляр и база уже подготовлены по README. Переменная $conn сохранит результат вызова. Строка в первом аргументе задаёт экземпляр, массив во втором — базу и кодировку. Оператор => связывает имя настройки с её значением. Двойной обратный слеш в одинарно заключённой PHP-строке даёт один слеш в имени экземпляра.

$conn = sqlsrv_connect('(localdb)\\AENPHPManual149', [
    'Database' => 'phpmanual149',
    'CharacterSet' => 'UTF-8',
]);
if ($conn === false) {
    echo 'Подключение не выполнено';
} else {
    echo 'Соединение готово';
    sqlsrv_close($conn);
}

Это минимальный контекстный фрагмент для указанной локальной подготовки, а не универсальный адрес любого SQL Server. === false проверяет именно неуспех. Ресурс $conn — служебный дескриптор открытого соединения, а не массив накладных и не объект PDO. Успешная ветка выводит «Соединение готово», но ещё ничего не выбирает. Полные файлы ниже не скрывают отказ под готовым результатом.

Нужная база должна существовать заранее: ключ Database выбирает её, а не создаёт. Без UID/PWD обычное локальное подключение использует Windows Authentication под учётной записью запуска PHP. Если нужен SQL-логин, UID и PWD передаются вместе из закрытой настройки. В архиве нет чужих паролей. На веб-сервере действует его учётная запись; успешный вход вашей программы в терминале не доказывает права IIS.

Следующий шаг: строка документа и её столбцы

$stmt = sqlsrv_query($conn,
    'SELECT invoice_no, customer_name, total FROM '.$qualified.' WHERE invoice_no = ?',
    ['INV-149']);
if ($stmt === false) {
    $diagnostics = sqlsrv_errors(SQLSRV_ERR_ALL);
    throw new RuntimeException('Накладную прочитать не удалось');
}
$invoice = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);

В этом фрагменте $conn ещё открыт, а $qualified — проверенное имя таблицы, созданной полным примером. Список после SELECT выбирает поля экрана; WHERE оставляет нужный номер. Знак ? занимает место одного значения, которое передаётся отдельным массивом. Он не заменяет имя таблицы. query подготавливает и выполняет запрос, а fetch_array читает одну строку. SQLSRV_FETCH_ASSOC даёт ключи invoice_no, customer_name и total. После этого нужно отдельно различить строку, null в конце результата и false при ошибке чтения.

Если SQL пока незнаком, сначала пройдите таблицу, соединение и первую выборку; устройство ассоциативного массива объясняет полученную строку. Следующая глава параметры и типы результатов SQLSRV разбирает точную цену, Unicode и даты. Название SQLSRV не делает mysqli, mysql_xdevapi и PDO_SQLSRV взаимозаменяемыми: у них разные вызовы и типы результатов.

Что нужно для самостоятельного запуска

Нужны совместимые PHP и расширение sqlsrv, Microsoft ODBC Driver и настоящий SQL Server с отдельной учебной базой. Для Windows проверяются версия PHP, разрядность и TS/NTS; наличие DLL в папке ещё не означает её загрузку. Расширение pdo_sqlsrv предоставляет другой API и не создаёт функции sqlsrv_connect. Матрица совместимости и имена сборок Microsoft. Точные команды выбранного окружения приведены в README самостоятельных архивов.

Эта глава учит подключениям и диагностике, а не выдаче административных прав. Полные программы создают только свои таблицы внутри выделенной учебной базы и удаляют их в finally. Сценарий отсутствующей базы таблиц не создаёт. Удаление учебных объектов — явная уборка, а не действие close. Обработчик finally также не исправляет ошибку запроса: неуспешный запуск остаётся неуспешным.

Почему сообщения нужно сохранять сразу

Первоначальная ошибка не должна теряться
  1. Вызов query получает неверное имя столбца → false
  2. Сразу errors(ALL) → сохраняем массив в PHP
  3. Только затем исправляем запрос и выполняем следующий вызов
  4. Новое успешное чтение даёт накладную
  5. Отчёт отдельно показывает сохранённую причину и исправленный результат

Массив диагностики — временный снимок последней операции драйвера. В нём могут быть несколько сообщений с разными кодами. Не пытайтесь извлечь исходную ошибку после close или другой операции. Сообщение посетителю и запись для разработчика имеют разные задачи: странице достаточно «Накладная временно недоступна», а разработчику нужны сохранённые SQLSTATE, код и контекст. Полный текст с адресами или данными не публикуется автоматически.

Что входит в этот маршрут

Официальная книга SQLSRV относится к доступу к Microsoft SQL Server и Azure SQL. Её вводная описывает выпуск 3.0 и поддержку SQL Server начиная с 2005, включая SQL Server 2012/LocalDB. Это сохранённый исторический контекст, а не рекомендация ставить старые серверы или утверждение о поддержке их современным драйвером. Расширение поддерживает Microsoft.

Здесь подробно разобраны connect, close, client_info, server_info, errors, configure и get_config. В связанной главе находятся query, prepare, execute, field_metadata, fetch_array, free_stmt и rows_affected. Остальные страницы официальной книги — транзакции, курсоры, потоки, следующие результаты, fetch_object и другие — остаются отдельными темами. Наличие этого обзора в дереве не означает, что вся книга SQLSRV уже наполнена.

Прочитать накладную и подтвердить, к какой базе подключился PHP

Перед переносом отчёта нужно проверить не только надпись «подключено», но и реальный документ в выбранной базе. Создадим свою учебную таблицу с накладной INV-149 для «Мастерской Север», прочитаем сумму 419.50 и приложим сведения о клиентском стеке и сервере. Затем закроем соединение: готовые данные останутся в PHP.

Что делает программа
  1. В phpmanual149 создаётся собственная таблица накладных
  2. Вставляется INV-149 / Мастерская Север / 419.50
  3. client_info описывает PHP SQLSRV и ODBC; server_info — сервер и базу
  4. SELECT по invoice_no читает только нужные три поля
  5. Массив $saved сохраняет строку; учебная таблица удаляется
  6. close завершает соединение, а отчёт использует уже прочитанные значения

Сначала короткий вызов

$server = sqlsrv_server_info($db);
if ($server === false) {
    throw new RuntimeException('Нет сведений о сервере');
}
echo $server['CurrentDatabase']; // phpmanual149

$db здесь уже хранит открытое учебное соединение из начала полного файла. server_info возвращает массив: квадратные скобки выбирают поле CurrentDatabase. Сначала проверяем false, затем обращаемся к ключу. В полной программе это проверка адреса перед чтением настоящей накладной; версии и имя сервера не подставляются заранее.

Какой результат получится

НаблюдениеРезультат
База накладнойphpmanual149
НомерINV-149
ПолучательМастерская Север
Сумма419.50
Прочитана ровно одна строкада
Четыре поля клиентского стека полученыда
Соединение закрытода
Накладная доступна после закрытияда
Полная программа и архив для самостоятельного запуска
Прочитать накладную и подтвердить, к какой базе подключился PHPСамостоятельный пример
<?php
declare(strict_types=1);
require __DIR__.'/lab.php';
$db=$config=null;$owned=$removed=$rows=$checks=$observations=[];
$runtime=s149Runtime();
try {

    $config=s149Config();$db=s149Connect($config);$runtime=s149Runtime($db,$config);
    $name = s149OwnTable($db, $owned, 'connection_receipt',
        '(invoice_no VARCHAR(20) PRIMARY KEY, customer_name NVARCHAR(80) NOT NULL, total DECIMAL(12,2) NOT NULL)');
    $qualified = s149Qualified($name);
    s149Command($db, 'INSERT INTO '.$qualified.' (invoice_no, customer_name, total) VALUES (?, ?, ?)',
        ['INV-149', 'Мастерская Север', '419.50']);
    $client = sqlsrv_client_info($db);
    if ($client === false) { s149Failure('Сведения о клиенте недоступны'); }
    $server = sqlsrv_server_info($db);
    if ($server === false) { s149Failure('Сведения о сервере недоступны'); }
    $stmt = sqlsrv_query($db,
        'SELECT invoice_no, customer_name, total FROM '.$qualified.' WHERE invoice_no = ?',
        ['INV-149'], ['QueryTimeout'=>10]);
    if ($stmt === false) { s149Failure('Накладная не прочитана'); }
    try {
        $invoice = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
        if ($invoice === false) { s149Failure('Ошибка чтения накладной'); }
        if ($invoice === null) { throw new RuntimeException('Накладная не найдена'); }
        $end = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
        if ($end === false) { s149Failure('Ошибка проверки конца результата'); }
    } finally {
        sqlsrv_free_stmt($stmt);
    }
    $clientKeys = ['DriverDllName','DriverODBCVer','DriverVer','ExtensionVer'];
    $clientFieldsPresent = count(array_diff($clientKeys, array_keys($client))) === 0;
    $clientNonEmpty = $clientFieldsPresent;
    foreach ($clientKeys as $key) {
        $clientNonEmpty = $clientNonEmpty && is_string($client[$key] ?? null) && $client[$key] !== '';
    }
    $saved = $invoice;
    $serverReceipt = ['database'=>$server['CurrentDatabase'], 'server_version'=>$server['SQLServerVersion'],
        'server_name_present'=>is_string($server['SQLServerName']) && $server['SQLServerName'] !== ''];
    $removed = s149Cleanup($db, $owned);
    $closed = sqlsrv_close($db);
    $closedType = get_debug_type($db);
    $rows = [['База накладной', $serverReceipt['database']], ['Номер', $saved['invoice_no']],
        ['Получатель', $saved['customer_name']], ['Сумма', $saved['total']],
        ['Прочитана ровно одна строка', $end === null], ['Четыре поля клиентского стека получены', $clientNonEmpty],
        ['Соединение закрыто', $closed === true && !is_resource($db)],
        ['Накладная доступна после закрытия', $saved === $invoice]];
    $checks = ['database'=>$serverReceipt['database'] === 'phpmanual149',
        'invoice'=>$invoice === ['invoice_no'=>'INV-149','customer_name'=>'Мастерская Север','total'=>'419.50'],
        'eof'=>$end === null, 'client_fields'=>$clientNonEmpty,
        'extension_version'=>$client['ExtensionVer'] === phpversion('sqlsrv'),
        'server_fields'=>$serverReceipt['server_name_present'] && is_string($serverReceipt['server_version'])
            && $serverReceipt['server_version'] !== '',
        'closed'=>$closed === true && !is_resource($db), 'saved_after_close'=>$saved === $invoice];
    $observations = ['invoice'=>$invoice, 'client'=>$client, 'server'=>$serverReceipt,
        'close_return'=>$closed, 'caller_type_after_close'=>$closedType, 'eof_type'=>get_debug_type($end)];
} finally {
    if (is_resource($db)) {try {$removed=s149Cleanup($db,$owned);} finally {sqlsrv_close($db);}}
}
s149Report('sqlsrv149-connection-receipt', 'Прочитать накладную и подтвердить, к какой базе подключился PHP', $rows, $checks, $observations, $runtime, $owned, $removed);
Ожидаемый результат
База накладной — phpmanual149
Номер — INV-149
Получатель — Мастерская Север
Сумма — 419.50
Прочитана ровно одна строка — да
Четыре поля клиентского стека получены — да
Соединение закрыто — да
Накладная доступна после закрытия — да

Распакуйте архив отдельно и выполните example.php по README.txt. lab.php содержит открытый код подготовки учебной среды, ограничения собственных имён и сохранения отчётов. Используется настоящий SQL Server; новая таблица получает случайное собственное имя и удаляется после проверки. Отсутствующая база не создаётся. result.html и result.json сохраняют фактические данные, metrics.json — проверки.

Открыть таблицу сохранённого запуска · Данные и диагностические наблюдения JSON.

Границы и ошибки

Программа создаёт пример данных, а не ищет накладную в чужой базе. На рабочем сайте таблицы существуют постоянно; учебную уборку переносить туда не нужно. Имя таблицы формируется lab.php только в разрешённой области, а номер накладной передаётся отдельным параметром. Получение server_info не заменяет проверку строки: можно успешно подключиться к неправильной базе. DECIMAL сохраняется строкой, чтобы цена не зависела от двоичного округления float. Версии драйверов выводятся в наблюдениях фактически, поэтому у другой установки они могут отличаться. Сначала освобождается statement, затем собственная таблица, затем соединение; массив PHP остаётся доступным.

Измените одно требование

Измените номер вставляемой накладной на INV-150. Что произойдёт, если параметр SELECT останется INV-149?

Что должно измениться

Запрос выполнится, но первая строка будет null: это «документ не найден», а не ошибка подключения. В файле такая ситуация отдельно останавливает сценарий. Для нового документа нужно согласованно изменить вставку, параметр выборки и ожидаемые значения; нельзя подменять отсутствие строки пустой накладной.

Отличить недоступную базу от ошибки запроса и восстановить правильное подключение

После переноса приложения в настройке Database осталось старое имя. Переписывать SELECT в этой ситуации бесполезно: до запроса дело не дошло. Покажем контролируемый отказ входа в отсутствующую учебную базу, сохраним причину и затем подключимся к настоящей phpmanual149, подтвердив её имя двумя независимыми API-вызовами.

Что делает программа
  1. Проверяем, что phpmanual149_missing действительно отсутствует
  2. Меняем только Database, остальные настройки сервера сохраняем
  3. connect возвращает false; сразу сохраняем SQLSTATE и code
  4. Исправляем Database и открываем новое соединение
  5. server_info и SELECT DB_NAME() оба показывают phpmanual149
  6. Закрываем соединение; создавать и удалять базы не потребовалось

Сначала короткий вызов

$options = $config['options'];
$options['Database'] = 'phpmanual149_missing';
$attempt = sqlsrv_connect($config['server'], $options);
$savedDiagnostics = sqlsrv_errors(SQLSRV_ERR_ALL);

$config поступает из lab.php и содержит адрес отдельного LocalDB, имя базы и открыто описанные настройки. Копия $options позволяет изменить один ключ, не испортив правильную конфигурацию. После connect сразу сохраняется диагностика; если передать false в query, получится лишь вторичная ошибка аргумента.

Какой результат получится

НаблюдениеРезультат
Имя ошибочной базы заранее свободнода
Подключение к отсутствующей базе вернуло falseда
Первоначальная диагностика сохраненада
У диагностики был текст причиныда
База после исправленияphpmanual149
server_info подтверждает ту же базуда
Учебные таблицы не создавалисьда
Полная программа и архив для самостоятельного запуска
Отличить недоступную базу от ошибки запроса и восстановить правильное подключениеСамостоятельный пример
<?php
declare(strict_types=1);
require __DIR__.'/lab.php';
$db=$config=null;$owned=$removed=$rows=$checks=$observations=[];
$runtime=s149Runtime();
try {
    $config = s149Config();
    $db = s149Connect($config);
    $runtime = s149Runtime($db, $config);
    $missingName = 'phpmanual149_missing';
    $preflight = s149Read($db, 'SELECT DB_ID(?) AS database_id', [$missingName])[0];
    if ($preflight['database_id'] !== null) {
        throw new RuntimeException('Имя для опыта уже занято; существующую базу не изменяем');
    }
    sqlsrv_close($db);
    $wrongOptions = $config['options'];
    $wrongOptions['Database'] = $missingName;
    $missing = sqlsrv_connect($config['server'], $wrongOptions);
    $rawDiagnostics = sqlsrv_errors(SQLSRV_ERR_ALL);
    $diagnostics = s149Diagnostics($rawDiagnostics);
    $hasMessage = is_array($rawDiagnostics) && count($rawDiagnostics) > 0;
    foreach ($rawDiagnostics ?? [] as $item) {
        $hasMessage = $hasMessage && is_string($item['message'] ?? null) && $item['message'] !== '';
    }
    if ($missing !== false) {
        sqlsrv_close($missing);
        throw new RuntimeException('Ожидаемая отсутствующая база неожиданно открылась');
    }
    $db = sqlsrv_connect($config['server'], $config['options']);
    if ($db === false) { s149Failure('Подключение с правильным именем не восстановлено'); }
    $runtime = s149Runtime($db, $config);
    $server = sqlsrv_server_info($db);
    if ($server === false) { s149Failure('Текущая база не определена'); }
    $stmt = sqlsrv_query($db, 'SELECT DB_NAME() AS database_name', [], ['QueryTimeout'=>10]);
    if ($stmt === false) { s149Failure('Контекст соединения не прочитан'); }
    try {
        $context = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
        if ($context === false) { s149Failure('Контекст соединения не получен'); }
        if ($context === null) { throw new RuntimeException('Контекст соединения пуст'); }
    } finally {
        sqlsrv_free_stmt($stmt);
    }
    $rows = [['Имя ошибочной базы заранее свободно', $preflight['database_id'] === null],
        ['Подключение к отсутствующей базе вернуло false', $missing === false],
        ['Первоначальная диагностика сохранена', count($diagnostics) > 0],
        ['У диагностики был текст причины', $hasMessage],
        ['База после исправления', $context['database_name']],
        ['server_info подтверждает ту же базу', $server['CurrentDatabase'] === $context['database_name']],
        ['Учебные таблицы не создавались', count($owned) === 0]];
    $checks = ['missing_name_free'=>$preflight['database_id'] === null, 'failed_connect'=>$missing === false,
        'diagnostics_saved'=>count($diagnostics) > 0, 'messages_present'=>$hasMessage,
        'recovered_context'=>$context === ['database_name'=>'phpmanual149'],
        'server_agrees'=>$server['CurrentDatabase'] === 'phpmanual149', 'no_tables'=>$owned === []];
    $observations = ['missing_database'=>$missingName, 'failed_connect_type'=>get_debug_type($missing),
        'failure_diagnostics'=>$diagnostics, 'raw_messages_were_nonempty'=>$hasMessage,
        'recovered_context'=>$context, 'current_database'=>$server['CurrentDatabase']];
} finally {
    if (is_resource($db)) {try {$removed=s149Cleanup($db,$owned);} finally {sqlsrv_close($db);}}
}
s149Report('sqlsrv149-missing-database', 'Отличить недоступную базу от ошибки запроса и восстановить правильное подключение', $rows, $checks, $observations, $runtime, $owned, $removed);
Ожидаемый результат
Имя ошибочной базы заранее свободно — да
Подключение к отсутствующей базе вернуло false — да
Первоначальная диагностика сохранена — да
У диагностики был текст причины — да
База после исправления — phpmanual149
server_info подтверждает ту же базу — да
Учебные таблицы не создавались — да

Распакуйте архив отдельно и выполните example.php по README.txt. lab.php содержит открытый код подготовки учебной среды, ограничения собственных имён и сохранения отчётов. Используется настоящий SQL Server; новая таблица получает случайное собственное имя и удаляется после проверки. Отсутствующая база не создаётся. result.html и result.json сохраняют фактические данные, metrics.json — проверки.

Открыть таблицу сохранённого запуска · Данные и диагностические наблюдения JSON.

Границы и ошибки

Коды и число диагностических записей могут зависеть от способа входа и версии SQL Server. Здесь они сохраняются фактически, а не заменяются заранее написанным сообщением. Не делайте вывод «такой базы нет» по любому отказу connect: причиной также бывают права, имя экземпляра, транспорт или сертификат. В этом опыте отсутствие имени отдельно проверено в собственной учебной среде. Ошибочную базу программа не создаёт. Текст диагностик проверяется внутри, но в публичный JSON попадают только SQLSTATE/code: сообщение может раскрыть имя машины или учётную запись.

Запрос работает в SQL Server Management Studio, а в PHP следующий вызов получает не ресурс соединения. Практическая проблема на Stack Overflow. Отделяем установление соединения от выполнения SQL: сначала проверяем результат connect, сохраняем его диагностику и только при успехе передаём ресурс дальше. Успех запроса в другом приложении не подтверждает настройки этого PHP.

Измените одно требование

Что изменится, если сразу передать Database=phpmanual149 и не выполнять ошибочную попытку?

Что должно измениться

Получится обычное успешное подключение; диагностический массив может быть null. Проверки этого учебного отказа нужно убрать или заменить проверкой успеха, а не требовать обязательного сообщения об ошибке от корректного вызова.

Сохранить ошибку столбца и после исправления получить правильную накладную

В отчёте опечатка: вместо total написано totla. Нужно получить понятную первоначальную причину, исправить поле и увидеть настоящую сумму накладной. Сценарий показывает и отказ, и успешное продолжение; ошибка не заменяется пустым массивом данных.

Что делает программа
  1. Таблица содержит invoice_no и total; totla в ней нет
  2. Первый query возвращает false
  3. errors(ALL) немедленно копируется в $saved
  4. Исправленный SELECT использует total и читает INV-149
  5. Текущая диагностика успешного запроса уже пустая
  6. Сохранённый массив прежнего отказа остаётся доступным рядом с суммой 419.50

Сначала короткий вызов

$stmt = sqlsrv_query($db, 'SELECT totla FROM '.$qualified);
if ($stmt === false) {
    $saved = sqlsrv_errors(SQLSRV_ERR_ALL);
    // Сначала сохранить причину, потом другие вызовы SQLSRV.
}

Возврат false относится к выполнению этого запроса. $saved — обычный массив PHP, в котором остаются записи о причине. Нельзя передавать $stmt=false в fetch_array и надеяться получить эту же причину: это другая неправильная операция. Полная программа создаёт таблицу, поэтому известно, что опечатка — единственный запланированный дефект.

Какой результат получится

НаблюдениеРезультат
Запрос с totla вернул falseда
Причина сохранена до исправленного запросада
Сохранённая диагностика не потерянада
У исправленного запроса нет диагностикида
Номер из исправленного результатаINV-149
Сумма из базы419.50
Полная программа и архив для самостоятельного запуска
Сохранить ошибку столбца и после исправления получить правильную накладнуюСамостоятельный пример
<?php
declare(strict_types=1);
require __DIR__.'/lab.php';
$db=$config=null;$owned=$removed=$rows=$checks=$observations=[];
$runtime=s149Runtime();
try {

    $config=s149Config();$db=s149Connect($config);$runtime=s149Runtime($db,$config);
    $name = s149OwnTable($db, $owned, 'diagnostics_window',
        '(invoice_no VARCHAR(20) PRIMARY KEY, total DECIMAL(12,2) NOT NULL)');
    $qualified = s149Qualified($name);
    s149Command($db, 'INSERT INTO '.$qualified.' (invoice_no, total) VALUES (?, ?)', ['INV-149','419.50']);
    $broken = sqlsrv_query($db,
        'SELECT invoice_no, totla FROM '.$qualified.' WHERE invoice_no = ?', ['INV-149'], ['QueryTimeout'=>10]);
    $rawSaved = sqlsrv_errors(SQLSRV_ERR_ALL);
    $saved = s149Diagnostics($rawSaved);
    $messagePresent = is_array($rawSaved) && count($rawSaved) > 0;
    foreach ($rawSaved ?? [] as $item) {
        $messagePresent = $messagePresent && is_string($item['message'] ?? null) && $item['message'] !== '';
    }
    if ($broken !== false) {
        sqlsrv_free_stmt($broken);
        throw new RuntimeException('Неверный столбец неожиданно принят');
    }
    $savedCopy = $saved;
    $stmt = sqlsrv_query($db,
        'SELECT invoice_no, total FROM '.$qualified.' WHERE invoice_no = ?', ['INV-149'], ['QueryTimeout'=>10]);
    $afterCorrectQuery = s149Diagnostics(sqlsrv_errors(SQLSRV_ERR_ALL));
    if ($stmt === false) { throw new RuntimeException('Исправленный запрос не выполнен'); }
    try {
        $invoice = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
        if ($invoice === false) { s149Failure('Строка исправленного запроса не прочитана'); }
        if ($invoice === null) { throw new RuntimeException('Накладная не найдена'); }
    } finally {
        sqlsrv_free_stmt($stmt);
    }
    $rows = [['Запрос с totla вернул false', $broken === false],
        ['Причина сохранена до исправленного запроса', count($saved) > 0 && $messagePresent],
        ['Сохранённая диагностика не потеряна', $saved === $savedCopy],
        ['У исправленного запроса нет диагностики', $afterCorrectQuery === []],
        ['Номер из исправленного результата', $invoice['invoice_no']], ['Сумма из базы', $invoice['total']]];
    $checks = ['broken_failed'=>$broken === false, 'saved_diagnostics'=>count($saved)>0 && $messagePresent,
        'saved_survives'=>$saved === $savedCopy, 'success_cleared'=>$afterCorrectQuery === [],
        'actual_invoice'=>$invoice === ['invoice_no'=>'INV-149','total'=>'419.50']];
    $observations = ['first_query_diagnostics'=>$saved, 'message_was_nonempty'=>$messagePresent,
        'after_correct_query_diagnostics'=>$afterCorrectQuery, 'invoice'=>$invoice,
        'saved_diagnostics_after_later_calls'=>$savedCopy];
} finally {
    if (is_resource($db)) {try {$removed=s149Cleanup($db,$owned);} finally {sqlsrv_close($db);}}
}
s149Report('sqlsrv149-diagnostics-window', 'Сохранить ошибку столбца и после исправления получить правильную накладную', $rows, $checks, $observations, $runtime, $owned, $removed);
Ожидаемый результат
Запрос с totla вернул false — да
Причина сохранена до исправленного запроса — да
Сохранённая диагностика не потеряна — да
У исправленного запроса нет диагностики — да
Номер из исправленного результата — INV-149
Сумма из базы — 419.50

Распакуйте архив отдельно и выполните example.php по README.txt. lab.php содержит открытый код подготовки учебной среды, ограничения собственных имён и сохранения отчётов. Используется настоящий SQL Server; новая таблица получает случайное собственное имя и удаляется после проверки. Отсутствующая база не создаётся. result.html и result.json сохраняют фактические данные, metrics.json — проверки.

Открыть таблицу сохранённого запуска · Данные и диагностические наблюдения JSON.

Границы и ошибки

Исправление выполняется вручную известным запросом. Сайт не должен автоматически угадывать имена столбцов и повторять произвольные SQL-команды. Снимок ошибки берётся до следующей операции драйвера; успешный запрос может очистить текущие записи, но не меняет уже сохранённый PHP-массив. В публичный отчёт не попадают исходный message и случайное имя таблицы из диагностического текста. В частном журнале разработчика можно хранить очищенные подробности, но оператору следует показать понятный статус документа. finally очищает только свою учебную таблицу.

Разработчик видит вторичную ошибку чтения из boolean и хочет узнать первоначальную причину отказа SQL. Практическая проблема на Stack Overflow. Сразу после false сохраняем массив SQLSTATE/code/message. Чтение результата выполняем только для успешного statement; журнал PHP и диагностические записи драйвера объясняем отдельно.

Измените одно требование

Переставьте чтение sqlsrv_errors на строку после успешного исправленного query. Почему такой журнал больше не объясняет первый отказ?

Что должно измениться

Теперь errors относится к последней успешной операции, и первоначальная запись может исчезнуть. Держите вызов errors непосредственно рядом с false и сохраняйте результат в переменную до любых последующих обращений к драйверу.

Показать неполную сумму платежей, даже когда драйвер не вернул предупреждение

В таблице три платежа: 120.00, ещё неизвестная сумма NULL и 25.50. Отчёту нужен итог известных сумм 145.50, но нельзя притворяться, что заполнены все три платежа. Покажем количество строк, число известных значений, саму сумму и фактически возвращённую диагностику; затем сравним политику драйвера 1 и 0. Если драйвер не вернул предупреждение, неизвестный платёж всё равно должен быть виден в отчёте.

Что делает программа
  1. PAY-1 содержит 120.00, PAY-2 содержит NULL, PAY-3 содержит 25.50
  2. SUM пропускает неизвестный amount; COUNT(*) даёт 3, COUNT(amount) даёт 2
  3. При ANSI_WARNINGS ON проверяем диагностику после выполнения и каждого этапа чтения
  4. В проверенной связке драйвер не вернул предупреждений при обеих политиках
  5. Отчёт всё равно показывает один неизвестный платёж: COUNT(*) минус COUNT(amount)
  6. В finally возвращаются прежние настройки PHP-драйвера и этого соединения

Сначала короткий вызов

$previous = sqlsrv_get_config('WarningsReturnAsErrors');
try {
    sqlsrv_configure('WarningsReturnAsErrors', 0);
    // Выполнить отчёт, сохранить результат и предупреждения.
} finally {
    sqlsrv_configure('WarningsReturnAsErrors', $previous);
}

get_config читает действующее значение, configure меняет его для текущей работы PHP. finally возвращает сохранённое значение, даже если чтение отчёта не удалось. Полная программа проверяет успех этих вызовов, отдельно настраивает ANSI_WARNINGS данного соединения и сохраняет диагностику после query, чтения, EOF и перехода к следующему результату. Если предупреждение доступно на одном из этих этапов, оно сохраняется; отсутствующую запись программа не придумывает.

Какой результат получится

НаблюдениеРезультат
Всего платежей в таблице3
Платежей с известной суммой2
Платежей с неизвестной суммой1
Сумма при политике 1145.50
Сумма при политике 0145.50
Получено предупреждений при политике 10
Получено предупреждений при политике 00
Ошибок SQLSRV в обоих опытах нетда
Неверное имя настройки обнаруженода
Исходная политика восстановленада
ANSI_WARNINGS восстановленада
Полная программа и архив для самостоятельного запуска
Показать неполную сумму платежей, даже когда драйвер не вернул предупреждениеСамостоятельный пример
<?php
declare(strict_types=1);
require __DIR__.'/lab.php';
$db=$config=null;$owned=$removed=$rows=$checks=$observations=[];
$runtime=s149Runtime();
try {

    $config=s149Config();$db=s149Connect($config);$runtime=s149Runtime($db,$config);
    function sqlsrv149Snapshot(): array {
        $all = sqlsrv_errors(SQLSRV_ERR_ALL);
        $errors = sqlsrv_errors(SQLSRV_ERR_ERRORS);
        $warnings = sqlsrv_errors(SQLSRV_ERR_WARNINGS);
        return [
            'all'=>s149Diagnostics($all),
            'errors'=>s149Diagnostics($errors),
            'warnings'=>s149Diagnostics($warnings),
            'raw_types'=>['all'=>get_debug_type($all), 'errors'=>get_debug_type($errors),
                'warnings'=>get_debug_type($warnings)],
        ];
    }
    $name = s149OwnTable($db, $owned, 'warning_policy',
        '(payment_no VARCHAR(20) PRIMARY KEY, amount DECIMAL(12,2) NULL)');
    $qualified = s149Qualified($name);
    s149Command($db, 'INSERT INTO '.$qualified.' (payment_no, amount) VALUES (?, ?)', ['PAY-1','120.00']);
    s149Command($db, 'INSERT INTO '.$qualified.' (payment_no, amount) VALUES (?, ?)', ['PAY-2',null]);
    s149Command($db, 'INSERT INTO '.$qualified.' (payment_no, amount) VALUES (?, ?)', ['PAY-3','25.50']);
    $previous = sqlsrv_get_config('WarningsReturnAsErrors');
    $previousDiagnostics = sqlsrv_errors(SQLSRV_ERR_ALL);
    if ($previousDiagnostics !== null) { throw new RuntimeException('Исходная политика не прочитана'); }
    $ansiBefore = s149Read($db, "SELECT CONVERT(int, SESSIONPROPERTY('ANSI_WARNINGS')) AS enabled")[0]['enabled'];
    $runs = [];
    try {
        s149Command($db, 'SET ANSI_WARNINGS ON');
        foreach ([1,0] as $policy) {
            $configured = sqlsrv_configure('WarningsReturnAsErrors', $policy);
            if ($configured !== true) { s149Failure('Политика предупреждений не принята'); }
            $configuredValue = sqlsrv_get_config('WarningsReturnAsErrors');
            $stmt = sqlsrv_query($db,
                'SELECT SUM(amount) AS total, COUNT(*) AS rows_total, COUNT(amount) AS known_amounts FROM '.$qualified,
                [], ['QueryTimeout'=>10]);
            $stages = ['query'=>sqlsrv149Snapshot()];
            if ($stmt === false) { throw new RuntimeException('Агрегат неожиданно завершился отказом'); }
            try {
                $aggregate = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
                $stages['fetch'] = sqlsrv149Snapshot();
                if (!is_array($aggregate)) { throw new RuntimeException('Агрегат не вернул строку'); }
                $end = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
                $stages['eof'] = sqlsrv149Snapshot();
                if ($end !== null) { throw new RuntimeException('Неверный конец агрегатного результата'); }
                $next = sqlsrv_next_result($stmt);
                $stages['next_result'] = sqlsrv149Snapshot();
                if ($next !== null) { throw new RuntimeException('Неожиданный дополнительный результат агрегата'); }
            } finally {
                sqlsrv_free_stmt($stmt);
            }
            $warnings = $errors = [];
            foreach ($stages as $snapshot) {
                array_push($warnings, ...$snapshot['warnings']);
                array_push($errors, ...$snapshot['errors']);
            }
            $runs[(string)$policy] = ['configured_value'=>$configuredValue, 'aggregate'=>$aggregate,
                'stages'=>$stages, 'returned_warnings_count'=>count($warnings), 'errors_empty'=>$errors===[]];
        }
        $invalidSetting = sqlsrv_get_config('WarningReturnAsErrors');
        $invalidDiagnostics = s149Diagnostics(sqlsrv_errors(SQLSRV_ERR_ALL));
    } finally {
        $restored = sqlsrv_configure('WarningsReturnAsErrors', $previous);
        s149Command($db, $ansiBefore === 1 ? 'SET ANSI_WARNINGS ON' : 'SET ANSI_WARNINGS OFF');
    }
    $after = sqlsrv_get_config('WarningsReturnAsErrors');
    $ansiAfter = s149Read($db, "SELECT CONVERT(int, SESSIONPROPERTY('ANSI_WARNINGS')) AS enabled")[0]['enabled'];
    $expected = ['total'=>'145.50','rows_total'=>3,'known_amounts'=>2];
    $rows = [['Всего платежей в таблице', $runs['1']['aggregate']['rows_total']],
        ['Платежей с известной суммой', $runs['1']['aggregate']['known_amounts']],
        ['Платежей с неизвестной суммой', $runs['1']['aggregate']['rows_total'] - $runs['1']['aggregate']['known_amounts']],
        ['Сумма при политике 1', $runs['1']['aggregate']['total']],
        ['Сумма при политике 0', $runs['0']['aggregate']['total']],
        ['Получено предупреждений при политике 1', $runs['1']['returned_warnings_count']],
        ['Получено предупреждений при политике 0', $runs['0']['returned_warnings_count']],
        ['Ошибок SQLSRV в обоих опытах нет', $runs['1']['errors_empty'] && $runs['0']['errors_empty']],
        ['Неверное имя настройки обнаружено', $invalidSetting === false && count($invalidDiagnostics)>0],
        ['Исходная политика восстановлена', $restored === true && $after === $previous],
        ['ANSI_WARNINGS восстановлена', $ansiAfter === $ansiBefore]];
    $checks = ['aggregate_policy_one'=>$runs['1']['aggregate']===$expected,
        'aggregate_policy_zero'=>$runs['0']['aggregate']===$expected,
        'null_accounted'=>$runs['1']['aggregate']['rows_total'] - $runs['1']['aggregate']['known_amounts'] === 1,
        'observed_no_warnings'=>$runs['1']['returned_warnings_count'] === 0 && $runs['0']['returned_warnings_count'] === 0,
        'errors_empty'=>$runs['1']['errors_empty'] && $runs['0']['errors_empty'],
        'policy_values'=>$runs['1']['configured_value']===true && $runs['0']['configured_value']===false,
        'invalid_setting'=>$invalidSetting===false && count($invalidDiagnostics)>0,
        'restored'=>$restored===true && $after===$previous, 'ansi_restored'=>$ansiAfter===$ansiBefore];
    $observations = ['policy_before'=>$previous, 'policy_after'=>$after, 'policy_runs'=>$runs,
        'invalid_setting_return'=>$invalidSetting, 'invalid_setting_diagnostics'=>$invalidDiagnostics,
        'ansi_before'=>$ansiBefore,'ansi_after'=>$ansiAfter];
} finally {
    if (is_resource($db)) {try {$removed=s149Cleanup($db,$owned);} finally {sqlsrv_close($db);}}
}
s149Report('sqlsrv149-warning-policy', 'Показать неполную сумму платежей, даже когда драйвер не вернул предупреждение', $rows, $checks, $observations, $runtime, $owned, $removed);
Ожидаемый результат
Всего платежей в таблице — 3
Платежей с известной суммой — 2
Платежей с неизвестной суммой — 1
Сумма при политике 1 — 145.50
Сумма при политике 0 — 145.50
Получено предупреждений при политике 1 — 0
Получено предупреждений при политике 0 — 0
Ошибок SQLSRV в обоих опытах нет — да
Неверное имя настройки обнаружено — да
Исходная политика восстановлена — да
ANSI_WARNINGS восстановлена — да

Распакуйте архив отдельно и выполните example.php по README.txt. lab.php содержит открытый код подготовки учебной среды, ограничения собственных имён и сохранения отчётов. Используется настоящий SQL Server; новая таблица получает случайное собственное имя и удаляется после проверки. Отсутствующая база не создаётся. result.html и result.json сохраняют фактические данные, metrics.json — проверки.

Открыть таблицу сохранённого запуска · Данные и диагностические наблюдения JSON.

Границы и ошибки

NULL означает неизвестную сумму, а не ноль. SUM(amount) складывает известные значения; без COUNT(amount) оператор мог бы принять частичный итог за полный. В SQLSRV есть четыре исключения SQLSTATE: 01000, 01001, 01003 и 01S02 по официальной документации не превращаются в ошибки даже при включённом WarningsReturnAsErrors. Документация SQL Server описывает предупреждение при исключении NULL из агрегата с ANSI_WARNINGS ON. В проверенной связке SQLSRV 5.13.3, ODBC 18.07 и SQL Server 16.00.1000 sqlsrv_errors вернул null после query, fetch, конца строк и next_result при обеих политиках. Это наблюдение конкретной среды, а не обещание такого поведения для всех версий и не доказательство, что сервер не создавал предупреждение. Переключатель не исправляет исходные данные. Это также не настройка SQL Server ANSI_WARNINGS: мы показываем оба механизма отдельно и восстанавливаем оба. В следующем результате в этой конкретной команде данных нет; общий разбор нескольких наборов и процедур относится к отдельной теме. Ошибочное имя WarningReturnAsErrors без s проверяется как отказ, а правильная настройка со значением false — как допустимое значение.

Сообщения сервера смешиваются с ошибками, и работающий запрос выглядит неуспешным. Практическая проблема на Stack Overflow. Проверяем возврат вызова и отдельно классифицируем диагностические записи. Ответ обсуждения не используем как правило: официальная документация выделяет SQLSTATE 01000, 01001, 01003 и 01S02, которые не превращаются в ошибки. Наш агрегат с NULL показывает фактический результат и границу наблюдения: в проверенной связке диагностика SQLSRV пуста даже при ANSI_WARNINGS ON.

Измените одно требование

Если PAY-2 действительно равен нулю, замените NULL на 0.00. Изменятся ли сумма и число известных платежей?

Что должно измениться

Сумма останется 145.50, COUNT(amount) станет 3, а неизвестных платежей будет 0. Это другая предметная ситуация: нулевая сумма известна. Нельзя автоматически заменять неизвестную сумму нулём только ради тишины в журнале. Для такого изменённого набора нужно обновить проверки количества; отсутствие предупреждений само по себе не подтверждает полноту данных.

Семь функций соединения и диагностики

ФункцияЧто помогает сделать
sqlsrv_connectОткрыть нужную базу SQL Server и получить соединение, через которое можно читать её данные.
sqlsrv_closeЗакончить работу с соединением и освободить связанные ресурсы после получения нужных данных.
sqlsrv_client_infoУвидеть, какие PHP- и ODBC-компоненты обслуживают именно это соединение.
sqlsrv_server_infoПроверить текущую базу и экземпляр сервера перед чтением рабочего документа.
sqlsrv_errorsСохранить причину отказа сразу после проблемного вызова и отделить предупреждение от ошибки.
sqlsrv_configureВременно изменить обработку предупреждений или журналирование и затем вернуть прежнюю настройку.
sqlsrv_get_configПрочитать действующую настройку перед временным изменением и отличить false-настройку от ошибки имени.

Дальше: значения параметров и типы полей

Теперь соединение подтверждено прочитанным документом, отказ входа отделён от SQL-ошибки, а диагностика не подменяет результат. Следующий шаг — параметры, Unicode, точные цены и даты: как повторно использовать подготовленную команду, что возвращается из DECIMAL и даты и как не спутать ноль изменённых строк с неизвестным количеством. Для выбора нужных полей и строк пригодится построение запроса под экран; общие идеи переносим между СУБД, а конкретные T-SQL-синтаксис и драйверные вызовы проверяем отдельно.

Функции и методы этой темы

Откройте карточку, чтобы увидеть договор функции, примеры, ограничения и связанные инструменты.

sqlsrv_connectОткрыть нужную базу SQL Server и получить соединение, через которое можно читать её данные.

PHP.net не сообщает минимальную версию функции. Совместимость конкретной сборки PHP, SQLSRV и ODBC проверяется отдельно; исторические версии из примеров не являются требованием. · sqlsrv

sqlsrv_connect(string $serverName, array $connectionInfo = ?): resource|false

Открыть нужную базу SQL Server и получить соединение, через которое можно читать её данные.

Путь действия
  1. Сервер и Database определяют адрес учебного каталога
  2. sqlsrv_connect устанавливает соединение через SQLSRV и ODBC
  3. Успех → ресурс $conn; отказ → false и диагностические записи
  4. Только успешный ресурс передаётся в sqlsrv_query
  5. После чтения своих данных освобождаем statement и соединение

Сигнатура и входные значения

sqlsrv_connect(string $serverName, array $connectionInfo = ?): resource|false

Это справочная запись типов и аргументов. Копируемые вызовы приведены ниже; слово resource в описании обозначает служебный ресурс PHP.

ПараметрНазначение
$serverNameСтрока с сервером: server\instance для именованного экземпляра или server,port для порта. LocalDB поддерживает (localdb)\instance. Это не имя таблицы и не путь к PHP-файлу.
$connectionInfoНеобязательный ассоциативный массив настроек: Database, CharacterSet, UID/PWD и другие ключи из таблицы ниже. Знак ? в официальной сигнатуре обозначает необязательный аргумент без показанного значения по умолчанию, а не параметр SQL.

Что возвращается

При успехе возвращается ресурс соединения. При неудаче — false, после которого сразу читают sqlsrv_errors. Наличие ресурса ещё не означает успешную выборку или право на любую таблицу.

Два применения

У локального каталога есть отдельный экземпляр и база phpmanual149, заранее подготовленные по README. В минимальном фрагменте используется Windows Authentication; файл базы здесь не создаётся. Полная программа проверяет реальную накладную и текущую базу.

$connectionInfo = ['Database' => 'phpmanual149', 'CharacterSet' => 'UTF-8'];
$conn = sqlsrv_connect('(localdb)\\AENPHPManual149', $connectionInfo);
if ($conn === false) {
    $diagnostics = sqlsrv_errors(SQLSRV_ERR_ALL);
    throw new RuntimeException('Учебная база недоступна');
}

Полная программа и её результат.

В диагностике переноса сайта отделяем ошибочное имя базы от корректной строки SQL. $server и $connectionInfo — подготовленные настройки этого же учебного сервера; в полном файле отсутствующее имя проверяется до опыта, а затем выполняется нормальное подключение.

$wrong = $connectionInfo;
$wrong['Database'] = 'phpmanual149_missing';
$missing = sqlsrv_connect($server, $wrong);
$diagnostics = sqlsrv_errors(SQLSRV_ERR_ALL);
if ($missing === false) {
    echo 'Имя базы нужно проверить';
}

Полная программа и её результат.

Ошибки и границы

Отсутствие UID/PWD в обычном вызове означает попытку Windows Authentication, а не анонимный доступ. Пользователь PHP CLI и учётная запись веб-сервера могут быть разными. UID и PWD для SQL Server Authentication задаются вместе; пароли нельзя вставлять в публикуемые примеры или журналы. LocalDB и именованный сетевой экземпляр — разные варианты подключения. Не включайте TrustServerCertificate автоматически ради прохождения любой ошибки сертификата. Нельзя продолжать запросы с false: вторичная ошибка аргумента скроет первоначальную причину. Автоматическое восстановление соединения не гарантирует безопасный повтор записи.

Второй аргумент connect — ассоциативный массив: слева имя настройки, справа её значение. Например, Database выбирает базу, а CharacterSet задаёт кодировку обмена. Это не столбцы таблицы и не параметры SQL-запроса. Ниже перечислены ключи официальной таблицы Microsoft; редкие возможности требуют соответствующей версии драйвера и настройки сервера. Значения «по умолчанию» взяты из таблицы PHP-драйвера, а не перенесены из ODBC или PDO.

КлючЗначение и исходная настройкаЗачем нужен и где граница
Databaseстрока; база входа по умолчаниюВыбор текущей базы. Не создаёт её и не выдаёт права; полное имя может адресовать другую разрешённую базу.
UID / PWDстроки; не заданыОба значения для SQL Server Authentication. Не печатайте массив настроек с паролем. Без них обычный вызов пробует Windows Authentication.
Authenticationстрока; не заданаSqlPassword, ActiveDirectoryIntegrated, ActiveDirectoryPassword (устаревший), ActiveDirectoryMsi, ActiveDirectoryServicePrincipal. Режим должен поддерживаться окружением.
AccessTokenстрока байтов; не заданТокен Microsoft Entra вместо UID/PWD/Authentication; совместное задание запрещено. Это не целый JSON-ответ OAuth.
APP / WSIDстроки; не заданыИмя приложения и рабочей станции для трассировки. Не доказывают подлинность пользователя.
CharacterSetSQLSRV_ENC_CHAR или "UTF-8"; SQLSRV_ENC_CHARКодировка передаваемых данных. Ключ относится к SQLSRV, а не PDO_SQLSRV. Unicode и тип столбца всё равно нужно согласовать.
Driverстрока; автоматический выборИмена Microsoft ODBC Driver 18/17/13/11 for SQL Server; 11 — только Windows. Без ключа драйвер ищет поддерживаемый, начиная с нового. Список имён не заменяет матрицу поддержки.
LoginTimeoutцелое, секунды; без заданного таймаутаОграничение установления соединения. Это не QueryTimeout запроса. Для автоматически приостановленной Azure SQL нужны отдельные ожидание и повторный вход.
ConnectRetryCountцелое 0…255; 1Число попыток восстановления разорванного соединения. 0 отключает их; это не разрешение повторять произвольную запись приложения.
ConnectRetryIntervalцелое 1…60 секунд; 10Интервал восстановления; первая попытка сразу. При ConnectRetryCount=0 не используется.
ConnectionPoolingbool/0/1; trueИспользование пула на поддерживаемой платформе. На Linux/macOS этот ключ не переключает pooling; там настройка выполняется в ODBC.
Encryptbool/0/1; таблица PHP-драйвера указывает falseШифрование соединения. Задавайте требование явно: версия ODBC, политика сервера и выбранная транспортная среда влияют на результат.
TrustServerCertificatebool/0/1; falseРазрешение доверять сертификату без обычной проверки. Это не исправление неверного имени сервера и не универсальный способ обходить TLS-ошибки.
ColumnEncryptionDisabled / Enabled / протокол и URL аттестации; DisabledAlways Encrypted, включая защищённые enclaves при выполнении их требований. Отдельно от шифрования сетевого канала.
KeyStoreAuthenticationKeyVaultPassword / KeyVaultClientSecret; не заданСпособ доступа к Azure Key Vault. Требует соответствующей настройки Always Encrypted и поддерживаемой версии.
KeyStorePrincipalId / KeyStoreSecretстроки; не заданыДля KeyVaultPassword — имя/пароль Entra; для KeyVaultClientSecret — client ID/secret приложения. Секреты не предназначены для вывода.
Languageстрока; язык SQL ServerЯзык серверных сообщений из sys.syslanguages. Не переводит PHP-драйвер и не меняет язык установленного ODBC.
ReturnDatesAsStringsbool/0/1; falsedatetime, smalldatetime, date, time, datetime2, datetimeoffset как строки вместо PHP DateTime. Ключ SQLSRV; у PDO свои настройки.
FormatDecimalsbool/0/1; falseДобавление ведущего нуля и включение форматирования money. Не переводит точные денежные значения в float.
DecimalPlacesцелое 0…4; исходные precision/scaleКоличество знаков для money только при FormatDecimals=true; значения вне диапазона игнорируются.
MultipleActiveResultSetsbool/0/1; trueMARS разрешает несколько активных результатов. Не делает одно соединение несколькими независимыми транзакциями.
Scrollableстрока "buffered"; по умолчанию forward-onlyКлиентский буфер может держать весь результат в памяти. Выбор курсора следует согласовать с задачей и размером выборки.
QuotedIdbool/0/1; trueПравила SQL-92 для кавычек идентификаторов либо старые правила T-SQL. Не экранирует пользовательские значения.
TransactionIsolationконстанта SQLSRV_TXN_*; READ_COMMITTEDREAD_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SNAPSHOT, SERIALIZABLE. SNAPSHOT требует поддержки настройками базы.
ApplicationIntentReadOnly / ReadWrite; ReadWriteНамерение нагрузки для соответствующей инфраструктуры высокой доступности; не замена правам чтения.
MultiSubnetFailoverстрока; NoYes/True/1 включает параллельные TCP-попытки к адресам поддерживаемой точки. Не сочетать с Failover_Partner; это не настройка LocalDB.
TransparentNetworkIPResolutionEnabled / Disabled; EnabledРезервная последовательность выбора IP; при MultiSubnetFailover=Yes не управляет порядком подключений.
Failover_Partnerстрока; не заданПартнёр зеркалирования; ограничения совместимости с MultiSubnetFailover. На Linux/macOS этот режим не поддерживается.
AttachDBFileNameстрока; не заданФайл базы для присоединения сервером. Database — имя базы, а не этот путь; доступ к файлу определяется сервером.
TraceOn / TraceFilebool и строка; false / не заданODBC-трассировка и её файл. Не путать с LogSubsystems/LogSeverity; трассы могут содержать сведения приложения.
Serverне ключ SQLSRV connectionInfoВ общей таблице Microsoft он предназначен для PDO DSN. В sqlsrv_connect сервер передаётся первым аргументом.

В SQLSRV 5.13.1 отдельно уточнено разделение пулов с AccessToken: содержимое токена влияет на внутренний ключ через APP. Это версия конкретного поведения, а не обещание такой реализации в любой старой DLL. Для Azure serverless Microsoft рекомендует при заданном LoginTimeout не меньше 60 секунд и обработку пробуждения; это рекомендация для удалённого сервиса, не обязательное ожидание каждого локального урока.

Для MultiSubnetFailover используется TCP и соответствующая точка доступности; указание больше 64 IP не поддерживается, а другие значения ключа, кроме включающих, интерпретируются как No. Для аутентификации, Key Vault, Always Encrypted, пулов и кластеров нужно читать их отдельные требования. Полная актуальная таблица и ссылки на эти механизмы.

Отдельной функции SQLSRV для смены текущей базы нет. Для уже открытого соединения официальное руководство предлагает SQL-команду USE dbName; например, USE [phpmanual149] выбирает заранее известную учебную базу, если у подключения есть права. Имя базы — идентификатор, его нельзя заменить значением параметра ?. Не подставляйте произвольный пользовательский ввод. Здесь база явно выбирается ключом Database при подключении, поэтому скрытого переключения контекста нет.

Версии. PHP.net не сообщает минимальную версию функции. Совместимость конкретной сборки PHP, SQLSRV и ODBC проверяется отдельно; исторические версии из примеров не являются требованием.

sqlsrv_closeЗакончить работу с соединением и освободить связанные ресурсы после получения нужных данных.

PHP.net не сообщает минимальную версию функции. Совместимость конкретной сборки PHP, SQLSRV и ODBC проверяется отдельно; исторические версии из примеров не являются требованием. · sqlsrv

sqlsrv_close(resource $conn): bool

Закончить работу с соединением и освободить связанные ресурсы после получения нужных данных.

Путь действия
  1. Прочитали накладную в обычный массив PHP
  2. Statement больше не нужен → sqlsrv_free_stmt
  3. Завершили операции → sqlsrv_close
  4. Сохранённый массив остаётся доступным; запросов через закрытый ресурс больше нет

Сигнатура и входные значения

sqlsrv_close(resource $conn): bool

Это справочная запись типов и аргументов. Копируемые вызовы приведены ниже; слово resource в описании обозначает служебный ресурс PHP.

ПараметрНазначение
$connОткрытое соединение из sqlsrv_connect. В полном файле перед уборкой проверяется is_resource; false после неудачного connect не является соединением.

Что возвращается

Официальный возврат — true при успехе и false при неудаче. Microsoft дополнительно описывает допустимый null и повторный close(null), но PHP 8.3.35 / SQLSRV 5.13.3 после первого close оставил в переменной resource (closed); и повторный вызов, и явный null дали TypeError. Это расхождение не скрываем: копируемый пример передаёт только действующий ресурс. Закрытие не возвращает строки и не подтверждает успешную запись.

Два применения

Отчёт можно сформировать из уже прочитанного массива после освобождения базы. $invoice и $stmt получены показанным полным сценарием: закрытие не стирает скопированные значения из $saved.

$saved = $invoice;
sqlsrv_free_stmt($stmt);
$closed = sqlsrv_close($conn);
echo $saved['invoice_no'];

Полная программа и её результат.

Если одна операция завершилась отказом, cleanup всё равно нужен. finally выполняет уборку, а диагностика первоначального отказа должна быть сохранена до закрытия. Полный сценарий сначала исправляет запрос и перечитывает накладную.

try {
    // Здесь выполняются операции с успешно открытым $conn.
} finally {
    if (is_resource($conn)) {
        sqlsrv_close($conn);
    }
}

Полная программа и её результат.

Ошибки и границы

Освобождение ресурса не заменяет commit/rollback явной транзакции и не является удалением таблиц. При pooling физическое соединение может вернуться в пул; это не обещание немедленного исчезновения серверного сеанса. Не держите соединение открытым ради формирования уже готового HTML. Если нужно прочитать ещё данные, делайте это до close или явно открывайте новое соединение. Передаваемая переменная и фактическое поведение повторного close проверяются отдельным наблюдением выбранной версии, а не предположением по другому драйверу.

Обработка выхода описана в try/finally; освобождение отдельного statement отличается от закрытия соединения.

Версии. PHP.net не сообщает минимальную версию функции. Совместимость конкретной сборки PHP, SQLSRV и ODBC проверяется отдельно; исторические версии из примеров не являются требованием.

sqlsrv_client_infoУвидеть, какие PHP- и ODBC-компоненты обслуживают именно это соединение.

PHP.net не сообщает минимальную версию функции. Совместимость конкретной сборки PHP, SQLSRV и ODBC проверяется отдельно; исторические версии из примеров не являются требованием. · sqlsrv

sqlsrv_client_info(resource $conn): array|false

Увидеть, какие PHP- и ODBC-компоненты обслуживают именно это соединение.

Путь действия
  1. PHP запускает расширение SQLSRV
  2. SQLSRV обращается к выбранному ODBC-драйверу
  3. client_info возвращает сведения этой клиентской цепочки
  4. Сведения о SQL Server читаются отдельно

Сигнатура и входные значения

sqlsrv_client_info(resource $conn): array|false

Это справочная запись типов и аргументов. Копируемые вызовы приведены ниже; слово resource в описании обозначает служебный ресурс PHP.

ПараметрНазначение
$connОткрытый ресурс соединения. Функция не устанавливает соединение сама и не читает сведения о браузере посетителя.

Что возвращается

Ассоциативный массив DriverDllName, DriverODBCVer, DriverVer и ExtensionVer; при невозможности получить сведения — false. DriverODBCVer обозначает версию спецификации ODBC, DriverVer — версию клиентского драйвера, ExtensionVer — расширения PHP.

Два применения

При воспроизведении ошибки нужно знать фактическую версию загруженного расширения. Значение нельзя заранее заменить номером скачанного ZIP: процесс мог загрузить другую DLL.

$client = sqlsrv_client_info($conn);
if ($client === false) {
    throw new RuntimeException('Нет сведений о клиенте');
}
echo $client['ExtensionVer'];

Полная программа и её результат.

При переносе локального импорта на сервер эти поля помогают сравнить клиентские стеки. Они сопровождают фактически прочитанную накладную в result.json, но не подменяют проверку её содержимого.

$client = sqlsrv_client_info($conn);
if ($client !== false) {
    $receipt = [
        'odbc_module' => $client['DriverDllName'],
        'odbc_driver_version' => $client['DriverVer'],
        'odbc_api_version' => $client['DriverODBCVer'],
    ];
}

Полная программа и её результат.

Ошибки и границы

В старой таблице PHP.net встречаются SQLNCLI10.DLL, 10.5.xxx и 2.0.xxx.x; Microsoft также приводит MSODBCSQL11.DLL для выпусков 3.1/3.2. Это исторические примеры, а не постоянные значения ключей. Имя модуля зависит от платформы и установленного ODBC. Версия SQL Server в этот массив не входит. Такая диагностика предназначена разработчику; посетителю магазина обычно достаточно содержимого заказа.

КлючЧто описывает
DriverDllNameНазвание клиентского модуля ODBC/Native Client, реально выбранного соединением.
DriverODBCVerПоддерживаемая версия интерфейса ODBC, например в форме xx.yy.
DriverVerВерсия самого клиентского драйвера, не версия SQL Server.
ExtensionVerВерсия PHP SQLSRV, не версия PHP.

Для другой стороны соединения используется sqlsrv_server_info.

Версии. PHP.net не сообщает минимальную версию функции. Совместимость конкретной сборки PHP, SQLSRV и ODBC проверяется отдельно; исторические версии из примеров не являются требованием.

sqlsrv_server_infoПроверить текущую базу и экземпляр сервера перед чтением рабочего документа.

PHP.net не сообщает минимальную версию функции. Совместимость конкретной сборки PHP, SQLSRV и ODBC проверяется отдельно; исторические версии из примеров не являются требованием. · sqlsrv

sqlsrv_server_info(resource $conn): array

Проверить текущую базу и экземпляр сервера перед чтением рабочего документа.

Путь действия
  1. Database из настроек выбирает начальную базу
  2. server_info считывает текущее состояние соединения
  3. CurrentDatabase сверяется с ожидаемым именем
  4. Затем читается накладная из этой базы, а не из случайной базы входа

Сигнатура и входные значения

sqlsrv_server_info(resource $conn): array

Это справочная запись типов и аргументов. Копируемые вызовы приведены ниже; слово resource в описании обозначает служебный ресурс PHP.

ПараметрНазначение
$connУже открытое соединение между PHP и SQL Server. Это не имя сервера и не statement запроса.

Что возвращается

Официальная таблица описывает массив CurrentDatabase, SQLServerVersion и SQLServerName. Пример документации содержит ветку отказа, а реализация SQLSRV 5.13.3 возвращает false при обработанном внутреннем отказе. Перед обращением к ключам проверяйте результат и сохраняйте диагностику. В сигнатуре PHP.net ветка false не отражена; не выводим фиктивный массив при неудаче.

Два применения

При запуске импорта проверяем адрес до работы с документом. Отсутствие Database в настройках могло выбрать базу входа пользователя; совпадение имени — проверка маршрута, не разрешение изменять всё её содержимое.

$serverInfo = sqlsrv_server_info($conn);
if ($serverInfo === false || $serverInfo['CurrentDatabase'] !== 'phpmanual149') {
    throw new RuntimeException('Выбрана другая база');
}

Полная программа и её результат.

После исправления ошибочного имени базы нужно подтвердить новое соединение фактическими данными. В пользовательском сообщении можно показать только статус, а техническую версию сохранить в диагностике разработчика.

$serverInfo = sqlsrv_server_info($conn);
if ($serverInfo !== false) {
    $environment = [
        'database' => $serverInfo['CurrentDatabase'],
        'server_version' => $serverInfo['SQLServerVersion'],
    ];
}

Полная программа и её результат.

Ошибки и границы

SQLServerName и SQLServerVersion принадлежат серверу, а не ODBC-DLL и не PHP. Не фиксируйте имя машины или номер обновления как универсальный ожидаемый результат урока. CurrentDatabase отражает текущий контекст; запросы с полным именем могут адресовать другую доступную базу. Ни наличие имени, ни номер версии не доказывают права на конкретную таблицу, актуальность её данных или правильность миграции.

ПолеСмысл
CurrentDatabaseБаза, являющаяся текущей для соединения.
SQLServerVersionВерсия SQL Server, обслуживающего соединение.
SQLServerNameСерверное имя экземпляра.

Сравните с сведениями о клиентской стороне.

Версии. PHP.net не сообщает минимальную версию функции. Совместимость конкретной сборки PHP, SQLSRV и ODBC проверяется отдельно; исторические версии из примеров не являются требованием.

sqlsrv_errorsСохранить причину отказа сразу после проблемного вызова и отделить предупреждение от ошибки.

PHP.net не сообщает минимальную версию функции. Совместимость конкретной сборки PHP, SQLSRV и ODBC проверяется отдельно; исторические версии из примеров не являются требованием. · sqlsrv

sqlsrv_errors(int $errorsOrWarnings = SQLSRV_ERR_ALL): array|null

Сохранить причину отказа сразу после проблемного вызова и отделить предупреждение от ошибки.

Путь действия
  1. Пробуем запрос с неверным столбцом
  2. query возвращает false
  3. Сразу копируем sqlsrv_errors в $savedDiagnostics
  4. Исправленный запрос выполняется позже
  5. Первоначальная причина остаётся в обычном массиве, даже если текущая диагностика уже другая

Сигнатура и входные значения

sqlsrv_errors(int $errorsOrWarnings = SQLSRV_ERR_ALL): array|null

Это справочная запись типов и аргументов. Копируемые вызовы приведены ниже; слово resource в описании обозначает служебный ресурс PHP.

ПараметрНазначение
$errorsOrWarningsSQLSRV_ERR_ALL — ошибки и предупреждения; SQLSRV_ERR_ERRORS — только ошибки; SQLSRV_ERR_WARNINGS — только предупреждения. Без аргумента возвращаются обе группы.

Что возвращается

Массив диагностических записей последней операции SQLSRV либо null, когда подходящих записей нет. У каждой записи есть SQLSTATE, code и message; Microsoft также допускает числовые ключи 0, 1 и 2. Это не массив строк SELECT и не история всех операций. Дополнение по реализации и запуску SQLSRV 5.13.3: недопустимый флаг даёт false; поэтому используйте три документированные константы, а не случайное число.

Два применения

При ошибке имён столбцов нужно найти первый отказ, а не последующее «ожидался resource». $qualified — безопасно сформированное имя собственной таблицы; в полной программе её структура и данные известны.

$stmt = sqlsrv_query($conn, 'SELECT absent_column FROM '.$qualified);
if ($stmt === false) {
    $savedDiagnostics = sqlsrv_errors(SQLSRV_ERR_ALL);
    $state = $savedDiagnostics[0]['SQLSTATE'] ?? 'unknown';
}

Полная программа и её результат.

Для отчёта с NULL важны итог и полнота данных. Все три снимка сохраняются до другого SQL-вызова; затем программа читает результат и фиксирует диагностику этапов отдельно. В нашем профиле эти снимки пусты: отсутствие предупреждения не доказывает, что все суммы заполнены.

$stmt = sqlsrv_query($conn, $aggregateSql);
$all = sqlsrv_errors(SQLSRV_ERR_ALL);
$errors = sqlsrv_errors(SQLSRV_ERR_ERRORS);
$warnings = sqlsrv_errors(SQLSRV_ERR_WARNINGS);

Полная программа и её результат.

Ошибки и границы

Не вызывайте сначала free_stmt, close, другой запрос или настройку, а затем пытайтесь извлечь прежнюю причину. Диагностика относится к последней операции, а не к переданному объекту: аргумента $conn у errors нет. Возврат null означает отсутствие выбранной диагностики, но сам по себе не доказывает успех прикладной задачи. По умолчанию предупреждения часто превращают возврат SQLSRV-функции в false, однако SQLSTATE 01000, 01001, 01003, 01S02 — исключения. Сообщение может содержать имена сервера, базы, запросов или данные: для посетителя используйте понятный статус, подробности сохраняйте в ограниченном журнале. Нельзя определить все ошибки одним англоязычным текстом: язык и версия меняются.

ПолеКак читать
SQLSTATEПятисимвольная категория ODBC; IMSSP — ошибка PHP-драйвера, 01SSP — его предупреждение.
codeНативный код SQL Server, ODBC либо PHP-драйвера — в зависимости от источника.
messageПодробное сообщение для диагностики; не стабильный машинный идентификатор.

Поведение предупреждений задаёт sqlsrv_configure. Для проверки данных используйте возврат операции и реальное чтение, а не один факт наличия диагностического массива.

Версии. PHP.net не сообщает минимальную версию функции. Совместимость конкретной сборки PHP, SQLSRV и ODBC проверяется отдельно; исторические версии из примеров не являются требованием.

sqlsrv_configureВременно изменить обработку предупреждений или журналирование и затем вернуть прежнюю настройку.

PHP.net не сообщает минимальную версию функции. Совместимость конкретной сборки PHP, SQLSRV и ODBC проверяется отдельно; исторические версии из примеров не являются требованием. · sqlsrv

sqlsrv_configure(string $setting, mixed $value): bool

Временно изменить обработку предупреждений или журналирование и затем вернуть прежнюю настройку.

Путь действия
  1. Сохраняем прежнее значение get_config
  2. configure применяет временную политику
  3. Выполняем ровно нужную операцию и читаем её результат
  4. finally возвращает сохранённое значение
  5. Другой участок приложения не наследует случайную настройку урока

Сигнатура и входные значения

sqlsrv_configure(string $setting, mixed $value): bool

Это справочная запись типов и аргументов. Копируемые вызовы приведены ниже; слово resource в описании обозначает служебный ресурс PHP.

ПараметрНазначение
$settingИмя настройки: WarningsReturnAsErrors, LogSubsystems, LogSeverity; Microsoft дополнительно документирует ClientBufferMaxKBSize. Это не ключи connectionInfo вроде Database или CharacterSet.
$valueТип и допустимое значение зависят от настройки. Логические значения управляют предупреждениями, битовые маски — журналом, положительное число KB — клиентским буфером.

Что возвращается

true, если настройка принята; false для неподдерживаемого имени или значения. Проверяйте возврат, а после false сразу читайте sqlsrv_errors. Изменение относится к текущему выполнению PHP; функция не редактирует php.ini.

Два применения

Некоторые отчёты хотят получить результат вместе с доступной диагностикой. Полная программа проверяет возвращённые значения configure и readback настройки. Агрегат доступен при обеих политиках; отсутствие возвращённого предупреждения здесь не заменяет подсчёт неизвестных сумм.

$previous = sqlsrv_get_config('WarningsReturnAsErrors');
try {
    if (!sqlsrv_configure('WarningsReturnAsErrors', 0)) {
        throw new RuntimeException('Настройка не принята');
    }
    // Выполнить отчёт и сохранить diagnostics до другого вызова.
} finally {
    sqlsrv_configure('WarningsReturnAsErrors', $previous);
}

Полная программа и её результат.

У отдельного отчёта с клиентским курсором можно ограничить буфер 2048 KB и вернуть прежний предел. Это контекстный фрагмент настройки, а не пример самого курсора: он не обещает вместить произвольную таблицу в 2 MB и не заменяет LIMIT/TOP. Полный сценарий ниже показывает тот же порядок сохранения и восстановления на политике предупреждений.

$oldLimit = sqlsrv_get_config('ClientBufferMaxKBSize');
if (!is_int($oldLimit) || $oldLimit <= 0) {
    throw new RuntimeException('Исходный предел буфера не получен');
}
try {
    if (!sqlsrv_configure('ClientBufferMaxKBSize', 2048)) {
        throw new RuntimeException('Предел буфера не принят');
    }
    // Здесь выполняется выбранная операция с клиентским буфером.
} finally {
    sqlsrv_configure('ClientBufferMaxKBSize', $oldLimit);
}

Полная программа и её результат.

Ошибки и границы

Отключение WarningsReturnAsErrors не лечит неверный столбец, отказ входа или нарушение ограничения. Четыре исключения SQLSTATE не меняют свой статус при переключении этой опции. LogSeverity без LogSubsystems не включает журнал; журнал PHP, ODBC TraceOn и серверный журнал — разные механизмы. Побитовое | объединяет флаги: это не логическое ||. ClientBufferMaxKBSize ограничивает буфер клиента, а не размер базы и не память SQL Server. Предварительно сохраняйте только известные поддерживаемые настройки и обрабатывайте ошибку восстановления; не оставляйте изменённую политику следующей задаче долгоживущего процесса.

НастройкаЗначениеПрактический смысл
WarningsReturnAsErrors1/true или 0/false; по умолчанию trueВлияет на возврат при предупреждениях, кроме четырёх исключений SQLSTATE. Не превращает SQL-ошибку в успех.
LogSubsystemsOFF=0, INIT=1, CONN=2, STMT=4, UTIL=8, ALL=-1Все имена с префиксом SQLSRV_LOG_SYSTEM_. По умолчанию OFF. Группы можно объединять побитовым |.
LogSeverityERROR=1, WARNING=2, NOTICE=4, ALL=-1Префикс SQLSRV_LOG_SEVERITY_. Microsoft указывает исходный ERROR=1; в проверенном CLI SQLSRV 5.13.3 get_config вернул 0. Уровни объединяются |; один выбор уровня не включает подсистему.
ClientBufferMaxKBSizeположительное число KB; по умолчанию 10240Дополнение Microsoft к краткой странице PHP.net: предел клиентского буфера. Ноль/отрицательное значение недопустимы; память процесса конечна.

Названия констант приведены полностью в PHP.net; числовые маски полезны в php.ini, но в PHP понятнее символические имена. Для CONN и STMT вместе: SQLSRV_LOG_SYSTEM_CONN | SQLSRV_LOG_SYSTEM_STMT; для ошибок и предупреждений — SQLSRV_LOG_SEVERITY_ERROR | SQLSRV_LOG_SEVERITY_WARNING. Настройка журнала и его назначения.

В нашем отдельном CLI SQLSRV 5.13.3 фактический get_config("LogSeverity") вернул 0, хотя таблица Microsoft описывает исходный ERROR=1. Более того, реализация configure не принимает 0 для LogSeverity. Поэтому нельзя без проверки предполагать, что любое прочитанное значение можно вернуть через configure. Настраивайте журнал на старте выделенного процесса, проверяйте результат и фактическую конфигурацию; временные опыты ниже меняют только настройки, для которых сохранённое значение поддерживается.

Версии. PHP.net не сообщает минимальную версию функции. Совместимость конкретной сборки PHP, SQLSRV и ODBC проверяется отдельно; исторические версии из примеров не являются требованием.

sqlsrv_get_configПрочитать действующую настройку перед временным изменением и отличить false-настройку от ошибки имени.

PHP.net не сообщает минимальную версию функции. Совместимость конкретной сборки PHP, SQLSRV и ODBC проверяется отдельно; исторические версии из примеров не являются требованием. · sqlsrv

sqlsrv_get_config(string $setting): mixed

Прочитать действующую настройку перед временным изменением и отличить false-настройку от ошибки имени.

Путь действия
  1. Запрашиваем точное имя настройки
  2. Получаем её действующее значение
  3. Если это false, проверяем диагностику того же вызова
  4. Сохраняем значение для finally
  5. После восстановления ещё раз читаем настройку и сравниваем

Сигнатура и входные значения

sqlsrv_get_config(string $setting): mixed

Это справочная запись типов и аргументов. Копируемые вызовы приведены ниже; слово resource в описании обозначает служебный ресурс PHP.

ПараметрНазначение
$settingТочное имя настройки, перечисленное у sqlsrv_configure. Опечатка не означает «настройка выключена». У функции нет аргумента соединения.

Что возвращается

Текущее значение настройки. Для неподдерживаемого имени возвращается false и записывается диагностика. Но false может быть самим допустимым значением: сразу прочитайте sqlsrv_errors, чтобы различить эти случаи.

Два применения

Перед отчётом нужна исходная политика. Проверка $before === false без диагностики ошибочно запретила бы корректную выключенную настройку. Полный опыт восстанавливает именно прочитанное значение.

$before = sqlsrv_get_config('WarningsReturnAsErrors');
$diagnostics = sqlsrv_errors(SQLSRV_ERR_ALL);
if ($diagnostics !== null) {
    throw new RuntimeException('Не удалось прочитать настройку');
}

Полная программа и её результат.

Похожая опечатка может годами скрываться в диагностическом коде. Здесь намеренно неверное имя показывает необходимость читать диагностику. Не исправляйте его молчаливым значением по умолчанию; полная программа отдельно сравнивает поддерживаемую настройку до и после опыта.

$value = sqlsrv_get_config('WarningReturnAsErrors');
$diagnostics = sqlsrv_errors(SQLSRV_ERR_ALL);
// В имени пропущена s: это не выключенная WarningsReturnAsErrors.

Полная программа и её результат.

Ошибки и границы

get_config читает настройку PHP SQLSRV, а не конфигурацию SQL Server и не переменные ODBC. Значение может отличаться от документированного исходного, потому что php.ini или предыдущий код уже изменили его. Снимок относится к этому процессу: он не доказывает настройки PHP под IIS/FPM или другой CLI. Не превращайте false в ошибку автоматически и не заменяйте неизвестное имя пустой строкой. Для постоянной настройки используйте корректную конфигурацию окружения; для локальной — configure и finally.

Допустимые имена, значения и единицы: sqlsrv_configure. Разницу между логическим false, null и числом 0 нужно сохранять при проверке результата.

Версии. PHP.net не сообщает минимальную версию функции. Совместимость конкретной сборки PHP, SQLSRV и ODBC проверяется отдельно; исторические версии из примеров не являются требованием.

Источники и обсуждения

Код и руководство с собой

Скачайте самостоятельные примеры с исходными данными, инструкциями и ожидаемыми результатами. Примеры HTTP и фрагменты для проекта помечены отдельно: им нужно указанное окружение.

Код не исполняется на сайте. Скачайте нужный пример и запускайте его в своём локальном окружении.

Материалы сверены 2026-10-12. Примеры и объяснения написаны для этого руководства; источники и обсуждения доступны в каждой главе.