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

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

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

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

Глава 71 · После SQL, транзакций и Service Manager Firebird

Firebird: sweep, диагностика проверки и обратное чтение настроек базы

Служебные действия с реальным обратным чтением: sweep, ожидаемые отказы validate, изменение и восстановление интервала и числа страниц кэша.

Выбирать результат обслуживания, который можно проверить

Каталог должен продолжать показывать настоящие остатки, а административная команда — давать проверяемый результат. В этой главе Cable остаётся равен 7 после sweep, порог обслуживания меняется с 20000 на 12345 и обратно, а сохранённое число страниц кэша — с 0 на 256 и обратно. Отдельно разберём честный результат «проверка структуры не выполнена в этом окружении».

Сначала разделим две роли. SQL-соединение позволяет читать и менять строки таблицы. Сервисное соединение обращается к Service Manager и выполняет административные действия над указанной базой. У них разные ресурсы и полномочия. Переменная $service хранит второй ресурс; $database — строку с разрешённым серверу именем FDB. Знакомство с этими ролями есть в главе Service Manager, а первое SELECT и commit — в основах запросов и транзакциях.

Что значит «настройка сработала»
  1. Сохранить текущее значение и проверить, что база наша
  2. Закончить свои SQL-операции и закрыть соединения
  3. Передать service + database + одно action + его argument
  4. Прочитать завершение службы или конкретный отказ
  5. Новый SQL/header подтверждает данные и свойство
  6. Временно изменённый режим вернуть; учебную базу удалить

Аналогия — отдельная панель обслуживания помещения: выключатель разрешения записи относится ко всему помещению, а не только к одному столу. Но Firebird не является папкой с обычными файлами, в которой достаточно поменять галочку Windows: режим базы, права пользователя и режим транзакции различаются. Обслуживание работает по правилам сервера; приложение не должно заменять их догадками по одному bool.

ЗадачаЧто получить
Ручной sweepПосле служебной операции прочитать именно Cable 7 / Clamp 0.
Диагностика validateОтделить неизвестный action -999 от отказа профиля -924; не обещать проверенную целостность.
Настройка sweep intervalВ заголовке увидеть 20000 → 12345 → 20000.
Число страниц кэшаВ заголовке увидеть 0 → 256 → 0; прочитать неизменный каталог.

Каждый полный проект создаёт одну отдельную синтетическую FDB из небольшого каталога. Перед обслуживанием проверяются имя, фактический путь и случайный маркер владельца PHPMAN159_OWNER. Проекты не адресуют production, security database или чужие FDB. Это ограничение конкретной учебной программы; оно не заменяет права и процедуры администратора на настоящем сервере. Примеры CLI проверяются на PHP 8.2.35 / interbase 3.0.1 / Firebird 5.0.4 embedded SuperClassic.

Выполнить ручной sweep и сохранить подтверждённые остатки

После нескольких изменений склада важно отличить текущий остаток от старых версий записей. У Cable сначала 3, затем подтверждены 4 и 7. Значение 99 намеренно отменено. Ручной sweep обслуживает внутреннее состояние базы, а посетитель по-прежнему должен видеть Cable — 7 и Clamp — 0.

Путь к результату
  1. Cable = 3 → UPDATE 4 + commit → UPDATE 7 + commit
  2. UPDATE 99 виден своей транзакции, затем rollback оставляет 7
  3. Закрыть свои SQL-подключения, вызвать SWEEP_DB
  4. Считать завершение службы, открыть новое соединение
  5. SELECT нужных полей возвращает Cable 7 и Clamp 0

Минимальный вызов и его части

$started = ibase_maintain_db($service, $database, IBASE_RPR_SWEEP_DB);
if ($started !== true) {
    throw new RuntimeException('Sweep не запущен');
}
// Далее прочитать ответ службы; только затем проверять результат.

Третий аргумент выбирает ручной sweep. Отсутствующий четвёртый аргумент равен 0: дополнительных флагов здесь нет. $service получен через ibase_service_attach, а $database — разрешённое серверу имя FDB. В отличие от UPDATE эта команда не задаёт значение QTY. В полном проекте f159Maintain сначала проверяет владение базой, затем вызывает функцию и дочитывает служебный ответ.

Конкретный результат самостоятельного запуска

НаблюдениеРезультат
Первоначальный остаток Cable3
Пробное значение до rollback99
Перед sweep: Cable / Clamp7 / 0
Сервисная команда принятада
Ответ службы прочитанда
После sweep: Cable / Clamp7 / 0
Подтверждённые товары сохранилисьда
Полная программа, вспомогательные файлы и архив
Выполнить ручной sweep и сохранить подтверждённые остаткиСамостоятельный пример
<?php
declare(strict_types=1);
require __DIR__.'/lab.php';
$owned=[];$removed=[];$db=$service=null;
try {
    $config=f159Config();$service=f159Service();$runtime=f159Runtime($service);

    $name=f159CreateDatabase($service,$owned,'sweep');
    $db=f159Connect($name);
    $initial=f159Read($db,'SELECT ID,TITLE,QTY FROM LAB_ITEMS ORDER BY ID');
    f159Command($db,'UPDATE LAB_ITEMS SET QTY=4 WHERE ID=1');
    f159Commit($db);
    f159Command($db,'UPDATE LAB_ITEMS SET QTY=7 WHERE ID=1');
    f159Commit($db);
    f159Command($db,'UPDATE LAB_ITEMS SET QTY=99 WHERE ID=1');
    $uncommitted=f159Read($db,'SELECT QTY FROM LAB_ITEMS WHERE ID=1')[0]['QTY'];
    if(ibase_rollback($db)!==true)f159Failure('Отмена пробной записи не подтверждена');
    $before=f159Read($db,'SELECT ID,TITLE,QTY FROM LAB_ITEMS ORDER BY ID');
    f159Close($db);
    $job=f159Maintain($service,$name,IBASE_RPR_SWEEP_DB);
    $db=f159Connect($name);
    $after=f159Read($db,'SELECT ID,TITLE,QTY FROM LAB_ITEMS ORDER BY ID');
    f159Close($db);
    $expected=[['ID'=>1,'TITLE'=>'Cable','QTY'=>7],['ID'=>2,'TITLE'=>'Clamp','QTY'=>0]];
    $rows=[['Первоначальный остаток Cable',$initial[0]['QTY']],
        ['Пробное значение до rollback',$uncommitted],
        ['Перед sweep: Cable / Clamp',$before[0]['QTY'].' / '.$before[1]['QTY']],
        ['Сервисная команда принята',$job['started']],
        ['Ответ службы прочитан',$job['output']===true || is_string($job['output'])],
        ['После sweep: Cable / Clamp',$after[0]['QTY'].' / '.$after[1]['QTY']],
        ['Подтверждённые товары сохранились',$after===$expected]];
    $checks=['initial_stock'=>$initial===[['ID'=>1,'TITLE'=>'Cable','QTY'=>3],['ID'=>2,'TITLE'=>'Clamp','QTY'=>0]],
        'rollback_discarded_99'=>$uncommitted===99 && $before===$expected,
        'service_started'=>$job['started']===true,
        'service_completed'=>$job['output']===true || is_string($job['output']),
        'committed_rows_unchanged'=>$after===$before && $after===$expected];
    $observations=['initial'=>$initial,'uncommitted_stock'=>$uncommitted,'before'=>$before,'after'=>$after,
        'service_started'=>$job['started'],'completion_kind'=>get_debug_type($job['output']),
        'completion_has_text'=>is_string($job['output']) && $job['output']!==''];

} finally {
    if(is_resource($db)){f159Close($db);}
    if(is_resource($service)){f159Detach($service);}
    $removed=f159Cleanup($owned);
}

f159Report('fb159-manual-sweep','Выполнить ручной sweep и сохранить подтверждённые остатки',$rows,$checks,$observations,$runtime,$owned,$removed);
Ожидаемый результат
Первоначальный остаток Cable — 3
Пробное значение до rollback — 99
Перед sweep: Cable / Clamp — 7 / 0
Сервисная команда принята — да
Ответ службы прочитан — да
После sweep: Cable / Clamp — 7 / 0
Подтверждённые товары сохранились — да

Распакуйте архив целиком в собственную папку и выполните example.php по README.txt. lab.php содержит проверку владельца, создание синтетической базы, SQL-помощники, чтение Service API и уборку. seed.sql показывает исходные Cable/3 и Clamp/0. result.html отображает предметный результат, result.json сохраняет наблюдения, metrics.json — проверки. После работы собственная база и промежуточный backup удаляются; отчёты остаются.

Открыть таблицу фактического результата · Открыть данные JSON.

Ошибки, ограничения и выбор другого инструмента

Sweep работает с ненужными версиями и состоянием транзакций. Он не делает rollback уже подтверждённых продаж, не является резервным копированием и не обещает уменьшить размер FDB на диске. Эта маленькая лаборатория подтверждает вызов и сохранность выбранных текущих строк; она не измеряет ускорение большой базы и не доказывает наличие или отсутствие повреждений. Длительные открытые транзакции могут мешать освобождению версий: сначала исследуют работу приложения, а не увеличивают число sweep в минуту.

Проверьте понимание

Замените второе подтверждённое значение 7 на 12. Какой остаток должен появиться после rollback пробного 99 и после sweep?

Разбор

В обоих случаях 12. Измените ожидаемый результат вместе с входными данными. Если после обслуживания показывается 99, проблема в границе транзакции либо проверке результата; sweep не предназначен выбирать бизнес-значение вместо commit/rollback.

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

Кнопка «проверить базу» не должна показывать зелёное «всё исправно» только потому, что страница открылась. Разберём два разных отказа: неизвестное число вместо действия и правильную команду, которую не позволяет выполнить текущая архитектура подключения. Человек получит конкретные коды, понятную границу проверки и подтверждение, что каталог всё ещё доступен.

Путь к результату
  1. Неизвестный action → локальный отказ драйвера -999
  2. Тот же service ещё читает заголовок: запрос к серверу не запускался
  3. VALIDATE_DB + CHECK_DB → отказ Firebird -924 в secondary attachment
  4. Устаревший service обнуляется; создаётся новый
  5. Новый SELECT читает Cable 3 / Clamp 0; целостность базы остаётся непроверенной

Минимальный вызов и его части

$started = ibase_maintain_db(
    $service, $database, IBASE_RPR_VALIDATE_DB, IBASE_RPR_CHECK_DB
);
if ($started === false) {
    $errorCode = ibase_errcode();
    $errorMessage = ibase_errmsg();
    // Сохранить диагностику сразу; не писать «проверка пройдена».
}

VALIDATE_DB выбирает структурную проверку, CHECK_DB просит не изменять структуру. Это не SELECT таблицы. false сравнивается строго; code/message снимаются до следующей операции драйвера. Для ожидаемых предупреждений полный проект использует локальный обработчик, чтобы сохранить отказ в отчёте. Проверяемый interbase 3.0.1 при нативной ошибке сервисной операции освобождает свой handle; f159MaintenanceAttempt обнуляет переменную и не делает повторный detach старого ресурса.

Конкретный результат самостоятельного запуска

НаблюдениеРезультат
Неизвестный action принятнет
Код неверного action-999
После локального отказа читается заголовокда
Проверка структуры запущенанет
Код отказа среды-924
Старый сервисный handle больше не используетсяда
Через новое подключение: Cable / Clamp3 / 0
Успешная проверка целостности заявленанет
Полная программа, вспомогательные файлы и архив
Отличить неверную команду от отказа среды при проверке базыСамостоятельный пример
<?php
declare(strict_types=1);
require __DIR__.'/lab.php';
$owned=[];$removed=[];$db=$service=null;
try {
    $config=f159Config();$service=f159Service();$runtime=f159Runtime($service);

    $name=f159CreateDatabase($service,$owned,'validate');
    $db=f159Connect($name);
    $before=f159Read($db,'SELECT ID,TITLE,QTY FROM LAB_ITEMS ORDER BY ID');
    f159Close($db);
    $invalid=f159MaintenanceAttempt($service,$name,2147483647,0);
    $localHandleKept=is_resource($service);
    $headerAfterInvalid=f159Header($service,$name);
    $validation=f159MaintenanceAttempt($service,$name,IBASE_RPR_VALIDATE_DB,IBASE_RPR_CHECK_DB);
    $consumedHandleCleared=$service===null;
    if($validation['value']!==false || $validation['code']!==-924 || !$validation['message_present'] || !$consumedHandleCleared) {
        throw new RuntimeException('Ожидаемый отказ secondary attachment не подтверждён этим профилем');
    }
    $service=f159Service();
    $db=f159Connect($name);
    $after=f159Read($db,'SELECT ID,TITLE,QTY FROM LAB_ITEMS ORDER BY ID');
    f159Close($db);
    $rows=[['Неизвестный action принят',$invalid['value']],['Код неверного action',$invalid['code']],
        ['После локального отказа читается заголовок',is_int($headerAfterInvalid['sweep_interval'])],
        ['Проверка структуры запущена',$validation['value']],['Код отказа среды',$validation['code']],
        ['Старый сервисный handle больше не используется',$consumedHandleCleared],
        ['Через новое подключение: Cable / Clamp',$after[0]['QTY'].' / '.$after[1]['QTY']],
        ['Успешная проверка целостности заявлена',false]];
    $checks=['unknown_action_rejected'=>$invalid['value']===false && $invalid['code']===-999 && $invalid['warning'] && $invalid['message_present'],
        'local_failure_kept_service'=>$localHandleKept && is_int($headerAfterInvalid['sweep_interval']),
        'profile_validation_refusal'=>$validation['value']===false && $validation['code']===-924 && $validation['warning'] && $validation['message_present'],
        'consumed_service_cleared'=>$consumedHandleCleared,
        'fresh_service_created'=>is_resource($service),
        'catalogue_still_readable'=>$before===$after && $after===[['ID'=>1,'TITLE'=>'Cable','QTY'=>3],['ID'=>2,'TITLE'=>'Clamp','QTY'=>0]]];
    $observations=['unknown_action'=>$invalid,'header_interval_after_invalid'=>$headerAfterInvalid['sweep_interval'],
        'validation_attempt'=>$validation,'validation_completed'=>false,
        'profile_limitation'=>'secondary server attachments cannot validate databases',
        'old_service_cleared'=>$consumedHandleCleared,'before'=>$before,'after'=>$after];

} finally {
    if(is_resource($db)){f159Close($db);}
    if(is_resource($service)){f159Detach($service);}
    $removed=f159Cleanup($owned);
}

f159Report('fb159-validation','Отличить неверную команду от отказа среды при проверке базы',$rows,$checks,$observations,$runtime,$owned,$removed);
Ожидаемый результат
Неизвестный action принят — нет
Код неверного action — -999
После локального отказа читается заголовок — да
Проверка структуры запущена — нет
Код отказа среды — -924
Старый сервисный handle больше не используется — да
Через новое подключение: Cable / Clamp — 3 / 0
Успешная проверка целостности заявлена — нет

Распакуйте архив целиком в собственную папку и выполните example.php по README.txt. lab.php содержит проверку владельца, создание синтетической базы, SQL-помощники, чтение Service API и уборку. seed.sql показывает исходные Cable/3 и Clamp/0. result.html отображает предметный результат, result.json сохраняет наблюдения, metrics.json — проверки. После работы собственная база и промежуточный backup удаляются; отчёты остаются.

Открыть таблицу фактического результата · Открыть данные JSON.

Ошибки, ограничения и выбор другого инструмента

Ожидаемый -924 здесь — реальный отказ текущего embedded SuperClassic профиля: secondary server attachments cannot validate databases. Он не означает, что FDB уже признана повреждённой, и не делает правильную комбинацию VALIDATE_DB/CHECK_DB неверной для всех серверов. Для настоящей проверки нужна поддерживаемая первичная сервисная среда либо административный gfix с соответствующими правами и условиями исключительного доступа. Это условие применения, а не выполненный в данном проекте gfix-тест. Пример не меняет серверный режим ради обхода отказа и не применяет MEND. Работоспособный SELECT двух товаров подтверждает только их чтение, не физическую целостность всех страниц.

Реальная задача: обходить таблицы и читать первую строку, чтобы решить, исправна ли база. Но успешное чтение одной записи не охватывает все страницы, индексы и служебные структуры. Исходная задача на Stack Overflow. Поэтому мы отдельно показываем статус структурной проверки и статус SELECT. Даже доступный каталог после -924 не превращает отказ validate в положительное заключение.

Проверьте понимание

Какой статус показать администратору при -924: «ошибок нет», «база повреждена» или «проверка не выполнена в этом окружении»?

Разбор

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

Изменить sweep interval, прочитать настройку и вернуть исходную

При изучении настроек базы легко перепутать порог обслуживания с таймером. Здесь изменим один параметр собственной FDB с 20000 на 12345, прочитаем фактический заголовок и вернём 20000. Каталог остаётся прежним: Cable — 3, Clamp — 0. Число 12345 выбрано так, чтобы изменение было хорошо видно; это не рекомендация для рабочей базы.

Путь к результату
  1. Прочитать сохранённый sweep interval = 20000
  2. SWEEP_INTERVAL + 12345 → прочитать ответ службы
  3. Новый заголовок подтверждает 12345; товары остаются 3 / 0
  4. finally возвращает сохранённое значение
  5. Ещё одно чтение заголовка показывает 20000

Минимальный вызов и его части

$started = ibase_maintain_db($service, $database, IBASE_PRP_SWEEP_INTERVAL, 12345);
if ($started !== true) {
    throw new RuntimeException('Изменение порога не принято');
}

SWEEP_INTERVAL — название свойства в третьем аргументе. 12345 — его новое значение в четвёртом. Такой вызов не выполняет ручной sweep немедленно. Полная программа читает прежнее значение до изменения, а в finally восстанавливает именно его, не выдуманный универсальный default. Наглядный результат получен из заголовка через Service API, а не из повторного вывода литерала 12345.

Конкретный результат самостоятельного запуска

НаблюдениеРезультат
Исходный sweep interval20000
Из заголовка после изменения12345
Товары при новом порогеCable — 3; Clamp — 0
После восстановления20000
Исходная настройка возвращенада
Полная программа, вспомогательные файлы и архив
Изменить sweep interval, прочитать настройку и вернуть исходнуюСамостоятельный пример
<?php
declare(strict_types=1);
require __DIR__.'/lab.php';
$owned=[];$removed=[];$db=$service=null;
try {
    $config=f159Config();$service=f159Service();$runtime=f159Runtime($service);

    $name=f159CreateDatabase($service,$owned,'interval');
    $original=f159Header($service,$name);
    $restore=false;
    try {
        $restore=true;
        $changedJob=f159Maintain($service,$name,IBASE_PRP_SWEEP_INTERVAL,12345);
        $changed=f159Header($service,$name);
        $db=f159Connect($name);
        $catalogue=f159Read($db,'SELECT ID,TITLE,QTY FROM LAB_ITEMS ORDER BY ID');
        f159Close($db);
    } finally {
        if(is_resource($db))f159Close($db);
        if($restore) {
            if($service===null)$service=f159Service();
            $restoreJob=f159Maintain($service,$name,IBASE_PRP_SWEEP_INTERVAL,$original['sweep_interval']);
        }
    }
    $restored=f159Header($service,$name);
    $rows=[['Исходный sweep interval',$original['sweep_interval']],['Из заголовка после изменения',$changed['sweep_interval']],
        ['Товары при новом пороге','Cable — '.$catalogue[0]['QTY'].'; Clamp — '.$catalogue[1]['QTY']],
        ['После восстановления',$restored['sweep_interval']],['Исходная настройка возвращена',$restored['sweep_interval']===$original['sweep_interval']]];
    $checks=['fixture_interval_20000'=>$original['sweep_interval']===20000,
        'changed_readback_12345'=>$changed['sweep_interval']===12345 && $changedJob['started']===true,
        'unchanged_catalogue'=>$catalogue===[['ID'=>1,'TITLE'=>'Cable','QTY'=>3],['ID'=>2,'TITLE'=>'Clamp','QTY'=>0]],
        'restored_readback'=>$restoreJob['started']===true && $restored['sweep_interval']===$original['sweep_interval']];
    $observations=['original_interval'=>$original['sweep_interval'],'requested_interval'=>12345,'readback_interval'=>$changed['sweep_interval'],
        'restored_interval'=>$restored['sweep_interval'],'catalogue'=>$catalogue,'changed_service_started'=>$changedJob['started'],
        'restore_service_started'=>$restoreJob['started']];

} finally {
    if(is_resource($db)){f159Close($db);}
    if(is_resource($service)){f159Detach($service);}
    $removed=f159Cleanup($owned);
}

f159Report('fb159-sweep-interval','Изменить sweep interval, прочитать настройку и вернуть исходную',$rows,$checks,$observations,$runtime,$owned,$removed);
Ожидаемый результат
Исходный sweep interval — 20000
Из заголовка после изменения — 12345
Товары при новом пороге — Cable — 3; Clamp — 0
После восстановления — 20000
Исходная настройка возвращена — да

Распакуйте архив целиком в собственную папку и выполните example.php по README.txt. lab.php содержит проверку владельца, создание синтетической базы, SQL-помощники, чтение Service API и уборку. seed.sql показывает исходные Cable/3 и Clamp/0. result.html отображает предметный результат, result.json сохраняет наблюдения, metrics.json — проверки. После работы собственная база и промежуточный backup удаляются; отчёты остаются.

Открыть таблицу фактического результата · Открыть данные JSON.

Ошибки, ограничения и выбор другого инструмента

Интервал связан с порогом разности служебных счётчиков oldest snapshot transaction и oldest interesting transaction. Это не секунды, не количество строк и не обещание «sweep ровно после каждых 20000 commit». Нулевое значение отключает автоматический sweep, но ручной остаётся отдельной операцией. Сам по себе большой номер транзакции не доказывает повреждение базы. Нельзя без анализа переносить настройки между архитектурами или лечить длинные открытые транзакции бесконечным изменением порога.

Реальная ситуация: большой счётчик транзакций и внешний вид заголовка базы принимают за причину повреждения и отсутствия sweep. Исходная задача на Stack Overflow. Число само по себе не является диагнозом. Для нашей задачи читаем конкретный sweep interval, меняем только его, подтверждаем новое значение и возвращаем старое. Восстановление повреждённой базы не подменяем настройкой этого порога.

Проверьте понимание

Что нужно изменить, чтобы временно проверить значение 25000, сохранив исходное состояние базы после примера?

Разбор

Замените запрашиваемый порог и ожидаемое обратное чтение 12345 на 25000. Код сохранения original и восстановления в finally оставьте прежним. Ожидаемое исходное 20000 относится к учебной fixture; для другой базы читают её настоящее значение.

Настроить число страниц кэша и проверить сохранённое значение

При изучении кэша важно понять единицу настройки. Указываем 256 страниц базы, а не 256 мегабайт, и читаем сохранённый параметр из заголовка. Затем возвращаем исходный 0. Пользователь видит конкретную настройку и неизменный каталог Cable — 3, Clamp — 0; это проверка управления свойством, а не обещание ускорить любой запрос.

Путь к результату
  1. Заголовок собственной FDB: page buffers = 0
  2. PAGE_BUFFERS + 256 → получить ответ службы
  3. Новый заголовок показывает 256; SELECT читает Cable 3 / Clamp 0
  4. finally возвращает сохранённое значение 0
  5. Ещё одно чтение подтверждает 0, затем собственная FDB удаляется

Минимальный вызов и его части

$started = ibase_maintain_db($service, $database, IBASE_PRP_PAGE_BUFFERS, 256);
if ($started !== true) {
    throw new RuntimeException('Настройка кэша не принята');
}
// Прочитайте завершение службы и фактическое поле Page buffers заголовка.

PAGE_BUFFERS в третьем аргументе выбирает свойство, 256 в четвёртом — число страниц. В полной программе readPageBuffers159 извлекает число из настоящего заголовка. setPageBuffers159 проверяет диапазон и владение базой, вызывает ibase_maintain_db и читает завершение службы через native item62. try/finally возвращает ранее прочитанное значение, даже если промежуточное чтение не завершится. Не нужно менять общий серверный конфигурационный файл ради этого опыта.

Конкретный результат самостоятельного запуска

НаблюдениеРезультат
Исходное число page buffers в заголовке0
Запрошенное число страниц256
Прочитано из заголовка после изменения256
Каталог при новой настройкеCable — 3; Clamp — 0
После восстановления0
Исходное значение возвращенода
Полная программа, вспомогательные файлы и архив
Настроить число страниц кэша и проверить сохранённое значениеСамостоятельный пример
<?php
declare(strict_types=1);
require __DIR__.'/lab.php';
$owned=[];$removed=[];$db=$service=null;
try {
    $config=f159Config();$service=f159Service();$runtime=f159Runtime($service);

    function readPageBuffers159(&$service,string $name): int {
        $header=f159Header($service,$name);
        if(!preg_match('/Page buffers\s+(\d+)/i',$header['text'],$match)) {
            throw new RuntimeException('Заголовок не содержит число буферов страниц');
        }
        return (int)$match[1];
    }
    function setPageBuffers159(&$service,string $name,int $pages): array {
        if($pages!==0 && ($pages<50 || $pages>2147483646))throw new InvalidArgumentException('Число буферов вне диапазона');
        $started=f159MaintenanceAttempt($service,$name,IBASE_PRP_PAGE_BUFFERS,$pages);
        if($started['value']!==true || $started['warning'])f159Failure('Число буферов не принято',$started);
        $completed=f159Capture(static fn()=>ibase_server_info($service,F159_SVC_LINE));
        if($completed['value']===false || $completed['warning'] || (!is_string($completed['value']) && $completed['value']!==true)) {
            if($completed['value']===false && $completed['code']!==0)$service=null;
            f159Failure('Ответ настройки буферов не прочитан',$completed);
        }
        return ['started'=>true,'completion_read'=>true];
    }
    $name=f159CreateDatabase($service,$owned,'buffers');
    $original=readPageBuffers159($service,$name);
    $restore=false;
    try {
        $restore=true;
        $changedJob=setPageBuffers159($service,$name,256);
        $changed=readPageBuffers159($service,$name);
        $db=f159Connect($name);
        $catalogue=f159Read($db,'SELECT ID,TITLE,QTY FROM LAB_ITEMS ORDER BY ID');
        f159Close($db);
    } finally {
        if(is_resource($db))f159Close($db);
        if($restore) {
            if($service===null)$service=f159Service();
            $restoreJob=setPageBuffers159($service,$name,$original);
        }
    }
    $restored=readPageBuffers159($service,$name);
    $rows=[['Исходное число page buffers в заголовке',$original],['Запрошенное число страниц',256],
        ['Прочитано из заголовка после изменения',$changed],
        ['Каталог при новой настройке','Cable — '.$catalogue[0]['QTY'].'; Clamp — '.$catalogue[1]['QTY']],
        ['После восстановления',$restored],['Исходное значение возвращено',$restored===$original]];
    $checks=['fixture_default_buffers'=>$original===0,
        'changed_buffers_readback'=>$changed===256 && $changedJob['started'] && $changedJob['completion_read'],
        'catalogue_unchanged'=>$catalogue===[['ID'=>1,'TITLE'=>'Cable','QTY'=>3],['ID'=>2,'TITLE'=>'Clamp','QTY'=>0]],
        'restored_buffers_readback'=>$restored===$original && $restoreJob['started'] && $restoreJob['completion_read']];
    $observations=['original_page_buffers'=>$original,'requested_page_buffers'=>256,'readback_page_buffers'=>$changed,
        'restored_page_buffers'=>$restored,'catalogue'=>$catalogue,'change'=>$changedJob,'restore'=>$restoreJob,
        'unit'=>'database pages; not bytes or megabytes'];

} finally {
    if(is_resource($db)){f159Close($db);}
    if(is_resource($service)){f159Detach($service);}
    $removed=f159Cleanup($owned);
}

f159Report('fb159-page-buffers','Настроить число страниц кэша и проверить сохранённое значение',$rows,$checks,$observations,$runtime,$owned,$removed);
Ожидаемый результат
Исходное число page buffers в заголовке — 0
Запрошенное число страниц — 256
Прочитано из заголовка после изменения — 256
Каталог при новой настройке — Cable — 3; Clamp — 0
После восстановления — 0
Исходное значение возвращено — да

Распакуйте архив целиком в собственную папку и выполните example.php по README.txt. lab.php содержит проверку владельца, создание синтетической базы, SQL-помощники, чтение Service API и уборку. seed.sql показывает исходные Cable/3 и Clamp/0. result.html отображает предметный результат, result.json сохраняет наблюдения, metrics.json — проверки. После работы собственная база и промежуточный backup удаляются; отчёты остаются.

Открыть таблицу фактического результата · Открыть данные JSON.

Ошибки, ограничения и выбор другого инструмента

Значение 0 в заголовке означает отсутствие отдельного значения для базы, а не отсутствие кэша: действует значение по умолчанию окружения. Число буферов не меняет размер страницы FDB. Реальный расход памяти и организация кэша зависят от серверной архитектуры, подключений и других параметров; нельзя просто умножить это число и объявить всю потреблённую память. Чтение нового заголовка не обещает немедленного изменения пула уже работающих чужих подключений: лаборатория открывает своё SQL-соединение после настройки. 256 — маленькое наглядное учебное значение. Пример проверяет сохранение и восстановление параметра, не бенчмарк, не оптимизацию запроса и не переносимую рекомендацию для production. Возврат исходного 0 проверяется именно нативным API этого профиля; описание 0 в заголовке само по себе не доказывает, что любая версия команды gfix принимает 0 как аргумент.

Проверьте понимание

Почему нельзя выводить «кэш 256 МБ» сразу после успешного вызова PAGE_BUFFERS с аргументом 256?

Разбор

Аргумент задаёт страницы, а не мегабайты. Сначала подтвердите сохранённое значение, выясните размер страниц и архитектуру сервера. Даже произведение количества на размер страницы описывает лишь соответствующий объём страниц, а не всю память процесса. Для оценки ускорения нужен отдельный измеримый рабочий запрос.

Справочник команды обслуживания и её аргументов

ФункцияКогда нужна
ibase_maintain_dbСервисное действие, числовое свойство, именованный режим, результат запуска и поздние ошибки.

Сопоставлять служебный ответ с реальными данными

Теперь результат можно объяснить предметно. Sweep сохранил актуальные 7 и 0; административный порог и число страниц кэша прочитаны обратно и возвращены к прежним значениям. Отказ проверки -924 остался отказом проверки, даже когда каталог читается. Это разные наблюдения, и интерфейс администратора должен показывать их раздельно.

Далее используйте настройки расширения и параметры окружения, проверяемое резервное копирование и восстановление и обработку ошибок запросов. Если проблема в медленном выборе данных, сначала смотрят запрос, нужные столбцы, WHERE, порядок и индекс; обслуживание базы не заменяет правильно поставленную SQL-задачу.

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

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

ibase_maintain_dbЗапустить обслуживание или изменение свойства базы через Service Manager и отдельно проверить завершение и результат.

Исторически PHP 5 / PHP 7 до 7.4; затем отдельное расширение. Проверяемый профиль interbase 3.0.1 / PHP 8.2. · interbase

ibase_maintain_db(resource $service_handle, string $db, int $action, int $argument = 0): bool

Администратору может понадобиться выполнить sweep, проверить структуру, поменять интервал обслуживания или временно запретить запись всей базы. ibase_maintain_db отправляет такую команду через Service Manager. Эта функция не заменяет UPDATE, не выбирает строки и не принимает обычный ресурс SQL-соединения вместо сервисного.

ibase_maintain_db(resource $service_handle, string $db, int $action, int $argument = 0): bool
Параметр / результатЧто передать и как понимать
service_handleДействующий ресурс от ibase_service_attach. У сервисной учётной записи должны быть полномочия на выбранное обслуживание. Подключение обычного читателя таблиц само по себе таких полномочий не доказывает.
dbПуть или допустимое имя базы со стороны сервера Firebird. Это не resource от ibase_connect, не имя таблицы и не путь к загружаемому через браузер файлу.
actionОдно распознаваемое действие IBASE_PRP_* или основное IBASE_RPR_*. Выбор определяет смысл и формат четвёртого аргумента.
argumentПо умолчанию 0. Для свойства — число/именованный режим; для repair — дополнительные разрешённые флаги. Нельзя предполагать, что 0 всегда означает отсутствие изменения.
trueДрайвер успешно вызвал isc_service_start. Это подтверждение запуска запроса службы, а не автоматически прочитанный итог проверки всех данных.
falseКоманда не принята либо не распознана; сразу сохраните ibase_errcode/ibase_errmsg и предупреждение. Поздний отказ может появиться при чтении ответа службы. Неверные типы PHP могут вызвать исключение языка.

На странице PHP Manual сейчас приведены только сигнатура и bool-результат; подробности ниже восстановлены по первичному исходнику interbase 3.0.1 и документации Firebird. Историческая отметка PHP 5 / PHP 7 до 7.4 относится к старому встроенному расширению. Примеры используют отдельное interbase 3.0.1, PHP 8.2.35 NTS x64 и Firebird 5.0.4 embedded; успешный запуск этого профиля не является обещанием совместимости со всеми версиями InterBase.

От команды к подтверждённому результату
  1. Сервисный ресурс + собственное имя FDB + action + argument
  2. ibase_maintain_db → true означает, что задание начато
  3. Прочитать ответ той же службы и проверить позднюю ошибку
  4. Открыть базу заново: прочитать header или выбранные товары
  5. Показать конкретный режим/остаток/интервал; восстановить изменённое свойство

Применение 1: настроить sweep interval с обратным чтением

$started = ibase_maintain_db($service, $database, IBASE_PRP_SWEEP_INTERVAL, 12345);
if ($started !== true) {
    $errorCode = ibase_errcode();
    $errorMessage = ibase_errmsg();
    throw new RuntimeException('Интервал обслуживания не принят');
}
// Дальше прочитать ответ службы, затем заголовок базы и сравнить interval с 12345.

Четвёртый аргумент здесь — новый числовой порог, а не маска. Полная программа сохраняет исходное значение, применяет 12345, читает его из заголовка и восстанавливает исходное в finally. Факт изменения измеряется обратным чтением, а не печатью заранее заданной переменной. Это административная настройка; её нельзя выполнять при каждом HTTP-запросе пользователя.

Применение 2: проверить структуру без её изменения

$started = ibase_maintain_db(
    $service,
    $database,
    IBASE_RPR_VALIDATE_DB,
    IBASE_RPR_CHECK_DB
);
if ($started !== true) {
    throw new RuntimeException('Проверка структуры не запущена');
}
// Считать ответ службы и ошибки; чтение двух товаров не заменяет этот результат.

VALIDATE_DB выбирает операцию, CHECK_DB ограничивает её режимом без обновления. Если дополнительно нужна проверка фрагментов записей, её контекстная форма — CHECK_DB | FULL в четвёртом аргументе. Полный пример сначала ловит неизвестный action, затем вызывает корректную комбинацию VALIDATE_DB/CHECK_DB. В данном embedded-профиле сервер отказывает с кодом -924: secondary server attachments cannot validate databases. Пример показывает этот реальный отказ, новое сервисное подключение и сохранённый каталог; он не выдаёт доступность двух строк за успешную проверку структуры всей базы.

Свойство и числовое значение — разные аргументы

actionargument и назначение
IBASE_PRP_PAGE_BUFFERSЧисло страниц кэша базы. Это количество буферов, а не размер одной страницы и не мегабайты; допустимые значения и расход памяти зависят от сервера/архитектуры.
IBASE_PRP_SWEEP_INTERVALНеотрицательный порог автоматического sweep; 0 отключает именно автоматический sweep. Значение не является временем в секундах.
IBASE_PRP_SHUTDOWN_DBВремя ожидания перед принудительным завершением работы с указанной базой. Это административное отключение подключений/транзакций, не остановка всех баз сервера.
IBASE_PRP_DENY_NEW_TRANSACTIONSСрок ожидания завершения имеющихся транзакций при запрете новых в процедуре отключения базы. Не переключатель read-only.
IBASE_PRP_DENY_NEW_ATTACHMENTSСрок ожидания выхода подключений при запрете новых в процедуре отключения базы. Не способ определить владельца веб-сессии.
IBASE_PRP_SET_SQL_DIALECTДиалект базы: 1 или 3. Изменение свойства не является автоматической миграцией всех данных/DDL и не заменяет изучение совместимости.

В этих ветках реализация 3.0.1 упаковывает четвёртый аргумент как четырёхбайтовое число. Не передавайте отрицательное значение или произвольный PHP int в надежде, что сервер догадается о смысле. Ограничьте разрешённые операции и диапазоны до вызова, а сохранённое значение затем прочитайте обратно. Нельзя передать PAGE_BUFFERS | SWEEP_INTERVAL, чтобы настроить сразу два свойства.

Свойство и именованный режим

actionargument — отдельное значение
IBASE_PRP_RESERVE_SPACEIBASE_PRP_RES оставляет резерв в страницах для будущих версий строк; IBASE_PRP_RES_USE_FULL позволяет заполнять страницы полнее. Это не резервирование товара и не настройка свободного места на диске.
IBASE_PRP_WRITE_MODEIBASE_PRP_WM_SYNC — синхронная запись, IBASE_PRP_WM_ASYNC — асинхронная. Выбор затрагивает надёжность сохранения, а не только скорость; примеры режим записи не меняют.
IBASE_PRP_ACCESS_MODEIBASE_PRP_AM_READONLY или IBASE_PRP_AM_READWRITE. Изменяется режим целой базы для подключений, а не права одного пользователя приложения.

Для этих трёх свойств драйвер передаёт однобайтовый режим. Вызов ACCESS_MODE без четвёртого аргумента отправит 0, а не «сохранить прежний режим». Именованные значения — не битовая маска: READONLY | READWRITE не является третьим допустимым режимом. Сначала сохраните прежнее состояние, завершите свои подключения, примените команду, а затем подтвердите состояние новым чтением.

Проверка, очистка и специальные операции

КонстантаГде используется и что важно
IBASE_RPR_SWEEP_DBОсновное действие ручного sweep: обслуживание версий записей и состояния транзакций. Это не исправление всех повреждений и не удаление актуальных товаров.
IBASE_RPR_VALIDATE_DBОсновное действие проверки структуры базы. Без ограничивающих параметров проверка может изменять служебные структуры; не объявляйте любой validate чисто читающим.
IBASE_RPR_CHECK_DBМодификатор проверки без обновления структуры. В примере передаётся четвёртым аргументом к VALIDATE_DB.
IBASE_RPR_FULLДополнительная проверка фрагментов записей; комбинируется с CHECK_DB через | в argument, а не в action. Не отдельное поддерживаемое действие switch этой версии.
IBASE_RPR_IGNORE_CHECKSUMПросьба игнорировать проверки контрольных сумм при подходящей операции; не признак исправности. Историческая возможность, которую нельзя добавлять как универсальное лечение.
IBASE_RPR_MEND_DBПодготовка повреждённой базы к извлечению доступных данных; может исключить повреждённые записи и привести к потере данных. Не routine sweep и не гарантия восстановления.
IBASE_RPR_KILL_SHADOWSУдаление ссылок на недоступные shadow-копии. Не очистка обычных резервных FBK и не средство ускорения SELECT.
IBASE_PRP_ACTIVATEАктивация shadow-копии в специальной процедуре восстановления. Нельзя экспериментировать с живой рабочей базой.
IBASE_PRP_DB_ONLINEВозврат ранее отключённой базы к работе. Современные режимы shutdown/online шире исторического набора этого PHP-адаптера.

Исходник драйвера принимает action через точный switch. Для веток repair он формирует поле options как action | argument; поэтому дополнительные флаги помещаются в argument. Перечисление констант не означает, что любая их комбинация допустима. Например, VALIDATE_DB | FULL в третьем аргументе может попасть в другую числовую ветку либо дать отказ. Используйте основное действие и документированные дополнительные параметры отдельно. Современные возможности gfix, например дополнительные режимы и параллельные работники, нельзя автоматически получить, подставив их число в старый PHP switch.

Прочитать ответ именно запущенной службы

// Число 62 — isc_info_svc_line нативного Firebird API.
// В interbase 3.0.1 нет отдельной PHP-константы с этим именем.
$output = ibase_server_info($service, 62);
if ($output === false) {
    $code = ibase_errcode();
    $message = ibase_errmsg();
    throw new RuntimeException('Служба сообщила ошибку при чтении результата');
}
// В этой реализации true означает завершённый ответ без строк;
// string содержит собранный текст. Не публикуйте сырой журнал с серверными путями.

Числовой item дан явно как совместимость с закреплённым API, а не выдан за стандартную PHP-константу. Внутренний код interbase читает строки службы до окончания ответа. Отсутствие строк может быть нормальным для успешного обслуживания: false и true здесь различаются строго. Другую команду на том же service_handle запускают после чтения результата предыдущей. Общую схему подключения и диагностики объясняет глава Service Manager.

Есть важная особенность владения ресурсом в закреплённом interbase 3.0.1: при нативном отказе Service API драйвер уничтожает сервисный ресурс. Сохранённую переменную затем обнуляют и при необходимости создают новое подключение; повторный detach старого handle недопустим. При локальном отказе неизвестного action служба не запускалась и handle остаётся. В нашем профиле локальный отказ имеет код -999, а отказ validation — -924; одно лишь «код не равен нулю» не различает эти случаи. Учебный адаптер учитывает распознанные ветки action из исходника. Это версионное правило управления ресурсом, не универсальная трактовка любого кода ошибки Firebird.

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

Обслуживание структуры и смена режима могут требовать отсутствия обычных подключений. Перед ними завершают свои транзакции, освобождают результаты и закрывают соединения; Service Manager остаётся отдельным ресурсом. Не делайте принудительный shutdown чужих пользователей, чтобы «починить» учебный пример. Перед восстановительными действиями нужна сохранённая копия и проверяемый план: backup и restore относятся к другой задаче, чем sweep или настройка свойства.

Для обычного чтения/записи нужны ibase_query и SELECT, для отказа неподтверждённой покупки — rollback, для ограничения конкретного пользователя — права/роль. Режим базы READONLY, транзакция READ ONLY и разрешение SELECT — разные уровни. READONLY не является ускорителем всех запросов или заменой индекса.

Граница применения ACCESS_MODE в этом профиле

В ограниченной подготовке READONLY был подтверждён заголовком, а UPDATE получил отказ -817. Но полный самостоятельный цикл переключения и восстановления в данном embedded-профиле не прошёл: возврат READWRITE встретил -901 с сообщением, что база используется. Новая сервисная сессия это не устранила. Поэтому готового запускаемого проекта, обещающего успешный полный цикл READONLY → READWRITE, здесь нет. Сам контракт функции и обе константы сохранены: перед реальным применением нужно обеспечить поддерживаемую среду и отсутствие мешающих подключений, а не бесконечно повторять переключатель.

Похожая задача об ошибке read-only на Stack Overflow показывает, почему сначала определяют уровень запрета. Ошибка при записи BLOB не означает автоматически проблему кодировки; режим базы, параметры транзакции и права проверяются отдельно. Этот разбор не является разрешением включить запись неизвестной архивной или рабочей базы.

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

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

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

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

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