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

Дерево руководства
Глава 75 · После SQL, транзакций и базовых ibase-функций
Firebird fbird_*: транзакции, ошибки, номера и обновление текущей строки
Альтернативные имена Firebird на четырёх рабочих задачах: конечные транзакции, retaining, диагностика, ID и текущая строка курсора.
Читать существующий fbird-код по его действию
В обслуживаемом проекте встречаются fbird_commit_ret, fbird_errcode или fbird_gen_id. Их названия отличаются от знакомых ibase_*, но ресурсы и механизм работы те же. Чтобы поправить такой код, нужно понять границы операции: какие изменения уже сохранены, какие ещё можно отменить, почему не совпало условие UPDATE и что означает текущая строка курсора.
Результаты этой главы предметные: Cable сохраняется с остатком 8 после отмены пробных значений; резерв оставляет 1 и отделяет нехватку от ошибки -206; после отменённого черновика единственная заявка получает ID 2; курсорная сверка даёт Cable 10, Clamp 14 и неизменный Archive 9. Сначала разберём минимальные вызовы, затем полный код и возможные отказы.
- Существующий код вызывает fbird_*
- Расширение 3.0.1 направляет alias к обработчику ibase_*
- Тот же ресурс соединения / транзакции / результата
- Тот же SQL и реальные строки базы
- Те же обязательные проверки false, количества строк и commit
Аналогия — две надписи на одной и той же кнопке. Она помогает понять равнозначность имени, но не превращает разные кнопки commit, rollback и commit_ret в одинаковое действие. Эти функции нельзя путать между собой только из-за общего префикса. Замена fbird_ на ibase_ не изменяет схему базы, не добавляет SQL-привилегии, не переводит код на PDO и сама по себе ничего не ускоряет.
Предпосылки: подключение, подготовка и получение строк через fbird_*, базовая модель транзакции, ошибки и affected_rows. Если функция отсутствует, сначала проверьте загрузку соответствующего расширения в фактическом PHP/CLI либо web SAPI: окружение Firebird. Не создавайте пользовательскую функцию с тем же именем, чтобы скрыть отсутствие драйвера.
| Рабочая задача | Куда перейти |
|---|---|
| Принятые и отменённые партии | 10 → принятые7 → отменённые99 → окончательные8; close и повторное чтение. |
| Резерв и диагностика | Резерв2 из3, затем affected0; отдельная SQL-опечатка-206. |
| Технический ID заявки | Отменённая строка1; сохранённая строка2 с настоящим названием. |
| Текущая строка курсора | Сверка двух выбранных товаров и неизменный третий. |
Сохранить принятую партию и отменить ошибочную, затем закрыть задачу
Старое приложение принимает результаты пересчёта небольшими партиями. Принятые 7 единиц нужно сохранить; ошибочные 99 — отменить, не потеряв уже принятую партию. Затем исправленные 8 подтверждаются обычным commit, а отдельная пробная запись 100 откатывается. После закрытия и открытия соединения каталог показывает Cable — 8.
- Начальный Cable: 10
- commit_ret подтверждает 7, контекст остаётся
- Черновые 99 → rollback_ret → снова 7
- Исправленные 8 → окончательный commit
- Новая транзакция пишет 100 → обычный rollback
- Закрытие и открытие → сохранено Cable — 8
Первый вызов и его части
$tx = fbird_trans(IBASE_WRITE | IBASE_CONCURRENCY | IBASE_NOWAIT, $db);
if ($tx === false) { throw new RuntimeException("Операция не начата"); }
// Все запросы одной операции получают $tx.
// В конце обязательно проверить fbird_commit($tx) или fbird_rollback($tx).$db — соединение, $tx — отдельная транзакция. Флаги выбирают запись, согласованный снимок и отказ при конфликте без ожидания. Суффикс _ret сохраняет контекст после подтверждения или отмены текущей части работы; обычные commit/rollback завершают его. Это разные операции, а не варианты написания одного результата. После конечного завершения переменная $tx обнуляется и больше не используется.
Видимый результат
| Наблюдение | Результат |
|---|---|
| После commit_ret | 7 |
| Черновое значение до rollback_ret | 99 |
| После rollback_ret | 7 |
| После окончательного commit и отдельного rollback | 8 |
| fbird_close завершился | да |
| После повторного открытия | Cable — 8 |
Полная программа, вспомогательные файлы и архив
<?php
declare(strict_types=1);
require __DIR__.'/lab.php';
$db=null;$owned=$removed=$rows=$checks=$observations=[];
try {
$config=f161Config();$db=f161Connect($config);$runtime=f161Runtime($db,$config);
$name=f161OwnTable($db,$owned,'checkpoints','(ID INTEGER NOT NULL PRIMARY KEY, TITLE VARCHAR(20) NOT NULL, QTY INTEGER NOT NULL CHECK(QTY>=0))');
$q=f161Qualified($name);
f161Command($db,"INSERT INTO $q (ID,TITLE,QTY) VALUES (1,'Cable',10)");f161Commit($db);
$tx=null;
try {
$call=f161Capture(static fn()=>fbird_trans(IBASE_WRITE|IBASE_CONCURRENCY|IBASE_NOWAIT,$db));
if($call['value']===false||$call['warning'])f161Failure('Транзакция не начата',$call);
$tx=$call['value'];unset($call);
f161Command($tx,"UPDATE $q SET QTY=7 WHERE ID=1");
if(fbird_commit_ret($tx)!==true)f161Failure('Принятая партия не сохранена');
$accepted=f161Read($tx,"SELECT QTY FROM $q WHERE ID=1")[0]['QTY'];
f161Command($tx,"UPDATE $q SET QTY=99 WHERE ID=1");
$draft=f161Read($tx,"SELECT QTY FROM $q WHERE ID=1")[0]['QTY'];
if(fbird_rollback_ret($tx)!==true)f161Failure('Черновая партия не отменена');
$afterRetaining=f161Read($tx,"SELECT QTY FROM $q WHERE ID=1")[0]['QTY'];
f161Command($tx,"UPDATE $q SET QTY=8 WHERE ID=1");
if(fbird_commit($tx)!==true)f161Failure('Исправленный остаток не подтверждён');$tx=null;
$call=f161Capture(static fn()=>fbird_trans(IBASE_WRITE|IBASE_CONCURRENCY|IBASE_NOWAIT,$db));
if($call['value']===false||$call['warning'])f161Failure('Новая проверка не начата',$call);
$tx=$call['value'];unset($call);
f161Command($tx,"UPDATE $q SET QTY=100 WHERE ID=1");
if(fbird_rollback($tx)!==true)f161Failure('Новая пробная запись не отменена');$tx=null;
}finally{if(is_resource($tx)){if(fbird_rollback($tx)!==true)f161Failure('Не завершена транзакция');$tx=null;}}
$beforeClose=f161Read($db,"SELECT TITLE,QTY FROM $q WHERE ID=1");
if(fbird_commit($db)!==true)f161Failure('Чтение перед закрытием не закончено');
// No closure captures this consuming connection handle.
$closed=fbird_close($db);$db=null;
if($closed!==true)f161Failure('Соединение не закрыто');
$db=f161Connect($config);
$stored=f161Read($db,"SELECT TITLE,QTY FROM $q WHERE ID=1");f161Commit($db);
$rows=[['После commit_ret', $accepted],['Черновое значение до rollback_ret',$draft],
['После rollback_ret',$afterRetaining],['После окончательного commit и отдельного rollback',$beforeClose[0]['QTY']],
['fbird_close завершился',$closed],['После повторного открытия',$stored[0]['TITLE'].' — '.$stored[0]['QTY']]];
$checks=['accepted_batch_saved'=>$accepted===7,'draft_visible_in_own_context'=>$draft===99,
'retained_rollback_keeps_committed_batch'=>$afterRetaining===7,
'ordinary_rollback_preserves_previous_commit'=>$beforeClose===[['TITLE'=>'Cable','QTY'=>8]],
'alias_close_succeeded'=>$closed===true,'reopened_value_persisted'=>$stored===[['TITLE'=>'Cable','QTY'=>8]]];
$observations=['initial_quantity'=>10,'after_commit_ret'=>$accepted,'draft'=>$draft,'after_rollback_ret'=>$afterRetaining,
'after_final_commit_and_new_rollback'=>$beforeClose,'after_reopen'=>$stored,'retained_context_explicitly_finished'=>true];
} finally {
if (is_resource($db)) {try {$removed=f161Cleanup($db,$owned);} finally {ibase_close($db);}}
}
f161Report('fb161-transaction-checkpoints','Сохранить принятую партию и отменить ошибочную, затем закрыть задачу',$rows,$checks,$observations,$runtime,$owned,$removed);
Ожидаемый результат
После commit_ret — 7
Черновое значение до rollback_ret — 99
После rollback_ret — 7
После окончательного commit и отдельного rollback — 8
fbird_close завершился — да
После повторного открытия — Cable — 8
Распакуйте весь архив и запустите example.php по README.txt. lab.php проверяет отдельную учебную базу, создаёт только собственные FB161-объекты и убирает их в finally. Первый запуск требует подготовленной лаборатории, описанной в README; рабочие базы не используются. result.html показывает реальные значения, result.json — наблюдения, metrics.json — проверки и удаление собственных объектов. Создаваемые таблицы и последовательность не остаются после успешного завершения, а файлы отчёта сохраняются.
Открыть фактическую таблицу результата · Открыть данные JSON.
Границы и типичные ошибки
Retaining нужен для понимания уже существующего кода, а не как рекомендация держать веб-транзакцию часами. Сохраняются контекст и связанные ресурсы; не обещается обновление снимка до последних чужих изменений. Для новой простой формы обычно понятнее короткая транзакция с обычным завершением. Rollback не отменяет принятую ранее партию и не восстанавливает историю commit. Перед закрытием соединения чтение и все явные транзакции завершены явно; не используем побочное подтверждение default-транзакции при close как алгоритм сохранения.
В реальном обсуждении разработчик сопоставляет противоречащие старые советы о бесконечном commit retaining и производительности Firebird/InterBase. Исходное обсуждение. Здесь retaining показан как конечный этап уже существующего алгоритма: принятые7 сохраняются,99 отменяются, затем контекст окончательно завершается. Исторические рассуждения о другой СУБД не объявляются измеренным результатом нашего профиля; ускорения пример не обещает.
Долгоживущий PHP-скрипт смешивает явную и стандартную транзакции соединения; в вопросе также описан сбой очень старой версии драйвера. Исходное обсуждение. Мы явно сохраняем $tx, передаём его SQL и завершаем именно его. Отдельный db выбирает default-контекст. Исторический crash не переносится на текущую сборку как её подтверждённое свойство.
Проверьте понимание
Почему отмена 99 вернула 7, а не исходные 10?
Разбор
Изменение 10 → 7 уже подтверждено commit_ret. Rollback_ret относится к последующей неподтверждённой части того же сохранённого контекста. Если все партии должны быть неделимы, не ставьте между ними commit_ret: завершите общую транзакцию только после последней проверки.
Отличить нехватку товара от сломанного SQL и сохранить причину
На складе 3 единицы Cable. Первый заказ резервирует 2, остаётся 1. Второй пытается забрать 4: SQL корректен, но условие QTY >= 4 не совпало ни с одной строкой. Это отказ бизнес-условия с affected_rows = 0. Опечатка NOT_A_FIELD — другой случай: настоящий SQL-отказ с кодом -206, который нужно сохранить до следующего вызова.
- Cable: 3 → UPDATE с условием запаса → affected_rows = 1 → commit
- Запрос 4 при остатке 1 → успешная команда, affected_rows = 0
- NOT_A_FIELD → false → немедленно errcode и errmsg
- Исправленный SELECT показывает Cable — 1
- Текущая ошибка очищена, сохранённый снимок -206 остаётся
Первый вызов и его части
$changed = fbird_query($db, "UPDATE STOCK SET QTY=QTY-? WHERE ID=? AND QTY>=?", 2, 1, 2);
if ($changed === false) {
$code = fbird_errcode();
$message = fbird_errmsg();
} else {
$count = fbird_affected_rows($db);
}Вопросительные знаки получают значения по порядку. SQL сам проверяет доступный запас в момент UPDATE; загружать весь склад в PHP и считать там не требуется. false означает отказ вызова; ноль от affected_rows означает отсутствие подходящих изменённых строк. Снимок ошибки нужно снимать до affected_rows, rollback, следующего query и очистки ресурсов: они могут сменить состояние диагностики.
Видимый результат
| Наблюдение | Результат |
|---|---|
| Первый резерв: изменено строк | 1 |
| Остаток Cable после резерва | 1 |
| Второй UPDATE успешно выполнился | да |
| Второй резерв: изменено строк | 0 |
| Запрос неизвестного поля вернул false | да |
| Сохранённый SQLCODE | -206 |
| Сообщение указывает неизвестное поле | да |
| После исправленного чтения ошибки больше нет | да |
Полная программа, вспомогательные файлы и архив
<?php
declare(strict_types=1);
require __DIR__.'/lab.php';
$db=null;$owned=$removed=$rows=$checks=$observations=[];
try {
$config=f161Config();$db=f161Connect($config);$runtime=f161Runtime($db,$config);
$name=f161OwnTable($db,$owned,'outcome','(ID INTEGER NOT NULL PRIMARY KEY, TITLE VARCHAR(20) NOT NULL, QTY INTEGER NOT NULL CHECK(QTY>=0))');
$q=f161Qualified($name);f161Command($db,"INSERT INTO $q VALUES (1,'Cable',3)");f161Commit($db);
$first=fbird_query($db,"UPDATE $q SET QTY=QTY-? WHERE ID=? AND QTY>=?",2,1,2);
if($first===false)f161Failure('Резервирование не выполнено');
$firstCount=fbird_affected_rows($db);
if($firstCount!==1)throw new RuntimeException('Ожидался один зарезервированный товар');
if(fbird_commit($db)!==true)f161Failure('Резерв не сохранён');
$second=fbird_query($db,"UPDATE $q SET QTY=QTY-? WHERE ID=? AND QTY>=?",4,1,4);
if($second===false)f161Failure('Проверка второго резерва не выполнена');
$secondCount=fbird_affected_rows($db);
if(!is_int($secondCount))f161Failure('Число изменённых строк недоступно');
$warning=false;
set_error_handler(static function(int $level,string $message)use(&$warning):bool{$warning=true;return true;},E_WARNING);
try {
$bad=fbird_query($db,"SELECT NOT_A_FIELD FROM $q");
$savedCode=fbird_errcode();$savedMessage=fbird_errmsg();
}finally{restore_error_handler();}
$messagePresent=is_string($savedMessage)&&$savedMessage!=='';
$mentionsField=$messagePresent&&str_contains($savedMessage,'NOT_A_FIELD');unset($savedMessage);
$stored=f161Read($db,"SELECT TITLE,QTY FROM $q WHERE ID=1");
$currentCode=fbird_errcode();$currentMessage=fbird_errmsg();
if(fbird_commit($db)!==true)f161Failure('Читающая транзакция не завершена');
$rows=[['Первый резерв: изменено строк',$firstCount],['Остаток Cable после резерва',$stored[0]['QTY']],
['Второй UPDATE успешно выполнился',$second===true],['Второй резерв: изменено строк',$secondCount],
['Запрос неизвестного поля вернул false',$bad===false],['Сохранённый SQLCODE',$savedCode],
['Сообщение указывает неизвестное поле',$mentionsField],['После исправленного чтения ошибки больше нет',$currentCode===false&&$currentMessage===false]];
$checks=['first_reservation_changed_one'=>$firstCount===1,'remaining_one'=>$stored===[['TITLE'=>'Cable','QTY'=>1]],
'insufficient_stock_is_zero_not_failure'=>$second===true&&$secondCount===0,
'sql_failure_recorded'=>$bad===false&&$savedCode===-206&&$warning&&$messagePresent&&$mentionsField,
'successful_read_clears_current_error'=>$currentCode===false&&$currentMessage===false];
$observations=['first_affected'=>$firstCount,'second_return'=>$second,'second_affected'=>$secondCount,'stored'=>$stored,
'saved_error'=>['code'=>$savedCode,'warning'=>$warning,'message_present'=>$messagePresent,'mentions_field'=>$mentionsField],
'current_code'=>$currentCode,'current_message'=>$currentMessage,'raw_error_published'=>false];
} finally {
if (is_resource($db)) {try {$removed=f161Cleanup($db,$owned);} finally {ibase_close($db);}}
}
f161Report('fb161-update-diagnostics','Отличить нехватку товара от сломанного SQL и сохранить причину',$rows,$checks,$observations,$runtime,$owned,$removed);
Ожидаемый результат
Первый резерв: изменено строк — 1
Остаток Cable после резерва — 1
Второй UPDATE успешно выполнился — да
Второй резерв: изменено строк — 0
Запрос неизвестного поля вернул false — да
Сохранённый SQLCODE — -206
Сообщение указывает неизвестное поле — да
После исправленного чтения ошибки больше нет — да
Распакуйте весь архив и запустите example.php по README.txt. lab.php проверяет отдельную учебную базу, создаёт только собственные FB161-объекты и убирает их в finally. Первый запуск требует подготовленной лаборатории, описанной в README; рабочие базы не используются. result.html показывает реальные значения, result.json — наблюдения, metrics.json — проверки и удаление собственных объектов. Создаваемые таблицы и последовательность не остаются после успешного завершения, а файлы отчёта сохраняются.
Открыть фактическую таблицу результата · Открыть данные JSON.
Границы и типичные ошибки
Ноль не говорит сам по себе, почему условие не совпало: отсутствует ID, недостаточен запас или не совпала версия записи. Текущий учебный набор известен заранее. В рабочем интерфейсе при необходимости отдельно уточняют причину разрешённым чтением. SQLCODE не является SQLSTATE или историей ошибок по соединениям. Текст диагностики может содержать внутренние пути и данные: здесь сохраняются только код и безопасные признаки, а не сырая строка. Успешная команда также требует явного commit для сохранения.
Проверьте понимание
Можно ли сначала выполнить исправленный SELECT, а затем вызвать errcode, чтобы узнать причину предыдущего отказа?
Разбор
Нет: состояние расширения уже могло очиститься. Сохраните код и сообщение сразу после false, затем выполняйте восстановление. Обычная PHP-переменная с сохранённым -206 останется доступна, даже когда текущее errcode уже вернёт false.
Сохранить заявку с новым номером и объяснить пропуск после отмены
Заявке нужен технический ID до сохранения, чтобы подготовить связанные действия. Первая выдача возвращает 1, но черновик отменяется. Следующая сохранённая заявка получает 2. Увидим саму строку «Подтверждённая заявка», а не только число вызовов: в таблице одна запись с ID = 2.
- Собственная последовательность: 0
- fbird_gen_id выдаёт 1 → INSERT черновика
- rollback отменяет строку, счётчик остаётся 1
- Новая выдача → 2 → INSERT + commit
- SELECT: ID 2, Подтверждённая заявка
Первый вызов и его части
$id = fbird_gen_id("APPLICATION_ID_SEQ", 1, $db);
if ($id === false) { throw new RuntimeException("ID не выдан"); }
// Передайте $id параметром в INSERT и подтвердите транзакцию.Первый аргумент — имя уже созданной последовательности. Шаг 1 увеличивает её и возвращает новое число; шаг 0 читает текущее состояние. Третий аргумент выбирает соединение. Сам gen_id не создаёт заявку и не подтверждает INSERT. В полной программе опущенный шаг первого вызова также проверяет документированное значение по умолчанию 1.
Видимый результат
| Наблюдение | Результат |
|---|---|
| Исходный счётчик | 0 |
| ID отменённого черновика | 1 |
| Черновиков осталось | 0 |
| Счётчик после rollback | 1 |
| ID сохранённой заявки | 2 |
| Сохранённая заявка | Подтверждённая заявка |
| Строк в таблице | 1 |
Полная программа, вспомогательные файлы и архив
<?php
declare(strict_types=1);
require __DIR__.'/lab.php';
$db=null;$owned=$removed=$rows=$checks=$observations=[];
try {
$config=f161Config();$db=f161Connect($config);$runtime=f161Runtime($db,$config);
$name=f161OwnTable($db,$owned,'ids','(ID BIGINT NOT NULL PRIMARY KEY, TITLE VARCHAR(60) CHARACTER SET UTF8 NOT NULL)');
$q=f161Qualified($name);$sequence=f161OwnSequence($db,$owned,'id_seq');
$initial=fbird_gen_id($sequence,0,$db);if($initial===false)f161Failure('Счётчик не прочитан');
$first=fbird_gen_id($sequence);if($first===false)f161Failure('Первый ID не выдан');
$tx=null;
try {
$tx=fbird_trans(IBASE_WRITE|IBASE_CONCURRENCY|IBASE_NOWAIT,$db);
if($tx===false)f161Failure('Транзакция заявки не создана');
f161Command($tx,"INSERT INTO $q VALUES (?,?)",[$first,'Черновая заявка']);
if(fbird_rollback($tx)!==true)f161Failure('Черновик не отменён');$tx=null;
}finally{if(is_resource($tx)){fbird_rollback($tx);$tx=null;}}
$afterRollback=fbird_gen_id($sequence,0,$db);if($afterRollback===false)f161Failure('Счётчик после отмены недоступен');
$cancelled=(int)f161Read($db,"SELECT COUNT(*) AS N FROM $q WHERE ID=?",[$first])[0]['N'];
$next=fbird_gen_id($sequence,1,$db);if($next===false)f161Failure('Новый ID не выдан');
f161Command($db,"INSERT INTO $q VALUES (?,?)",[$next,'Подтверждённая заявка']);
if(fbird_commit($db)!==true)f161Failure('Заявка не сохранена');
$stored=f161Read($db,"SELECT ID,TITLE FROM $q ORDER BY ID");f161Commit($db);
$rows=[['Исходный счётчик',$initial],['ID отменённого черновика',$first],['Черновиков осталось',$cancelled],
['Счётчик после rollback',$afterRollback],['ID сохранённой заявки',$stored[0]['ID']],['Сохранённая заявка',$stored[0]['TITLE']],['Строк в таблице',count($stored)]];
$checks=['initial_zero'=>$initial===0,'first_id_one'=>$first===1,'cancelled_row_absent'=>$cancelled===0,
'sequence_not_rolled_back'=>$afterRollback===1,'next_id_two'=>$next===2,
'saved_application'=>$stored===[['ID'=>2,'TITLE'=>'Подтверждённая заявка']]];
$observations=['initial'=>$initial,'allocated_first'=>$first,'cancelled_row_count'=>$cancelled,'sequence_after_rollback'=>$afterRollback,'next'=>$next,'stored'=>$stored,'sequence_decrement_attempted'=>false];
} finally {
if (is_resource($db)) {try {$removed=f161Cleanup($db,$owned);} finally {ibase_close($db);}}
}
f161Report('fb161-generated-id','Сохранить заявку с новым номером и объяснить пропуск после отмены',$rows,$checks,$observations,$runtime,$owned,$removed);
Ожидаемый результат
Исходный счётчик — 0
ID отменённого черновика — 1
Черновиков осталось — 0
Счётчик после rollback — 1
ID сохранённой заявки — 2
Сохранённая заявка — Подтверждённая заявка
Строк в таблице — 1
Распакуйте весь архив и запустите example.php по README.txt. lab.php проверяет отдельную учебную базу, создаёт только собственные FB161-объекты и убирает их в finally. Первый запуск требует подготовленной лаборатории, описанной в README; рабочие базы не используются. result.html показывает реальные значения, result.json — наблюдения, metrics.json — проверки и удаление собственных объектов. Создаваемые таблицы и последовательность не остаются после успешного завершения, а файлы отчёта сохраняются.
Открыть фактическую таблицу результата · Открыть данные JSON.
Границы и типичные ошибки
Генератор Firebird — последовательность базы, не PHP-генератор yield. Счётчик не откатывается вместе со строкой: не уменьшайте его после ошибки и не вычисляйте будущий ID как MAX(ID)+1. Другой процесс уже мог получить значение. Пропуск технического ID допустим; непрерывная бизнес-нумерация документов требует отдельной модели. На PHP x64 малые значения возвращаются int; большое значение на узкой платформе может быть строкой. Не переводите его в float. В pinned-драйвере имя ограничено 31 байтом и вставляется в SQL: здесь оно создаётся нашим helper, а не берётся из запроса пользователя.
Автор пытается вернуть выданный генератором номер после неудачного INSERT и получить нумерацию без пропусков. Исходное обсуждение. Показываем реальные данные: отменённой строки1 нет, счётчик остаётся1, сохранённая заявка получает2. Генератор не уменьшается; непрерывная бизнес-нумерация отделена от технического ключа.
Проверьте понимание
Почему ID = 2 не означает, что в таблице точно существуют две заявки?
Разбор
Последовательность считает выдачи значений, а не сохранённые строки. Первая выдача была использована отменённым INSERT. Число заявок получают отдельным COUNT с нужным условием; счётчик ID не заменяет этот запрос.
Изменить текущую строку курсора, не затронув товар вне выборки
В существующей программе пересчёт устроен через изменяемый курсор. Для Cable уже известно число 10, для Clamp — 14. Имя курсора связывает UPDATE с только что прочитанной строкой. После commit эти два товара изменены, а Archive, не входивший в выборку, сохраняет 9.
- SELECT ID<=2 FOR UPDATE → открытый результат
- fbird_name_result задаёт FB161_STOCK_CURSOR
- fetch делает одну строку текущей
- UPDATE WHERE CURRENT OF меняет именно её; affected_rows = 1
- free_query + free_result → commit
- Новый SELECT ORDER BY ID показывает Cable10 / Clamp14 / Archive9
Первый вызов и его части
if (fbird_name_result($result, "STOCK_CURSOR") !== true) {
throw new RuntimeException("Курсор не назван");
}
// После успешного fetch: UPDATE ... WHERE CURRENT OF STOCK_CURSOR.$result — ресурс открытого SELECT. Имя позволяет SQL-команде обратиться к его текущей позиции; оно не является ID товара и не переименовывает таблицу. Текущая строка появляется после успешного fetch. Выборка и подготовленный UPDATE используют одну явную транзакцию. Данные пересчёта уже готовы до её открытия; ожидать действий пользователя с открытым курсором не нужно.
Видимый результат
| Наблюдение | Результат |
|---|---|
| Курсор получил имя | да |
| Cable до сверки | 0 |
| Cable после сверки | 10 |
| Clamp до сверки | 4 |
| Clamp после сверки | 14 |
| Archive вне выборки | 9 |
| Изменено текущих строк | 2 |
| Конец выдачи без ошибки | да |
Полная программа, вспомогательные файлы и архив
<?php
declare(strict_types=1);
require __DIR__.'/lab.php';
$db=null;$owned=$removed=$rows=$checks=$observations=[];
try {
$config=f161Config();$db=f161Connect($config);$runtime=f161Runtime($db,$config);
$name=f161OwnTable($db,$owned,'cursor','(ID INTEGER NOT NULL PRIMARY KEY, TITLE VARCHAR(20) NOT NULL, QTY INTEGER NOT NULL)');
$q=f161Qualified($name);
foreach([[1,'Cable',0],[2,'Clamp',4],[3,'Archive',9]] as $item)f161Command($db,"INSERT INTO $q VALUES (?,?,?)",$item);
f161Commit($db);$counted=[1=>10,2=>14];$tx=$cursor=$update=null;$applied=[];$cleanEof=false;
try {
$call=f161Capture(static fn()=>fbird_trans(IBASE_WRITE|IBASE_CONCURRENCY|IBASE_NOWAIT,$db));
if($call['value']===false||$call['warning'])f161Failure('Транзакция сверки не создана',$call);
$tx=$call['value'];unset($call);
$cursor=f161Query($tx,"SELECT ID,QTY FROM $q WHERE ID<=2 FOR UPDATE OF QTY");
$named=fbird_name_result($cursor,'FB161_STOCK_CURSOR');if($named!==true)f161Failure('Курсор не назван');
$call=f161Capture(static fn()=>fbird_prepare($tx,"UPDATE $q SET QTY=? WHERE CURRENT OF FB161_STOCK_CURSOR"));
if($call['value']===false||$call['warning'])f161Failure('UPDATE не подготовлен',$call);
$update=$call['value'];unset($call);
while(true){
$call=f161Capture(static fn()=>fbird_fetch_row($cursor));
if($call['warning']||$call['code']!==0)f161Failure('Строка не прочитана',$call);
if($call['value']===false){$cleanEof=true;break;}
$current=$call['value'];unset($call);$id=$current[0];
if(!array_key_exists($id,$counted))throw new RuntimeException('Нет подтверждённого пересчёта');
$call=f161Capture(static fn()=>fbird_execute($update,$counted[$id]));
if($call['value']===false||$call['warning'])f161Failure('Текущий товар не изменён',$call);
$changed=fbird_affected_rows($tx);if($changed!==1)throw new RuntimeException('Ожидалась одна текущая строка');
$applied[$id]=['before'=>$current[1],'after'=>$counted[$id],'changed'=>$changed];unset($call);
}
if(fbird_free_query($update)!==true)f161Failure('Подготовка не освобождена');$update=null;
if(fbird_free_result($cursor)!==true)f161Failure('Курсор не освобождён');$cursor=null;
if(fbird_commit($tx)!==true)f161Failure('Сверка не подтверждена');$tx=null;
}finally{
if(is_resource($update)){fbird_free_query($update);$update=null;}
if(is_resource($cursor)){fbird_free_result($cursor);$cursor=null;}
if(is_resource($tx)){fbird_rollback($tx);$tx=null;}
}
$stored=f161Read($db,"SELECT ID,TITLE,QTY FROM $q ORDER BY ID");f161Commit($db);
$rows=[['Курсор получил имя',$named],['Cable до сверки',$applied[1]['before']],['Cable после сверки',$stored[0]['QTY']],
['Clamp до сверки',$applied[2]['before']],['Clamp после сверки',$stored[1]['QTY']],['Archive вне выборки',$stored[2]['QTY']],['Изменено текущих строк',count($applied)],['Конец выдачи без ошибки',$cleanEof]];
$checks=['cursor_named'=>$named===true,'two_current_rows_changed'=>count($applied)===2,
'first_transition'=>$applied[1]===['before'=>0,'after'=>10,'changed'=>1],
'second_transition'=>$applied[2]===['before'=>4,'after'=>14,'changed'=>1],
'committed_catalogue'=>$stored===[['ID'=>1,'TITLE'=>'Cable','QTY'=>10],['ID'=>2,'TITLE'=>'Clamp','QTY'=>14],['ID'=>3,'TITLE'=>'Archive','QTY'=>9]],'clean_eof'=>$cleanEof];
$observations=['cursor_name'=>'FB161_STOCK_CURSOR','applied'=>$applied,'stored'=>$stored,'selection'=>'ID<=2','same_transaction'=>true,'resources_released_before_commit'=>true];
} finally {
if (is_resource($db)) {try {$removed=f161Cleanup($db,$owned);} finally {ibase_close($db);}}
}
f161Report('fb161-positioned-update','Изменить текущую строку курсора, не затронув товар вне выборки',$rows,$checks,$observations,$runtime,$owned,$removed);
Ожидаемый результат
Курсор получил имя — да
Cable до сверки — 0
Cable после сверки — 10
Clamp до сверки — 4
Clamp после сверки — 14
Archive вне выборки — 9
Изменено текущих строк — 2
Конец выдачи без ошибки — да
Распакуйте весь архив и запустите example.php по README.txt. lab.php проверяет отдельную учебную базу, создаёт только собственные FB161-объекты и убирает их в finally. Первый запуск требует подготовленной лаборатории, описанной в README; рабочие базы не используются. result.html показывает реальные значения, result.json — наблюдения, metrics.json — проверки и удаление собственных объектов. Создаваемые таблицы и последовательность не остаются после успешного завершения, а файлы отчёта сохраняются.
Открыть фактическую таблицу результата · Открыть данные JSON.
Границы и типичные ошибки
В исходной выборке не задан ORDER BY: порядок обхода не обещается, пересчёт выбирается по ID. Итоговый SELECT упорядочен явно. Сохранённый массив PHP не сохраняет позицию курсора и не обновляется автоматически после UPDATE. Курсор не применим к любой агрегированной выборке. Для обычной формы проще короткий UPDATE WHERE ID=? AND VERSION=? с affected_rows, а для общего правила — одна SQL-команда над набором. Имя курсора фиксировано приложением и не принимается из HTTP. Этот опыт не измеряет блокировки и не обещает их отсутствие.
Проверьте понимание
Можно ли закрыть SELECT, затем обходить полученный ранее массив и выполнять WHERE CURRENT OF?
Разбор
Нет: массив хранит значения, но открытой серверной позиции уже нет. Либо изменяйте текущую строку до следующего fetch и до закрытия курсора, либо используйте ключи/версию записи в отдельных коротких запросах.
Справочник одиннадцати имён и их контрактов
| Alias | Задача | Соответствующая карточка ibase |
|---|---|---|
| fbird_trans | Создать явный транзакционный контекст для связанных запросов. | ibase_trans |
| fbird_commit | Подтвердить и окончательно закончить выбранную транзакцию. | ibase_commit |
| fbird_rollback | Отменить неподтверждённые изменения и закончить транзакцию. | ibase_rollback |
| fbird_commit_ret | Подтвердить текущую часть работы, сохранив контекст для продолжения. | ibase_commit_ret |
| fbird_rollback_ret | Отменить текущую часть работы без закрытия её контекста. | ibase_rollback_ret |
| fbird_affected_rows | Проверить число строк предыдущего INSERT, UPDATE или DELETE. | ibase_affected_rows |
| fbird_errcode | Снять числовой код последнего отказа до следующего вызова. | ibase_errcode |
| fbird_errmsg | Сохранить текст причины и безопасно отделить его от публичного ответа. | ibase_errmsg |
| fbird_close | Завершить использование обычного подключения после явного окончания работы. | ibase_close |
| fbird_gen_id | Выдать или прочитать значение существующей последовательности. | ibase_gen_id |
| fbird_name_result | Назвать открытый курсор для изменения его текущей строки. | ibase_name_result |
Сохранять понятную границу операции при любом имени функции
При сопровождении начните с результата задачи: конкретный остаток, сохранённая заявка или безопасный отказ. Затем найдите ресурс, к которому относится вызов. Явная транзакция и default-транзакция соединения не заменяют друг друга; result и подготовленный statement имеют собственный срок жизни. Префикс fbird_ этих правил не меняет.
Для короткого веб-запроса обычно достаточно понятного SQL с нужными WHERE, полями и порядком, параметров для значений и обычного commit/rollback. Retaining и именованный курсор разобраны, чтобы понимать и корректно поддерживать программы, где они уже используются. Дальше: формы результатов и параметры fbird_*, ID и модели результата, права на SQL-действия.
Функции и методы этой темы
Откройте карточку, чтобы увидеть договор функции, примеры, ограничения и связанные инструменты.
fbird_transСоздать явный транзакционный контекст для связанных запросов.
PHP5 / PHP7 <7.4; далее отдельное расширение. Целевой профиль interbase3.0.1 / PHP8.2. · interbase
fbird_trans(int $trans_args = ?, resource $link_identifier = ?): resource|falseКогда несколько запросов должны составлять одну операцию, сначала создают явную транзакцию и передают её всем частям этой операции. fbird_trans — зарегистрированное расширением альтернативное имя ibase_trans. Ресурсы, правила аргументов и результат у этой пары общие; смена префикса не создаёт другой способ работы с базой.
fbird_trans(): resource|false
fbird_trans(resource $connection): resource|false
fbird_trans(int $flags, resource $connection): resource|false| Параметр или результат | Что означает |
|---|---|
| $flags / trans_args | Маска настроек, объединяемых через |. Варианты одной группы могут быть несовместимы. |
| $connection / link_identifier | Живой ресурс соединения. При отсутствии используется последнее открытое соединение. |
| Без аргументов или только flags | Новое явное выполнение для последнего соединения со стандартными либо указанными настройками. |
| resource | Ресурс новой транзакции. Первый вызов не возвращает уже существующую default-транзакцию соединения. |
| false | Начать транзакцию не удалось; сразу сохранить errcode/errmsg. Неверные PHP-типы или ресурсы могут вызвать отдельную ошибку PHP. |
Страница PHP Manual относит имя к PHP5 и встроенному расширению PHP7 до 7.4. После удаления расширения из комплекта PHP оно устанавливается отдельно; наличие имени нужно проверять в используемой сборке. Здесь целевой профиль PHP8.2.35 / interbase3.0.1 / Firebird5.0.4. В исходнике этой версии PHP_FALIAS связывает два имени с одним обработчиком. Это не ускорение, не миграция на PDO и не изменение версии SQL-сервера.
| Группа/константа | Смысл |
|---|---|
| IBASE_READ / IBASE_WRITE | Только чтение обычных постоянных таблиц либо чтение и запись. Выберите один режим; это не выдача SQL-привилегий. |
| IBASE_CONCURRENCY | SNAPSHOT: согласованный снимок подтверждённых данных на начало транзакции плюс её собственные изменения. |
| IBASE_CONSISTENCY | SNAPSHOT TABLE STABILITY: более строгий режим с ограничениями конкурентного доступа к таблицам. |
| IBASE_COMMITTED | READ COMMITTED. Детали видимости и конфликтов зависят также от версии и настроек Firebird. |
| IBASE_REC_VERSION / IBASE_REC_NO_VERSION | Альтернативные классические модификаторы READ COMMITTED: работа с доступной подтверждённой версией либо учёт конфликтующей текущей версии. Не объединяйте оба. |
| IBASE_WAIT / IBASE_NOWAIT | Ожидать разрешение конфликта либо получить отказ без такого ожидания. NOWAIT не отменяет блокировки, WAIT не задаёт количество секунд. |
| IBASE_DEFAULT | Стандартные настройки драйвера/клиента. Это не autocommit и не команда выбрать прежнюю default-транзакцию. |
Все девять флагов краткой официальной страницы перечислены выше; DEFAULT объясняет дополнительный стандартный режим. В Firebird4/5 настройка ReadConsistency влияет на трактовку классических модификаторов COMMITTED: нельзя обещать поведение любой установки только по одной константе. В примерах задан CONCURRENCY, а не проводится тест конкурентной нагрузки.
Применение 1: сохранить согласованный пересчёт
$tx = fbird_trans(IBASE_WRITE | IBASE_CONCURRENCY | IBASE_NOWAIT, $db);
if ($tx === false) { throw new RuntimeException("Пересчёт не начат"); }
// UPDATE обеих выбранных строк получает именно $tx.
// Проверить affected_rows, освободить результаты, затем commit/rollback.Полный пересчёт подтверждает Cable10 и Clamp14 одной транзакцией. Передача $db вместо $tx незаметно выбрала бы другой, стандартный контекст соединения.
Применение 2: один снимок для составного отчёта
$tx = fbird_trans(IBASE_READ | IBASE_CONCURRENCY | IBASE_NOWAIT, $db);
if ($tx === false) { throw new RuntimeException("Отчёт не начат"); }
// Несколько SELECT отчёта выполняются через $tx.
// Освободить результаты; завершить чтение обычным fbird_commit($tx).Это контекстный фрагмент: таблицы отчёта зависят от вашей задачи. Даже чтение имеет срок жизни; не оставляйте снимок открытым, пока посетитель рассматривает готовую страницу. Самостоятельный пример показывает отличие сохранённого контекста от окончательного завершения.
Полная форма допускает несколько пар настроек и соединений: fbird_trans($flagsA, $dbA, $flagsB, $dbB). Последняя заданная маска применяется к следующим соединениям до новой маски. Драйвер поддерживает распределённую транзакцию с двухфазным commit; query/prepare тогда должны получить и нужный link, и общий transaction. Это не JOIN таблиц разных баз в одном SELECT. При сбое между фазами возможны limbo-транзакции и административное восстановление; многобазовый вариант здесь является объяснением контракта и не входит в четыре выполненных проекта. Незавершённые явные транзакции в конце скрипта откатываются, но это аварийная граница. В нормальном коде каждый путь заканчивается явно.
fbird_commitПодтвердить и окончательно закончить выбранную транзакцию.
PHP5 / PHP7 <7.4; далее отдельное расширение. Целевой профиль interbase3.0.1 / PHP8.2. · interbase
fbird_commit(resource $link_or_trans_identifier = ?): boolСогласованную часть операции нужно сохранить. Эта функция окончательно завершает выбранную транзакцию. fbird_commit — зарегистрированное расширением альтернативное имя ibase_commit. Ресурсы, правила аргументов и результат у этой пары общие; смена префикса не создаёт другой способ работы с базой.
fbird_commit(): bool
fbird_commit(resource $connectionOrTransaction): bool| Параметр или результат | Что означает |
|---|---|
| Без аргумента | Default-транзакция последнего/default-соединения, а не все транзакции процесса. |
| $connectionOrTransaction = соединение | Выбирается default-транзакция этого соединения. |
| $connectionOrTransaction = транзакция | Выбирается переданная явная транзакция. В рабочих сценариях это переменная $tx. |
| true | Удалось подтвердить выбранную часть работы. Явный контекст завершён; после этого его не используют. |
| false | Отказ; сохранить диагностику немедленно и не сообщать пользователю об успешном сохранении/отмене. |
Страница PHP Manual относит имя к PHP5 и встроенному расширению PHP7 до 7.4. После удаления расширения из комплекта PHP оно устанавливается отдельно; наличие имени нужно проверять в используемой сборке. Здесь целевой профиль PHP8.2.35 / interbase3.0.1 / Firebird5.0.4. В исходнике этой версии PHP_FALIAS связывает два имени с одним обработчиком. Это не ускорение, не миграция на PDO и не изменение версии SQL-сервера.
Управляющих флагов нет. В краткой сигнатуре canonical-страницы необязательный ресурс показан со значением null. Парсер interbase3.0.1 ожидает переданный аргумент типа resource: для выбора по умолчанию опустите аргумент, а не подставляйте явный null. Неподходящий или уже освобождённый ресурс может дать предупреждение либо PHP-ошибку; это не новый пустой контекст.
Применение 1: принять исправленные остатки
if (fbird_commit($tx) !== true) {
$code = fbird_errcode();
$message = fbird_errmsg();
throw new RuntimeException("Остатки не подтверждены");
}
$tx = null;Полный сценарий окончательно сохраняет Cable8 после проверки исправления. Успешный UPDATE до этой строки не заменяет commit; уже прочитанный массив PHP сам не обновляется.
Применение 2: закончить согласованное чтение отчёта
// Все результаты SELECT уже скопированы в PHP и освобождены.
if (fbird_commit($reportTx) !== true) {
throw new RuntimeException("Чтение отчёта не завершено");
}
$reportTx = null;
// Теперь сформировать HTML из обычных PHP-массивов.Отчёт с явной READ-транзакцией тоже должен освободить контекст. Это каркас окончания уже выполненного чтения; данные отчёта не удаляются из массивов при завершении транзакции. Пересчёт курсором также освобождает SELECT и подготовку перед окончательным commit.
После успешного завершения обнулите переменную явной транзакции; она больше не подходит для следующего запроса. Функция действует только на выбранную транзакцию, не на все соединения и не на историю ранее подтверждённых операций. Если действие вернуло false, его причина сохраняется до cleanup. Полная модель и условия выбора есть в ibase_commit.
fbird_rollbackОтменить неподтверждённые изменения и закончить транзакцию.
PHP5 / PHP7 <7.4; далее отдельное расширение. Целевой профиль interbase3.0.1 / PHP8.2. · interbase
fbird_rollback(resource $link_or_trans_identifier = ?): boolОшибочный или отменённый пользователем черновик не должен остаться в базе. Эта функция окончательно завершает выбранную транзакцию. fbird_rollback — зарегистрированное расширением альтернативное имя ibase_rollback. Ресурсы, правила аргументов и результат у этой пары общие; смена префикса не создаёт другой способ работы с базой.
fbird_rollback(): bool
fbird_rollback(resource $connectionOrTransaction): bool| Параметр или результат | Что означает |
|---|---|
| Без аргумента | Default-транзакция последнего/default-соединения, а не все транзакции процесса. |
| $connectionOrTransaction = соединение | Выбирается default-транзакция этого соединения. |
| $connectionOrTransaction = транзакция | Выбирается переданная явная транзакция. В рабочих сценариях это переменная $tx. |
| true | Удалось отменить выбранную часть работы. Явный контекст завершён; после этого его не используют. |
| false | Отказ; сохранить диагностику немедленно и не сообщать пользователю об успешном сохранении/отмене. |
Страница PHP Manual относит имя к PHP5 и встроенному расширению PHP7 до 7.4. После удаления расширения из комплекта PHP оно устанавливается отдельно; наличие имени нужно проверять в используемой сборке. Здесь целевой профиль PHP8.2.35 / interbase3.0.1 / Firebird5.0.4. В исходнике этой версии PHP_FALIAS связывает два имени с одним обработчиком. Это не ускорение, не миграция на PDO и не изменение версии SQL-сервера.
Управляющих флагов нет. В краткой сигнатуре canonical-страницы необязательный ресурс показан со значением null. Парсер interbase3.0.1 ожидает переданный аргумент типа resource: для выбора по умолчанию опустите аргумент, а не подставляйте явный null. Неподходящий или уже освобождённый ресурс может дать предупреждение либо PHP-ошибку; это не новый пустой контекст.
Применение 1: отменить отдельную пробную запись
// Пробная запись 100 выполнена через $tx; сохранять её не решили.
if (fbird_rollback($tx) !== true) {
throw new RuntimeException("Пробная запись не отменена");
}
$tx = null;Полная последовательность после этого читает ранее подтверждённые8. Rollback не возвращает базу ко времени до предыдущего commit.
Применение 2: отказаться от создания заявки
// INSERT черновой заявки выполнен через $tx.
if (fbird_rollback($tx) !== true) { throw new RuntimeException("Черновик не отменён"); }
$tx = null;
// Выданный ранее fbird_gen_id номер не уменьшайте.Пример с последовательностью показывает отсутствие строки1 и сохранённый следующий ID2. Откат данных не возвращает выданные номера и не отменяет внешнюю отправку письма/HTTP-запроса.
После успешного завершения обнулите переменную явной транзакции; она больше не подходит для следующего запроса. Функция действует только на выбранную транзакцию, не на все соединения и не на историю ранее подтверждённых операций. Если действие вернуло false, его причина сохраняется до cleanup. Полная модель и условия выбора есть в ibase_rollback.
fbird_commit_retПодтвердить текущую часть работы, сохранив контекст для продолжения.
PHP5 / PHP7 <7.4; далее отдельное расширение. Целевой профиль interbase3.0.1 / PHP8.2. · interbase
fbird_commit_ret(resource $link_or_trans_identifier = ?): boolСогласованную часть операции нужно сохранить. Эта функция сохраняет транзакционный контекст для продолжения. fbird_commit_ret — зарегистрированное расширением альтернативное имя ibase_commit_ret. Ресурсы, правила аргументов и результат у этой пары общие; смена префикса не создаёт другой способ работы с базой.
fbird_commit_ret(): bool
fbird_commit_ret(resource $connectionOrTransaction): bool| Параметр или результат | Что означает |
|---|---|
| Без аргумента | Default-транзакция последнего/default-соединения, а не все транзакции процесса. |
| $connectionOrTransaction = соединение | Выбирается default-транзакция этого соединения. |
| $connectionOrTransaction = транзакция | Выбирается переданная явная транзакция. В рабочих сценариях это переменная $tx. |
| true | Удалось подтвердить выбранную часть работы. Контекст сохранён. |
| false | Отказ; сохранить диагностику немедленно и не сообщать пользователю об успешном сохранении/отмене. |
Страница PHP Manual относит имя к PHP5 и встроенному расширению PHP7 до 7.4. После удаления расширения из комплекта PHP оно устанавливается отдельно; наличие имени нужно проверять в используемой сборке. Здесь целевой профиль PHP8.2.35 / interbase3.0.1 / Firebird5.0.4. В исходнике этой версии PHP_FALIAS связывает два имени с одним обработчиком. Это не ускорение, не миграция на PDO и не изменение версии SQL-сервера.
Управляющих флагов нет. В краткой сигнатуре canonical-страницы необязательный ресурс показан со значением null. Парсер interbase3.0.1 ожидает переданный аргумент типа resource: для выбора по умолчанию опустите аргумент, а не подставляйте явный null. Неподходящий или уже освобождённый ресурс может дать предупреждение либо PHP-ошибку; это не новый пустой контекст.
Применение 1: принять проверенную партию
if (fbird_commit_ret($tx) !== true) {
throw new RuntimeException("Партия не принята");
}
// $tx остаётся активным для следующей короткой части работы.Проверяемый сценарий принимает7, затем отменяет ошибочные99 через rollback_ret. Подтверждённые7 при этом сохраняются.
Применение 2: продолжить существующую подготовленную операцию
// $update подготовлен в $tx; предыдущая партия проверена.
if (fbird_commit_ret($tx) !== true) { throw new RuntimeException("Партия не сохранена"); }
if (fbird_execute($update, $verifiedQuantity, $productId) === false) {
$failure = [fbird_errcode(), fbird_errmsg()];
// Решить об откате текущей части, сохранив причину.
}
// Освободить подготовку и окончательно завершить $tx.Фрагмент объясняет обслуживание существующего кода с подготовленной командой: retaining не инвалидирует её контекст. Это не дополнительный измеренный MAIN и не обещание ускорения. Обычный commit нужен в конце всей задачи.
Retaining не равен новой независимой транзакции: сохраняются контекст, связанные statements и особенности видимости снимка. Не используйте его как вечный цикл веб-сессии. В конце обязательно обычный commit/rollback. Функция действует только на выбранную транзакцию, не на все соединения и не на историю ранее подтверждённых операций. Если действие вернуло false, его причина сохраняется до cleanup. Полная модель и условия выбора есть в ibase_commit_ret.
fbird_rollback_retОтменить текущую часть работы без закрытия её контекста.
PHP5 / PHP7 <7.4; далее отдельное расширение. Целевой профиль interbase3.0.1 / PHP8.2. · interbase
fbird_rollback_ret(resource $link_or_trans_identifier = ?): boolОшибочный или отменённый пользователем черновик не должен остаться в базе. Эта функция сохраняет транзакционный контекст для продолжения. fbird_rollback_ret — зарегистрированное расширением альтернативное имя ibase_rollback_ret. Ресурсы, правила аргументов и результат у этой пары общие; смена префикса не создаёт другой способ работы с базой.
fbird_rollback_ret(): bool
fbird_rollback_ret(resource $connectionOrTransaction): bool| Параметр или результат | Что означает |
|---|---|
| Без аргумента | Default-транзакция последнего/default-соединения, а не все транзакции процесса. |
| $connectionOrTransaction = соединение | Выбирается default-транзакция этого соединения. |
| $connectionOrTransaction = транзакция | Выбирается переданная явная транзакция. В рабочих сценариях это переменная $tx. |
| true | Удалось отменить выбранную часть работы. Контекст сохранён. |
| false | Отказ; сохранить диагностику немедленно и не сообщать пользователю об успешном сохранении/отмене. |
Страница PHP Manual относит имя к PHP5 и встроенному расширению PHP7 до 7.4. После удаления расширения из комплекта PHP оно устанавливается отдельно; наличие имени нужно проверять в используемой сборке. Здесь целевой профиль PHP8.2.35 / interbase3.0.1 / Firebird5.0.4. В исходнике этой версии PHP_FALIAS связывает два имени с одним обработчиком. Это не ускорение, не миграция на PDO и не изменение версии SQL-сервера.
Управляющих флагов нет. В краткой сигнатуре canonical-страницы необязательный ресурс показан со значением null. Парсер interbase3.0.1 ожидает переданный аргумент типа resource: для выбора по умолчанию опустите аргумент, а не подставляйте явный null. Неподходящий или уже освобождённый ресурс может дать предупреждение либо PHP-ошибку; это не новый пустой контекст.
Применение 1: отбросить ошибку после принятой партии
if (fbird_rollback_ret($tx) !== true) {
throw new RuntimeException("Черновая партия не отменена");
}
// Тот же контекст можно использовать для исправленной партии.В полном сценарии отменённые99 заменяются подтверждёнными ранее7, затем исправленные8 сохраняются обычным commit. Это не rollback всего прошлого импорта.
Применение 2: повторно использовать подготовку с исправленными данными
// Решение об отмене текущего черновика уже принято приложением.
if (fbird_rollback_ret($tx) !== true) { throw new RuntimeException("Черновик не отменён"); }
if (fbird_execute($preparedUpdate, $correctedQuantity, $id) === false) {
throw new RuntimeException("Исправление не выполнено");
}
// Затем проверить строки, освободить подготовку и сделать обычный commit/rollback.Речь о конечной операции с уже проверенным исправлением, а не об автоматическом бесконечном повторе любой ошибки. Retaining сохраняет контекст statements; готовые значения в PHP и текущая серверная позиция курсора — разные вещи.
Retaining не равен новой независимой транзакции: сохраняются контекст, связанные statements и особенности видимости снимка. Не используйте его как вечный цикл веб-сессии. В конце обязательно обычный commit/rollback. Функция действует только на выбранную транзакцию, не на все соединения и не на историю ранее подтверждённых операций. Если действие вернуло false, его причина сохраняется до cleanup. Полная модель и условия выбора есть в ibase_rollback_ret.
fbird_affected_rowsПроверить число строк предыдущего INSERT, UPDATE или DELETE.
PHP5 / PHP7 <7.4; далее отдельное расширение. Целевой профиль interbase3.0.1 / PHP8.2. · interbase
fbird_affected_rows(resource $link_identifier = ?): int|falseУсловный UPDATE корректно исполнился, но товар мог не пройти проверку остатка или версии. Счётчик показывает, состоялось ли изменение нужного числа строк. fbird_affected_rows — зарегистрированное расширением альтернативное имя ibase_affected_rows. Ресурсы, правила аргументов и результат у этой пары общие; смена префикса не создаёт другой способ работы с базой.
fbird_affected_rows(): int|false
fbird_affected_rows(resource $connectionOrTransaction): int|false| Параметр или результат | Что означает |
|---|---|
| $connectionOrTransaction | Явная транзакция либо соединение с его default-транзакцией. Не результат SELECT. |
| Аргумент опущен | Стандартный контекст последнего соединения. При нескольких контекстах передавайте ресурс явно. |
| int, включая 0 | Количество строк предыдущего INSERT/UPDATE/DELETE в этом контексте. Ноль допустим и не равен отказу SQL. |
| false | В 3.0.1 возможен при отсутствии нужного транзакционного контекста; не приводите его к0. |
Страница PHP Manual относит имя к PHP5 и встроенному расширению PHP7 до 7.4. После удаления расширения из комплекта PHP оно устанавливается отдельно; наличие имени нужно проверять в используемой сборке. Здесь целевой профиль PHP8.2.35 / interbase3.0.1 / Firebird5.0.4. В исходнике этой версии PHP_FALIAS связывает два имени с одним обработчиком. Это не ускорение, не миграция на PDO и не изменение версии SQL-сервера.
Canonical-страница кратко указывает int; false дополнен из реального исходника этой версии. Специальных флагов нет. Читайте счётчик сразу после успешной записи, до других SQL-команд и завершения транзакции. При false самого query сначала снимайте ошибку. Это не число строк SELECT, не размер таблицы, не признак commit и не обещание подсчёта всех побочных изменений триггеров.
Применение 1: атомарно зарезервировать остаток
$ok = fbird_query($db, "UPDATE STOCK SET QTY=QTY-? WHERE ID=? AND QTY>=?", 2, 1, 2);
if ($ok === false) { throw new RuntimeException("Запрос резерва не выполнен"); }
$changed = fbird_affected_rows($db);
// 1: резерв выполнен; 0: условие не совпало. Commit проверяется отдельно.Полная программа показывает1 после запроса двух единиц и0 после запроса четырёх при остатке1. Бизнес-условие проверяет база; не требуется сортировать весь каталог в PHP.
Применение 2: не перезаписать чужое изменение формы
$ok = fbird_query($tx, "UPDATE PRODUCTS SET TITLE=?, VERSION=VERSION+1 WHERE ID=? AND VERSION=?", $title, $id, $seenVersion);
if ($ok === false) { throw new RuntimeException("Сохранение не выполнено"); }
$changed = fbird_affected_rows($tx);
// При 0: сообщить о несовпадении условия, не выдавать ложное «сохранено».Фрагмент предполагает поле VERSION и выбранную модель конкурентного редактирования. Это не отдельный нагрузочный тест. Ноль также возможен при отсутствии ID; приложение решает, нужно ли уточняющее чтение. Сверка курсором использует строгую проверку1 после каждого изменения текущей строки.
fbird_errcodeСнять числовой код последнего отказа до следующего вызова.
PHP5 / PHP7 <7.4; далее отдельное расширение. Целевой профиль interbase3.0.1 / PHP8.2. · interbase
fbird_errcode(): int|falseПосле неудачного запроса нужно сохранить причину до следующего обращения к драйверу. Числовой SQLCODE помогает различить отказы. fbird_errcode — зарегистрированное расширением альтернативное имя ibase_errcode. Ресурсы, правила аргументов и результат у этой пары общие; смена префикса не создаёт другой способ работы с базой.
fbird_errcode(): int|false| Параметр или результат | Что означает |
|---|---|
| Параметры | Нет. Соединение, ресурс транзакции или код ошибки сюда не передаются. |
| int | Сохранённая диагностика последнего отказа расширения: в нашем неизвестном поле -206. |
| false | Сохранённой ошибки нет. Строго отличайте false от числового0 или пустой строки. |
| Область состояния | Текущее состояние расширения в PHP-запросе, а не отдельная история каждого соединения. |
Страница PHP Manual относит имя к PHP5 и встроенному расширению PHP7 до 7.4. После удаления расширения из комплекта PHP оно устанавливается отдельно; наличие имени нужно проверять в используемой сборке. Здесь целевой профиль PHP8.2.35 / interbase3.0.1 / Firebird5.0.4. В исходнике этой версии PHP_FALIAS связывает два имени с одним обработчиком. Это не ускорение, не миграция на PDO и не изменение версии SQL-сервера.
Чтение errcode/errmsg само сохраняет снимок; многие другие функции очищают или заменяют его. Наличие warning также важно: PHP-ошибка параметров не обязана иметь SQL-код. SQLCODE не является SQLSTATE или системным errno. Локальные ошибки модуля могут иметь -999; одно число не описывает все детали причины.
Применение 1: сохранить опечатку запроса
$result = fbird_query($db, "SELECT NOT_A_FIELD FROM PRODUCTS");
if ($result === false) {
$savedCode = fbird_errcode();
$savedMessage = fbird_errmsg();
$hasMessage = is_string($savedMessage) && $savedMessage !== "";
// Сначала сохранить безопасную диагностику; затем rollback/cleanup.
}Полный пример сохраняет -206 и признак упоминания поля. После исправленного SELECT текущее состояние уже false, но сохранённая переменная остаётся. Это снимок причины, а не автоматическое исправление SQL.
Применение 2: отличить EOF от сбоя получения строки
$row = fbird_fetch_assoc($result);
if ($row === false) {
$fetchCode = fbird_errcode();
$fetchMessage = fbird_errmsg();
if ($fetchCode !== false || $fetchMessage !== false) {
throw new RuntimeException("Не удалось прочитать результат");
}
// При отсутствии предупреждений это обычный конец выдачи.
}Это середина цикла уже открытого SELECT. Полные программы дополнительно перехватывают warning, чтобы ошибка PHP не превратилась в безусловный конец списка. Курсорный пример заканчивает обход только при чистом EOF. Соседняя карточка fbird_errmsg объясняет вторую часть снимка.
fbird_errmsgСохранить текст причины и безопасно отделить его от публичного ответа.
PHP5 / PHP7 <7.4; далее отдельное расширение. Целевой профиль interbase3.0.1 / PHP8.2. · interbase
fbird_errmsg(): string|falseПосле неудачного запроса нужно сохранить причину до следующего обращения к драйверу. Текст помогает разработчику найти конкретное имя поля или нарушенное ограничение. fbird_errmsg — зарегистрированное расширением альтернативное имя ibase_errmsg. Ресурсы, правила аргументов и результат у этой пары общие; смена префикса не создаёт другой способ работы с базой.
fbird_errmsg(): string|false| Параметр или результат | Что означает |
|---|---|
| Параметры | Нет. Соединение, ресурс транзакции или код ошибки сюда не передаются. |
| string | Сохранённая диагностика последнего отказа расширения: текст зависит от причины, сервера и драйвера. |
| false | Сохранённой ошибки нет. Строго отличайте false от числового0 или пустой строки. |
| Область состояния | Текущее состояние расширения в PHP-запросе, а не отдельная история каждого соединения. |
Страница PHP Manual относит имя к PHP5 и встроенному расширению PHP7 до 7.4. После удаления расширения из комплекта PHP оно устанавливается отдельно; наличие имени нужно проверять в используемой сборке. Здесь целевой профиль PHP8.2.35 / interbase3.0.1 / Firebird5.0.4. В исходнике этой версии PHP_FALIAS связывает два имени с одним обработчиком. Это не ускорение, не миграция на PDO и не изменение версии SQL-сервера.
Чтение errcode/errmsg само сохраняет снимок; многие другие функции очищают или заменяют его. Наличие warning также важно: PHP-ошибка параметров не обязана иметь SQL-код. Сырая строка может содержать путь к базе, SQL и внутренние данные. HTML-экранирование не скрывает эти сведения; не показывайте её посетителю и не сравнивайте целиком как стабильный машинный протокол.
Применение 1: сохранить опечатку запроса
$result = fbird_query($db, "SELECT NOT_A_FIELD FROM PRODUCTS");
if ($result === false) {
$savedCode = fbird_errcode();
$savedMessage = fbird_errmsg();
$hasMessage = is_string($savedMessage) && $savedMessage !== "";
// Сначала сохранить безопасную диагностику; затем rollback/cleanup.
}Полный пример сохраняет -206 и признак упоминания поля. После исправленного SELECT текущее состояние уже false, но сохранённая переменная остаётся. Это снимок причины, а не автоматическое исправление SQL.
Применение 2: отличить EOF от сбоя получения строки
$row = fbird_fetch_assoc($result);
if ($row === false) {
$fetchCode = fbird_errcode();
$fetchMessage = fbird_errmsg();
if ($fetchCode !== false || $fetchMessage !== false) {
throw new RuntimeException("Не удалось прочитать результат");
}
// При отсутствии предупреждений это обычный конец выдачи.
}Это середина цикла уже открытого SELECT. Полные программы дополнительно перехватывают warning, чтобы ошибка PHP не превратилась в безусловный конец списка. Курсорный пример заканчивает обход только при чистом EOF. Соседняя карточка fbird_errcode объясняет вторую часть снимка.
fbird_closeЗавершить использование обычного подключения после явного окончания работы.
PHP5 / PHP7 <7.4; далее отдельное расширение. Целевой профиль interbase3.0.1 / PHP8.2. · interbase
fbird_close(resource $connection_id = ?): boolЗадача закончила работу с обычным подключением. Сначала явно решают судьбу транзакций и освобождают результаты, затем закрывают соединение. fbird_close — зарегистрированное расширением альтернативное имя ibase_close. Ресурсы, правила аргументов и результат у этой пары общие; смена префикса не создаёт другой способ работы с базой.
fbird_close(): bool
fbird_close(resource $connection): bool| Параметр или результат | Что означает |
|---|---|
| $connection | Обычный link от fbird_connect/ibase_connect; не транзакция и не результат SELECT. |
| Аргумент опущен | Последнее открытое соединение. С несколькими базами указывайте ресурс явно. |
| true / false | Успешное закрытие либо отказ. Неверный/освобождённый ресурс может вызвать PHP-ошибку. |
| Default-транзакция | Базовый контракт close подтверждает её; другие незавершённые транзакции откатываются. Полные примеры не полагаются на этот побочный выбор. |
| Persistent-подключение | Срок жизни persistent-ресурса отличается; этим вызовом не обещается закрыть пул/физическое соединение pconnect. |
Страница PHP Manual относит имя к PHP5 и встроенному расширению PHP7 до 7.4. После удаления расширения из комплекта PHP оно устанавливается отдельно; наличие имени нужно проверять в используемой сборке. Здесь целевой профиль PHP8.2.35 / interbase3.0.1 / Firebird5.0.4. В исходнике этой версии PHP_FALIAS связывает два имени с одним обработчиком. Это не ускорение, не миграция на PDO и не изменение версии SQL-сервера.
Флагов нет. Для необязательного аргумента в3.0.1 пропустите его, а не передавайте null. Закрытие link не является удалением FDB: для последнего существует отдельный административный API. Результаты и подготовки могут удерживать ссылки, поэтому free_result/free_query и null/unset важны. Не решайте по одному is_resource, что уже освобождённый внутренний объект всё ещё пригоден.
Применение 1: явно сохранить и закончить задачу
if (fbird_commit($db) !== true) { throw new RuntimeException("Изменения не подтверждены"); }
if (fbird_close($db) !== true) { throw new RuntimeException("Соединение не закрыто"); }
$db = null;Полный проект открывает соединение снова и получает Cable8. Успешный close отдельно от commit делает границу сохранения понятной; чтение после открытия подтверждает предметные данные.
Применение 2: отменить черновик перед закрытием
if (fbird_rollback($tx) !== true) { throw new RuntimeException("Черновик не отменён"); }
$tx = null;
// Подготовки и результаты были освобождены раньше.
if (fbird_close($db) !== true) { throw new RuntimeException("Соединение не закрыто"); }
$db = null;Это окончание отменённой задачи, подобной черновой заявке. Close не заменяет осмысленный rollback, а ранее сохранённые PHP-массивы после закрытия остаются обычными данными. Действующие ссылки на link могут влиять на его срок жизни; для доказательства независимой аутентификации при смене пароля смотрите отдельные проверки входа.
fbird_gen_idВыдать или прочитать значение существующей последовательности.
PHP5 / PHP7 <7.4; далее отдельное расширение. Целевой профиль interbase3.0.1 / PHP8.2. · interbase
fbird_gen_id(string $generator, int $increment = 1, resource $link_identifier = ?): int|string|falseПриложению нужен новый технический ключ до INSERT, например для заявки и её связанных записей. Последовательность выдаёт число, а вставка и подтверждение выполняются отдельно. fbird_gen_id — зарегистрированное расширением альтернативное имя ibase_gen_id. Ресурсы, правила аргументов и результат у этой пары общие; смена префикса не создаёт другой способ работы с базой.
fbird_gen_id(string $generator, int $increment = 1): int|string|false
fbird_gen_id(string $generator, int $increment, resource $connection): int|string|false| Параметр или результат | Что означает |
|---|---|
| $generator | Имя существующей последовательности. В3.0.1 ограничено31байтом и попадает в SQL; берите фиксированное/проверенное имя приложения. |
| $increment = 1 | Шаг изменения:1 выдаёт новое число,0 читает текущее. Отрицательный шаг уменьшает значение и не является безопасным откатом выданного ID. |
| $connection | Соединение нужной базы; при отсутствии используется последнее/default. |
| int / string | Новое значение счётчика. Если целое не помещается в PHP int платформы, возвращается строка. |
| false | Ошибка имени, отсутствующей последовательности или выполнения; сохранить диагностику. Неверные PHP-типы рассматриваются отдельно. |
Страница PHP Manual относит имя к PHP5 и встроенному расширению PHP7 до 7.4. После удаления расширения из комплекта PHP оно устанавливается отдельно; наличие имени нужно проверять в используемой сборке. Здесь целевой профиль PHP8.2.35 / interbase3.0.1 / Firebird5.0.4. В исходнике этой версии PHP_FALIAS связывает два имени с одним обработчиком. Это не ускорение, не миграция на PDO и не изменение версии SQL-сервера.
Официальная canonical-страница отмечена как неполная и содержит список аргументов и краткий возврат; дополнительные правила взяты из закреплённого исходника и руководства генераторов. Для выбора default-соединения третий аргумент опускают: явный null в3.0.1 не заменяет resource. Функция не создаёт sequence и не делает INSERT. Она использует явный шаг GEN_ID, что не следует безусловно приравнивать к NEXT VALUE FOR с настроенным шагом последовательности.
Применение 1: ID до создания заявки
$id = fbird_gen_id("APPLICATION_ID_SEQ", 1, $db);
if ($id === false) { throw new RuntimeException("ID не выдан"); }
$ok = fbird_query($db, "INSERT INTO APPLICATIONS (ID,TITLE) VALUES (?,?)", $id, $title);
if ($ok === false) { throw new RuntimeException("Заявка не записана"); }
if (fbird_commit($db) !== true) { throw new RuntimeException("Заявка не подтверждена"); }Фрагмент предполагает существующие таблицу и sequence. Самостоятельный проект создаёт собственные объекты: отменённый ID1 не используется повторно, сохранённая заявка имеет ID2.
Применение 2: посмотреть счётчик без выдачи номера
$current = fbird_gen_id("APPLICATION_ID_SEQ", 0, $db);
if ($current === false) { throw new RuntimeException("Счётчик недоступен"); }
echo "Текущее значение: ", $current;После нашего примера значение равно2 при одной сохранённой строке. Шаг0 не резервирует будущий ID и не обходит SQL-права. Другой процесс может увеличить счётчик сразу после чтения; для выдачи нужен настоящий шаг1, не $current+1 в PHP.
Последовательности находятся вне rollback пользовательской транзакции. Не уменьшайте значение после ошибки и не ищите ID через MAX+1. PRIMARY KEY по-прежнему нужен; уникальный ключ бизнес-операции защищает от повторного HTTP-запроса отдельно. Технические ID с пропусками и непрерывные номера документов — разные задачи. Не превращайте строковое большое число во float. Альтернативы новой схеме: identity-столбцы и INSERT RETURNING; они не делают простую замену имени fbird_gen_id миграцией на другой API.
fbird_name_resultНазвать открытый курсор для изменения его текущей строки.
PHP5 / PHP7 <7.4; далее отдельное расширение. Целевой профиль interbase3.0.1 / PHP8.2. · interbase
fbird_name_result(resource $result, string $name): boolСтарый код обходит изменяемый результат и должен менять именно только что прочитанную строку. Имя курсора связывает SELECT с WHERE CURRENT OF в UPDATE или DELETE. fbird_name_result — зарегистрированное расширением альтернативное имя ibase_name_result. Ресурсы, правила аргументов и результат у этой пары общие; смена префикса не создаёт другой способ работы с базой.
fbird_name_result(resource $result, string $name): bool| Параметр или результат | Что означает |
|---|---|
| $result | Действующий результат изменяемого SELECT, не соединение и не подготовленный UPDATE. |
| $name | Фиксированное SQL-имя курсора, которое затем используется в WHERE CURRENT OF. Не значение для placeholder ?. |
| true / false | Имя назначено либо получен отказ. Сразу сохраните диагностику при false. |
| Позиция | После первого успешного fetch и до следующего перемещения/освобождения результата. Имя само не выбирает строку. |
Страница PHP Manual относит имя к PHP5 и встроенному расширению PHP7 до 7.4. После удаления расширения из комплекта PHP оно устанавливается отдельно; наличие имени нужно проверять в используемой сборке. Здесь целевой профиль PHP8.2.35 / interbase3.0.1 / Firebird5.0.4. В исходнике этой версии PHP_FALIAS связывает два имени с одним обработчиком. Это не ускорение, не миграция на PDO и не изменение версии SQL-сервера.
Дополнительных флагов нет. SELECT и связанный UPDATE/DELETE должны использовать один подходящий транзакционный контекст. После EOF, освобождения результата или обычного завершения транзакции старую позицию использовать нельзя. Ошибочные PHP-типы/ресурсы дают отдельную ошибку. Отчёт с агрегатом или JOIN не становится изменяемым от назначения имени.
Применение 1: записать подтверждённый остаток
if (fbird_name_result($result, "STOCK_CURSOR") !== true) { throw new RuntimeException("Нет имени курсора"); }
$update = fbird_prepare($tx, "UPDATE PRODUCTS SET QTY=? WHERE CURRENT OF STOCK_CURSOR");
if ($update === false) { throw new RuntimeException("UPDATE не подготовлен"); }
$row = fbird_fetch_row($result);
if ($row !== false && fbird_execute($update, 10) === false) {
throw new RuntimeException("Текущий товар не изменён");
}Контекстный фрагмент начинается с уже открытого SELECT в $tx. Полная сверка проверяет каждое affected_rows, освобождает оба ресурса до commit и отдельно читает Cable10 / Clamp14 / Archive9.
Применение 2: удалить текущую проверенную запись очереди
if (fbird_name_result($expiredRows, "EXPIRED_CURSOR") !== true) { throw new RuntimeException("Курсор не назван"); }
$delete = fbird_prepare($tx, "DELETE FROM JOBS WHERE CURRENT OF EXPIRED_CURSOR");
if ($delete === false) { throw new RuntimeException("DELETE не подготовлен"); }
$row = fbird_fetch_row($expiredRows);
if ($row !== false && fbird_execute($delete) === false) {
throw new RuntimeException("Задание не удалено");
}Здесь предполагается авторизованная выборка действительно просроченных заданий и готовая таблица JOBS. Это объяснение второго применения, не дополнительный выполненный MAIN. После операций проверяют строки, освобождают подготовку/результат и окончательно завершают транзакцию.
Не накапливайте результат в PHP, чтобы позже обращаться к закрытому курсору. Если известен ID, параметризованный UPDATE/DELETE WHERE ID=? обычно проще; версия записи добавляет контроль конкурирующего изменения. Для массового общего правила рассматривайте один SQL-запрос. FOR UPDATE обозначает изменяемую выборку, но не обещает универсальную блокировку всего набора или отсутствие конфликтов. Храните имя курсора в коде, не принимайте его из запроса посетителя.
Источники и обсуждения
- PHP Manual: fbird_trans
- PHP Manual: fbird_commit
- PHP Manual: fbird_rollback
- PHP Manual: fbird_commit_ret
- PHP Manual: fbird_rollback_ret
- PHP Manual: fbird_affected_rows
- PHP Manual: fbird_errcode
- PHP Manual: fbird_errmsg
- PHP Manual: fbird_close
- PHP Manual: fbird_gen_id
- PHP Manual: fbird_name_result
- PHP Manual: ibase_trans
- PHP Manual: ibase_commit
- PHP Manual: ibase_rollback
- PHP Manual: ibase_commit_ret
- PHP Manual: ibase_rollback_ret
- PHP Manual: ibase_affected_rows
- PHP Manual: ibase_errcode
- PHP Manual: ibase_errmsg
- PHP Manual: ibase_close
- PHP Manual: ibase_gen_id
- PHP Manual: ibase_name_result
- FirebirdSQL: регистрация aliases и реализация транзакций 3.0.1
- FirebirdSQL: результаты запросов и курсоры 3.0.1
- Firebird: последовательности и rollback
- Firebird5: транзакции
- Firebird5: UPDATE и WHERE CURRENT OF
Код и руководство с собой
Скачайте самостоятельные примеры с исходными данными, инструкциями и ожидаемыми результатами. Примеры HTTP и фрагменты для проекта помечены отдельно: им нужно указанное окружение.
Код не исполняется на сайте. Скачайте нужный пример и запускайте его в своём локальном окружении.
Материалы сверены 2026-10-12. Примеры и объяснения написаны для этого руководства; источники и обсуждения доступны в каждой главе.


