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

Дерево руководства
Глава 87 · После форм строк CUBRID
CUBRID: паспорт колонок, происхождение полей и границы метаданных
Паспорт экспорта, имена и происхождение колонок, типовые ширины и флаги, отдельный указатель полей и пустые результаты.
Зачем знать не только строки, но и смысл колонок
При подготовке таблицы для администратора мало знать только значения Кабель и 0. Нужно объяснить, как называются поля, какие у них типы, откуда они пришли и что означает ограничение хранения. В этих проектах получится паспорт экспорта, понятная карта псевдонимов, разбор правил заполнения и повторный заголовок без перемотки товаров.
Метаданные — данные об устройстве результата. Описание title / varchar / 120 не является ещё одной товарной строкой; строка хранит конкретное слово Кабель. SQL сначала выбирает нужные поля и ограниченные записи, затем PHP читает описание и оформляет экран. Ни справка о колонках, ни её обход не требуют получить весь каталог и сортировать его в PHP.
- Схема: title VARCHAR(120), qty INT NOT NULL
- SELECT sku,title,qty → выбранных полей 3, исходных колонок таблицы 7
- Описание: позиция 1 → title / varchar / ширина 120
- Значение этой позиции в карточке: Кабель; strlen UTF-8 → 12 байт
- Интерфейс использует подписи и правила приложения; метаданные помогают, но не заменяют их
Удобная модель — шапка и строки накладной. В шапке описывается назначение колонки, в строке находится товарное значение. Указатель описаний двигается по колонкам, товарный курсор — по строкам. Но реальные ограничения схемы сложнее накладной: не вся информация DDL сохраняется в метаданных выражения или псевдонима.
Сначала полезно пройти подключение и таблицу, параметры и SELECT и формы строк и общие метаданные. Здесь сначала дан минимальный вызов, затем самостоятельный проект с конкретным результатом. Соседняя глава перемещения по строкам отдельно объясняет data_seek и длины текущей записи.
| Потребность | Что получится | Проект |
|---|---|---|
| Описать формат обмена | sku/varchar/24; title/varchar/120; qty/integer/11 | Паспорт полей |
| Разобраться с AS и выражениями | display_title→Кабель; double_price→25800; собственная карта правок | Имена и происхождение |
| Не спутать хранение и требования формы | 0 принят, пустое название отклонено, NULL и пустая строка различимы | Правила карточки |
| Перечитать заголовок | Поля sku/title/qty; товары Кабель/Клемма независимо | Указатель метаданных |
Составить понятный паспорт трёх полей экспорта
Администратор готовит обмен с каталогом и должен понять, что означает каждое поле файла. Вместо семи колонок исходной таблицы запрос выбирает три: артикул, название и остаток. Отчёт покажет их имена, SQL-типы, ширины и флаги рядом с конкретной записью CAB-167 / Кабель / 0.
- SELECT sku,title,qty → три поля в порядке файла
- num_fields → 3; позиции метаданных 0,1,2
- field_name/type/len → sku/varchar/24, title/varchar/120, qty/integer/11
- Флаги указывают UNIQUE у sku и NOT NULL у qty
- Строка данных отдельно: CAB-167 / Кабель / 0
Самый простой вызов и его объяснение
$field = cubrid_fetch_field($request, 1);
if ($field === false) { throw new RuntimeException("Нет поля"); }
echo $field->name, " / ", $field->type, "\n"; // title / varcharВторой аргумент 1 — индекс второго поля SELECT, потому что отсчёт начинается с нуля. Возвращается объект описания: стрелка -> читает свойство name либо type. Это не объект товара и не очередная строка. num_fields считает выбранные поля, а не строки и не все столбцы таблицы. Полный цикл обращается только к индексам меньше полученного количества.
Видимый результат самостоятельной программы
| Наблюдение | Результат |
|---|---|
| Выбрано полей | 3 |
| Поле 0 | sku / varchar / 24 |
| Поле 1 | title / varchar / 120 |
| Поле 2 | qty / integer / 11 |
| SKU: уникальный ключ | да |
| Остаток: NOT NULL | да |
| Строка экспорта | CAB-167 / Кабель / 0 |
| fetch_field.max_length для title | 0 |
Полная программа, файлы и архив для запуска
<?php
declare(strict_types=1);
require __DIR__.'/lab.php';
$db=null;$owned=$removed=$rows=$checks=$observations=[];
try {
$config=c167Config();$db=c167Connect();$runtime=c167Runtime($db);
$name=c167CreateTable($db,$owned,'fieldcatalog',[
['id'=>1,'sku'=>'CAB-167','title'=>'Кабель','category'=>'electric','price_cents'=>12900,'qty'=>0,'note'=>null]
]);$table=c167Qualified($name);
$request=cubrid_execute($db,'SELECT sku,title,qty FROM '.$table.' WHERE id=1');
if($request===false){c167Failure('Каталог полей не выбран');}
$fields=[];
try {
$count=cubrid_num_fields($request);
if($count===false||$count<0){throw new RuntimeException('Нет количества полей.');}
for($position=0;$position<$count;$position++){
$field=cubrid_fetch_field($request,$position);
if($field===false){c167Failure('Не получен паспорт поля');}
$nameAtPosition=cubrid_field_name($request,$position);
$type=cubrid_field_type($request,$position);
$length=cubrid_field_len($request,$position);
$flags=cubrid_field_flags($request,$position);
if(!is_string($nameAtPosition)||!is_string($type)||!is_int($length)||!is_string($flags)){
throw new RuntimeException('Описание поля неполное.');
}
$fields[]=['position'=>$position,'name'=>$nameAtPosition,'type'=>$type,'length'=>$length,
'flags'=>$flags,'object'=>get_object_vars($field)];
}
$item=cubrid_fetch_assoc($request);
if(!is_array($item)){throw new RuntimeException('Не получена карточка.');}
} finally {c167Release($request);}
$rows=[['Выбрано полей',$count],['Поле 0',$fields[0]['name'].' / '.$fields[0]['type'].' / '.$fields[0]['length']],
['Поле 1',$fields[1]['name'].' / '.$fields[1]['type'].' / '.$fields[1]['length']],
['Поле 2',$fields[2]['name'].' / '.$fields[2]['type'].' / '.$fields[2]['length']],
['SKU: уникальный ключ',in_array('unique_key',explode(' ',$fields[0]['flags']),true)],
['Остаток: NOT NULL',in_array('not_null',explode(' ',$fields[2]['flags']),true)],
['Строка экспорта',$item['sku'].' / '.$item['title'].' / '.$item['qty']],
['fetch_field.max_length для title',$fields[1]['object']['max_length']]];
$checks=['three_fields'=>$count===3,'names_order'=>array_column($fields,'name')===['sku','title','qty'],
'types_order'=>array_column($fields,'type')===['varchar','varchar','integer'],
'widths_not_row_lengths'=>array_column($fields,'length')===[24,120,11],
'unique_sku'=>in_array('unique_key',explode(' ',$fields[0]['flags']),true),
'not_null_qty'=>in_array('not_null',explode(' ',$fields[2]['flags']),true),
'object_names_match'=>array_column(array_column($fields,'object'),'name')===['sku','title','qty'],
'max_length_not_trusted'=>$fields[1]['object']['max_length']===0,
'actual_card'=>$item===['sku'=>'CAB-167','title'=>'Кабель','qty'=>'0'],'request_closed'=>$request===null];
$observations=['field_catalog'=>$fields,'actual_row'=>$item,'selected_columns'=>3,
'schema_columns'=>7,'width_units'=>'Driver type width/precision; not measured row bytes.'];
} finally {
if (is_resource($db)) {try {$removed=c167Cleanup($db,$owned);} finally {c167Close($db);}}
}
c167Report('cub167-field-catalog','Составить понятный паспорт трёх полей экспорта',$rows,$checks,$observations,$runtime,$owned,$removed);
Ожидаемый результат
Выбрано полей — 3
Поле 0 — sku / varchar / 24
Поле 1 — title / varchar / 120
Поле 2 — qty / integer / 11
SKU: уникальный ключ — да
Остаток: NOT NULL — да
Строка экспорта — CAB-167 / Кабель / 0
fetch_field.max_length для title — 0
Распакуйте архив целиком и запустите example.php по README.txt в отдельной CUBRID-лаборатории. lab.php проверяет маркер namespace/базы, создаёт только свою случайную c167-таблицу и удаляет её в finally. result.html показывает значения, result.json — метаданные и наблюдения, metrics.json — проверки и очистку. Реквизиты подключения остаются в закрытом окружении.
Открыть фактический результат · Открыть данные JSON.
Границы и ошибки
В закреплённом расширении fetch_field.max_length всегда 0: это ограничение реализации, а не доказательство нулевой ширины title. Для типовой ширины используется отдельный field_len. Поле multiple_key объекта также не доказывает наличие индекса: драйвер вычисляет его как отрицание unique_key. Метаданные результата не являются полной схемой миграции и не раскрывают всю логику разрешённых значений.
В C-клиенте MySQL длина метаданных не совпала с объявленным размером CHAR, что мешало переносу схемы. Исходное обсуждение. Это повод различить схему, типовую ширину драйвера и байты текущего значения. Старый совет делить ширину на три не переносится в CUBRID; его правила сверены с исходником и реальной подготовкой.
Измените требование
В экспорт решили добавить note. Что должно измениться и почему количество строк товара не обязано меняться?
Разбор решения
Добавьте note в список SELECT: num_fields станет 4, цикл получит четвёртое описание, а одна выбранная товарная строка останется одной. Отдельно договоритесь, как представить SQL NULL примечания в обменном файле; описание поля не выбирает за вас формат отсутствующего значения.
Отличить имя на экране от поля таблицы и вычисляемой цены
Экран называет поле display_title, а таблица хранит его как title. Рядом показывается двойная цена 25800 копеек, рассчитанная SQL. Для редактора важно отличить обычную колонку от вычисления: псевдоним удобен пользователю кода, но не создаёт новую записываемую колонку.
- p.title AS display_title → ключ PHP display_title, значение Кабель
- field_table простого поля → собственная таблица каталога
- p.price_cents*2 AS double_price → 25800, исходная таблица у выражения не указана
- Приложение разрешает только известное сопоставление display_title → title
- Вычисление double_price показывается, но не включается в редактор
Самый простой вызов и его объяснение
$name = cubrid_field_name($request, 1);
$table = cubrid_field_table($request, 1);
if (!is_string($name) || !is_string($table)) {
throw new RuntimeException("Нет описания источника");
}
echo $name; // display_titleAS задаёт имя поля результата. field_table сообщает доступное драйверу происхождение таблицы, а field_name — имя в текущем SELECT. fetch_field этой библиотеки не содержит mysqli-свойства orgname. Поэтому приложение хранит своё небольшое сопоставление разрешённых редактируемых полей; оно не пытается извлечь исходный SQL из произвольного alias.
Видимый результат самостоятельной программы
| Наблюдение | Результат |
|---|---|
| Ключ названия на экране | display_title |
| Название | Кабель |
| Исходная таблица двух простых полей | Таблица каталога |
| Вычисленная цена в копейках | 25800 |
| Таблица у выражения отсутствует | да |
| Известное приложению поле редактирования | title |
| Вычисляемая double_price доступна для записи | нет |
| Свойство orgname есть у fetch_field | нет |
Полная программа, файлы и архив для запуска
<?php
declare(strict_types=1);
require __DIR__.'/lab.php';
$db=null;$owned=$removed=$rows=$checks=$observations=[];
try {
$config=c167Config();$db=c167Connect();$runtime=c167Runtime($db);
$name=c167CreateTable($db,$owned,'fieldorigins',[
['id'=>1,'sku'=>'CAB-167','title'=>'Кабель','category'=>'electric','price_cents'=>12900,'qty'=>0,'note'=>null]
]);$table=c167Qualified($name);
$request=cubrid_execute($db,'SELECT p.sku AS article,p.title AS display_title,p.price_cents*2 AS double_price FROM '.$table.' p WHERE p.id=1');
if($request===false){c167Failure('Строка с псевдонимами не выбрана');}
$fields=[];
try {
$count=cubrid_num_fields($request);
if($count!==3){throw new RuntimeException('Ожидались три поля.');}
for($i=0;$i<$count;$i++){
$field=cubrid_fetch_field($request,$i);
$origin=cubrid_field_table($request,$i);
$label=cubrid_field_name($request,$i);
if($field===false||!is_string($origin)||!is_string($label)){throw new RuntimeException('Происхождение не прочитано.');}
$fields[]=['label'=>$label,'table'=>$origin,'properties'=>get_object_vars($field)];
}
$item=cubrid_fetch_assoc($request);
if(!is_array($item)){throw new RuntimeException('Нет карточки.');}
} finally {c167Release($request);}
// Сопоставление задаёт наше приложение; оно не выдумывает исходное имя из alias.
$editMap=['display_title'=>'title'];
$ownOrigin0=strtolower($fields[0]['table'])===$name||strtolower($fields[0]['table'])==='dba.'.$name;
$ownOrigin1=strtolower($fields[1]['table'])===$name||strtolower($fields[1]['table'])==='dba.'.$name;
$expressionHasNoTable=$fields[2]['table']==='';
$rows=[['Ключ названия на экране',$fields[1]['label']],['Название',$item['display_title']],
['Исходная таблица двух простых полей',$ownOrigin0&&$ownOrigin1?'Таблица каталога':'Неожиданный источник'],
['Вычисленная цена в копейках',(int)$item['double_price']],['Таблица у выражения отсутствует',$expressionHasNoTable],
['Известное приложению поле редактирования',$editMap['display_title']],
['Вычисляемая double_price доступна для записи',array_key_exists('double_price',$editMap)],
['Свойство orgname есть у fetch_field',array_key_exists('orgname',$fields[1]['properties'])]];
$checks=['alias_names'=>array_column($fields,'label')===['article','display_title','double_price'],
'base_origins'=>$ownOrigin0&&$ownOrigin1,'expression_origin_empty'=>$expressionHasNoTable,
'visible_values'=>$item===['article'=>'CAB-167','display_title'=>'Кабель','double_price'=>'25800'],
'explicit_edit_mapping'=>$editMap===['display_title'=>'title'],
'computed_read_only'=>!array_key_exists('double_price',$editMap),
'no_invented_orgname'=>!array_key_exists('orgname',$fields[1]['properties']),'request_closed'=>$request===null];
$observations=['fields'=>$fields,'row'=>$item,'application_edit_mapping'=>$editMap,
'computed_column'=>'price_cents*2 AS double_price','no_SQL_generated_from_user_supplied_metadata'=>true];
} finally {
if (is_resource($db)) {try {$removed=c167Cleanup($db,$owned);} finally {c167Close($db);}}
}
c167Report('cub167-field-origins','Отличить имя на экране от поля таблицы и вычисляемой цены',$rows,$checks,$observations,$runtime,$owned,$removed);
Ожидаемый результат
Ключ названия на экране — display_title
Название — Кабель
Исходная таблица двух простых полей — Таблица каталога
Вычисленная цена в копейках — 25800
Таблица у выражения отсутствует — да
Известное приложению поле редактирования — title
Вычисляемая double_price доступна для записи — нет
Свойство orgname есть у fetch_field — нет
Распакуйте архив целиком и запустите example.php по README.txt в отдельной CUBRID-лаборатории. lab.php проверяет маркер namespace/базы, создаёт только свою случайную c167-таблицу и удаляет её в finally. result.html показывает значения, result.json — метаданные и наблюдения, metrics.json — проверки и очистку. Реквизиты подключения остаются в закрытом окружении.
Открыть фактический результат · Открыть данные JSON.
Границы и ошибки
Пустая строка таблицы у вычисления не равна ошибке false и не означает, что поле отсутствует в результате. Нельзя считать наличие имени таблицы полным разрешением UPDATE: JOIN, представления, права и бизнес-правила требуют отдельного решения. Не подставляйте имена из запроса пользователя в SQL. Параметры bind предназначены для значений, а разрешённая структура задаётся приложением.
Автор PDO-отчёта хотел получить исходное имя за псевдонимом и сравнивал разные наборы свойств драйверов. Исходное обсуждение. В этой главе проверяется конкретный CUBRID: имя результата и происхождение таблицы показываются отдельно, а разрешённое редактирование задаёт собственная карта. Свойства mysqli orgname/orgtable не выдумываются.
Измените требование
В SELECT добавили price_cents + 500 AS delivered_price. Можно ли автоматически создать редактор delivered_price?
Разбор решения
Нет: это значение выражения, а не новая колонка. Покажите вычисленный результат и отдельно определите, что редактируется — исходная цена, доставка или иной параметр. Если нужна запись title, используйте заранее известное поле title и параметризованное значение, а не произвольный псевдоним посетителя.
Сопоставить подсказки схемы с правилами заполнения карточки
Импорт может сохранить черновик товара с пустым названием, но публиковать такую карточку нельзя. Нулевой остаток, наоборот, допустим и нужен посетителю. Отчёт сопоставляет типовые ширины и флаги схемы с реальными значениями: Кабель занимает 12 UTF-8-байт, хотя title объявлен VARCHAR(120), а note хранит NULL и пустую строку раздельно.
- Схема: title VARCHAR(120), qty INT NOT NULL, note VARCHAR(160) nullable
- Данные 1: Кабель / 0 / NULL; данные 2: пустое название / 7 / пустая строка
- field_len и flags описывают хранение; strlen измеряет конкретное PHP-значение в байтах
- Правило публикации: непустое название и остаток не меньше нуля
- Первая карточка принята с 0; вторая остаётся черновиком из-за названия
Самый простой вызов и его объяснение
$flags = cubrid_field_flags($request, 3);
if (!is_string($flags)) { throw new RuntimeException("Нет флагов"); }
$notNull = in_array("not_null", explode(" ", $flags), true);
echo $notNull ? "SQL NULL запрещён" : "SQL NULL допустим";Флаги возвращаются строкой с разделителем-пробелом, не битовой маской. explode делит её на отдельные слова, in_array проверяет конкретное имя. not_null запрещает SQL NULL, но сам по себе не запрещает числовой 0 или пустую текстовую строку. Правило «название должно быть непустым при публикации» формулируется приложением отдельно.
Видимый результат самостоятельной программы
| Наблюдение | Результат |
|---|---|
| Карточка 1 | Кабель / остаток 0 |
| Название: ширина по field_len | 120 |
| Кабель: фактические байты UTF-8 | 12 |
| qty: типовая ширина | 11 |
| qty: NOT NULL | да |
| Карточку с остатком 0 можно опубликовать | да |
| Пустое название второй карточки допускает публикацию | нет |
| note: NOT NULL | нет |
| Примечание первой карточки | SQL NULL |
| Примечание второй карточки | Пустая строка |
Полная программа, файлы и архив для запуска
<?php
declare(strict_types=1);
require __DIR__.'/lab.php';
$db=null;$owned=$removed=$rows=$checks=$observations=[];
try {
$config=c167Config();$db=c167Connect();$runtime=c167Runtime($db);
$name=c167CreateTable($db,$owned,'fieldpolicy',[
['id'=>1,'sku'=>'CAB-167','title'=>'Кабель','category'=>'electric','price_cents'=>12900,'qty'=>0,'note'=>null],
['id'=>2,'sku'=>'EMPTY-167','title'=>'','category'=>'draft','price_cents'=>900,'qty'=>7,'note'=>'']
]);$table=c167Qualified($name);
$request=cubrid_execute($db,'SELECT id,sku,title,qty,note FROM '.$table.' ORDER BY id LIMIT 2');
if($request===false){c167Failure('Правила карточки не выбраны');}
try {
$titleField=cubrid_fetch_field($request,2);$qtyField=cubrid_fetch_field($request,3);$noteField=cubrid_fetch_field($request,4);
$titleLimit=cubrid_field_len($request,2);$qtyWidth=cubrid_field_len($request,3);$noteLimit=cubrid_field_len($request,4);
$qtyFlags=cubrid_field_flags($request,3);$noteFlags=cubrid_field_flags($request,4);
if($titleField===false||$qtyField===false||$noteField===false||!is_int($titleLimit)||!is_int($qtyWidth)||!is_int($noteLimit)||!is_string($qtyFlags)||!is_string($noteFlags)){
throw new RuntimeException('Не получены метаданные формы.');
}
$first=cubrid_fetch_assoc($request);$second=cubrid_fetch_assoc($request);
if(!is_array($first)||!is_array($second)){throw new RuntimeException('Ожидались две карточки.');}
} finally {c167Release($request);}
// Политика публикации задаётся отдельно от разрешённого SQL NULL.
$firstPublishable=is_string($first['title'])&&trim($first['title'])!==''&&(int)$first['qty']>=0;
$secondPublishable=is_string($second['title'])&&trim($second['title'])!==''&&(int)$second['qty']>=0;
$rows=[['Карточка 1',$first['title'].' / остаток '.$first['qty']],['Название: ширина по field_len',$titleLimit],
['Кабель: фактические байты UTF-8',strlen($first['title'])],['qty: типовая ширина',$qtyWidth],
['qty: NOT NULL',in_array('not_null',explode(' ',$qtyFlags),true)],['Карточку с остатком 0 можно опубликовать',$firstPublishable],
['Пустое название второй карточки допускает публикацию',$secondPublishable],
['note: NOT NULL',in_array('not_null',explode(' ',$noteFlags),true)],
['Примечание первой карточки',$first['note']===null?'SQL NULL':'Неожиданное значение'],
['Примечание второй карточки',$second['note']===''?'Пустая строка':'Неожиданное значение']];
$checks=['actual_first'=>$first['title']==='Кабель'&&$first['qty']==='0','declared_title_width'=>$titleLimit===120,
'utf8_bytes_not_width'=>strlen($first['title'])===12,'integer_display_width'=>$qtyWidth===11,
'note_width'=>$noteLimit===160,'quantity_required'=>in_array('not_null',explode(' ',$qtyFlags),true),
'nullable_note'=>!in_array('not_null',explode(' ',$noteFlags),true),
'zero_is_accepted'=>$firstPublishable,'blank_name_rejected'=>!$secondPublishable,
'null_and_empty_differ'=>$first['note']===null&&$second['note']==='',
'metadata_not_publish_rule'=>$titleField->not_null===0&&$second['title']==='',
'request_closed'=>$request===null];
$observations=['fields'=>['title'=>get_object_vars($titleField),'qty'=>get_object_vars($qtyField),'note'=>get_object_vars($noteField)],
'declared_widths'=>['title'=>$titleLimit,'qty'=>$qtyWidth,'note'=>$noteLimit],
'rows'=>[$first,$second],'publication_policy'=>['title'=>'non-blank','qty'=>'non-negative INT','note'=>'optional'],
'accepted'=>[$firstPublishable,$secondPublishable],'data_modified'=>false];
} finally {
if (is_resource($db)) {try {$removed=c167Cleanup($db,$owned);} finally {c167Close($db);}}
}
c167Report('cub167-field-policy','Сопоставить подсказки схемы с правилами заполнения карточки',$rows,$checks,$observations,$runtime,$owned,$removed);
Ожидаемый результат
Карточка 1 — Кабель / остаток 0
Название: ширина по field_len — 120
Кабель: фактические байты UTF-8 — 12
qty: типовая ширина — 11
qty: NOT NULL — да
Карточку с остатком 0 можно опубликовать — да
Пустое название второй карточки допускает публикацию — нет
note: NOT NULL — нет
Примечание первой карточки — SQL NULL
Примечание второй карточки — Пустая строка
Распакуйте архив целиком и запустите example.php по README.txt в отдельной CUBRID-лаборатории. lab.php проверяет маркер namespace/базы, создаёт только свою случайную c167-таблицу и удаляет её в finally. result.html показывает значения, result.json — метаданные и наблюдения, metrics.json — проверки и очистку. Реквизиты подключения остаются в закрытом окружении.
Открыть фактический результат · Открыть данные JSON.
Границы и ошибки
field_len не даёт длину текущей карточки и не задаёт допустимый диапазон количества. Для INT значение 11 — типовая текстовая ширина драйвера, а не «от 0 до 11» и не 11 байт хранения. Не используйте fetch_field.max_length как maxlength HTML: в этом профиле он равен 0. Длина VARCHAR выражается в символах схемы, strlen PHP — в байтах; для многоязычного ввода нужна осознанная проверка символов. Пример проверяет уже прочитанный INT, а не подменяет полноценную валидацию входной формы простым cast.
В импортированных данных примечание допускает NULL, но при отправке формы его хотели сделать обязательным. Исходное обсуждение. Здесь показаны отдельно допустимое хранение черновика и правило публикации. Код ASP.NET, аннотации и выводы о SQL Server не копируются; решение сформулировано для собственной PHP-карточки.
Измените требование
Если редактор обязан заполнить примечание именно перед публикацией, нужно ли считать старые SQL NULL ошибкой чтения?
Разбор решения
Нет. Прочитайте старое значение как null и покажите незаполненное поле. Отдельно задайте требование непустого примечания для команды публикации. Разрешённое хранение черновика и требования конкретного действия не обязаны совпадать; флаг nullable не выбирает эту политику автоматически.
Перечитать описание колонок, не перематывая товары
Компонент отчёта уже прочитал первую карточку, затем ему понадобилось повторно вывести заголовок второго столбца. Перемещение указателя полей не должно возвращать товары к началу. Программа показывает два независимых движения: описания sku/title/qty и товарные строки Кабель/Клемма; у пустой выборки заголовки тоже сохраняются.
- Товарный курсор: первая строка Кабель уже прочитана
- Указатель полей: fetch_field → sku, затем title
- field_seek(2) → следующее описание qty; конец списка false без ошибки
- Явный fetch_field(0) → sku, следующее неявное → title
- Товарный курсор не перемещался: следующая строка Клемма; пустая выборка всё ещё описывает 3 поля
Самый простой вызов и его объяснение
if (!cubrid_field_seek($request, 1)) {
throw new RuntimeException("Нет второго поля");
}
$field = cubrid_fetch_field($request);
if ($field === false) { throw new RuntimeException("Описание не прочитано"); }
echo $field->name; // titlefield_seek меняет позицию для следующего fetch_field без второго аргумента. Это указатель описаний колонок, не позиция товарной строки. Явный fetch_field(request,0) тоже меняет следующую позицию на 1. Когда нужны независимые потребители метаданных, удобнее один раз сохранить описания в PHP-массив либо согласовать владение указателем.
Видимый результат самостоятельной программы
| Наблюдение | Результат |
|---|---|
| Первая карточка | Кабель |
| Первые описания | sku / title |
| После field_seek(2) | qty |
| Конец описаний без ошибки | да |
| После явного fetch_field(0), затем следующего | sku / title |
| Следующая товарная карточка | Клемма |
| Индекс 3 отклонён | да |
| Поля пустой выборки | 3 |
| Второе поле пустой выборки | title |
Полная программа, файлы и архив для запуска
<?php
declare(strict_types=1);
require __DIR__.'/lab.php';
$db=null;$owned=$removed=$rows=$checks=$observations=[];
try {
$config=c167Config();$db=c167Connect();$runtime=c167Runtime($db);
$name=c167CreateTable($db,$owned,'fieldcursor',[
['id'=>1,'sku'=>'CAB-167','title'=>'Кабель','category'=>'electric','price_cents'=>12900,'qty'=>0,'note'=>null],
['id'=>2,'sku'=>'CLP-167','title'=>'Клемма','category'=>'electric','price_cents'=>900,'qty'=>7,'note'=>'']
]);$table=c167Qualified($name);
$request=cubrid_execute($db,'SELECT sku,title,qty FROM '.$table.' ORDER BY id LIMIT 2');
if($request===false){c167Failure('Страница не выбрана');}
try {
$firstRow=cubrid_fetch_assoc($request);
if(!is_array($firstRow)){throw new RuntimeException('Нет первой карточки.');}
$firstField=cubrid_fetch_field($request);$secondField=cubrid_fetch_field($request);
if($firstField===false||$secondField===false){throw new RuntimeException('Нет первых описаний.');}
if(cubrid_field_seek($request,2)!==true){c167Failure('Переход к qty не выполнен');}
$thirdField=cubrid_fetch_field($request);
if($thirdField===false){throw new RuntimeException('Нет описания qty.');}
$end=cubrid_fetch_field($request);$endCode=cubrid_error_code();
if($end!==false||$endCode!==0){throw new RuntimeException('Неожиданный конец описаний.');}
$explicitFirst=cubrid_fetch_field($request,0);
$afterExplicit=cubrid_fetch_field($request);
if($explicitFirst===false||$afterExplicit===false){throw new RuntimeException('Повторное описание не прочитано.');}
$secondRow=cubrid_fetch_assoc($request);
if(!is_array($secondRow)){throw new RuntimeException('Нет второй карточки.');}
$invalid=c167Capture(static function() use($request){return cubrid_field_seek($request,3);});
if($invalid['value']!==false){throw new RuntimeException('Несуществующее поле не отклонено.');}
if(cubrid_field_seek($request,0)!==true){throw new RuntimeException('Указатель полей не восстановлен.');}
} finally {c167Release($request);}
$emptyRequest=cubrid_execute($db,'SELECT sku,title,qty FROM '.$table.' WHERE id<0 ORDER BY id LIMIT 2');
if($emptyRequest===false){c167Failure('Пустая выборка не выполнена');}
try {
$emptyCount=cubrid_num_fields($emptyRequest);
if(cubrid_field_seek($emptyRequest,1)!==true){throw new RuntimeException('Нет второго поля пустой выборки.');}
$emptyField=cubrid_fetch_field($emptyRequest);
$emptyRow=cubrid_fetch_assoc($emptyRequest);$emptyCode=cubrid_error_code();
if($emptyField===false||$emptyRow!==false||$emptyCode!==0){throw new RuntimeException('Пустая выборка прочитана неверно.');}
} finally {c167Release($emptyRequest);}
$rows=[['Первая карточка',$firstRow['title']],['Первые описания',$firstField->name.' / '.$secondField->name],
['После field_seek(2)',$thirdField->name],['Конец описаний без ошибки',$end===false&&$endCode===0],
['После явного fetch_field(0), затем следующего',$explicitFirst->name.' / '.$afterExplicit->name],
['Следующая товарная карточка',$secondRow['title']],['Индекс 3 отклонён',$invalid['value']===false],
['Поля пустой выборки',$emptyCount],['Второе поле пустой выборки',$emptyField->name]];
$checks=['first_row'=>$firstRow['title']==='Кабель','initial_fields'=>[$firstField->name,$secondField->name]===['sku','title'],
'seek_targets_qty'=>$thirdField->name==='qty','metadata_end'=>$end===false&&$endCode===0,
'explicit_advances_pointer'=>[$explicitFirst->name,$afterExplicit->name]===['sku','title'],
'row_pointer_independent'=>$secondRow['title']==='Клемма','invalid_offset_rejected'=>$invalid['value']===false&&$invalid['code']!==0&&$invalid['warning'],
'empty_schema_retained'=>$emptyCount===3&&$emptyField->name==='title','empty_no_rows'=>$emptyRow===false&&$emptyCode===0,
'requests_closed'=>$request===null&&$emptyRequest===null];
$observations=['first_row'=>$firstRow,'second_row'=>$secondRow,
'metadata_sequence'=>[$firstField->name,$secondField->name,$thirdField->name],
'explicit_then_implicit'=>[$explicitFirst->name,$afterExplicit->name],
'invalid_offset'=>['value'=>$invalid['value'],'code'=>$invalid['code'],'facility'=>$invalid['facility'],'warning'=>$invalid['warning'],'message_present'=>$invalid['message_present']],
'empty'=>['fields'=>$emptyCount,'field'=>get_object_vars($emptyField),'row'=>$emptyRow],
'row_seek_calls'=>0];
} finally {
if (is_resource($db)) {try {$removed=c167Cleanup($db,$owned);} finally {c167Close($db);}}
}
c167Report('cub167-field-cursor','Перечитать описание колонок, не перематывая товары',$rows,$checks,$observations,$runtime,$owned,$removed);
Ожидаемый результат
Первая карточка — Кабель
Первые описания — sku / title
После field_seek(2) — qty
Конец описаний без ошибки — да
После явного fetch_field(0), затем следующего — sku / title
Следующая товарная карточка — Клемма
Индекс 3 отклонён — да
Поля пустой выборки — 3
Второе поле пустой выборки — title
Распакуйте архив целиком и запустите example.php по README.txt в отдельной CUBRID-лаборатории. lab.php проверяет маркер namespace/базы, создаёт только свою случайную c167-таблицу и удаляет её в finally. result.html показывает значения, result.json — метаданные и наблюдения, metrics.json — проверки и очистку. Реквизиты подключения остаются в закрытом окружении.
Открыть фактический результат · Открыть данные JSON.
Границы и ошибки
Допустимые позиции — от 0 до num_fields - 1. Явный недопустимый индекс вызывает отказ и предупреждение; программа перехватывает его, сохраняет диагностику и возвращает указатель к 0. Обычный конец последовательного списка без индекса также false, но без ошибки. Не используйте field_seek для пагинации строк и не вызывайте его на закрытом ресурсе. Для строк предназначены другие функции, рассмотренные в соседней главе.
Измените требование
После получения всех описаний вызывается field_seek(request) без индекса. Что вернёт следующий fetch_field, и какая товарная строка будет прочитана после него?
Разбор решения
field_seek по умолчанию ставит указатель полей на 0, поэтому fetch_field вернёт описание sku. Позиция товарного курсора не меняется: следующий fetch строки продолжит прежнее чтение. Если сами товары уже закончились, метаданные не создадут новую строку.
Восемь функций описания выбранных полей
| Функция | Задача |
|---|---|
| cubrid_fetch_field | Получить объект описания одного поля и понимать ограничения его свойств. |
| cubrid_field_flags | Прочитать признаки ограничения и индекса, не подменяя ими правила приложения. |
| cubrid_field_len | Узнать типовую ширину поля отдельно от длины конкретного значения. |
| cubrid_field_name | Прочитать имя или псевдоним выбранной позиции SELECT. |
| cubrid_field_seek | Выбрать следующее описание колонки без перемещения товарных строк. |
| cubrid_field_table | Посмотреть доступное происхождение поля и отличить его от выражения. |
| cubrid_field_type | Узнать SQL-тип конкретного поля для понятного описания или формата. |
| cubrid_num_fields | Посчитать поля результата и безопасно ограничить обход метаданных. |
Использовать метаданные как описание, а правила задавать явно
Описывайте ровно те поля, которые действительно нужны текущему экрану или файлу. Имена и типы помогают согласовать формат, но не восстанавливают автоматически полную схему, исходный SQL или правила бизнеса. Отдельно определяйте допустимые правки, обязательность данных конкретного действия и поведение при отсутствующих значениях.
Следующий шаг — связать выбранное представление с чтением и позициями строк, параметрами фильтра и границей сохранения изменений. Указатель метаданных не отменяет и не фиксирует записи; закрытие request и connection также остаётся отдельной частью владения ресурсами.
Функции и методы этой темы
Откройте карточку, чтобы увидеть договор функции, примеры, ограничения и связанные инструменты.
cubrid_fetch_fieldПолучить объект описания одного поля и понимать ограничения его свойств.
PECL CUBRID >= 8.3.1; профиль PHP согласуется отдельно. · cubrid
cubrid_fetch_field(resource $result, int $field_offset = 0): object|falseПолучить объект описания одного поля и понимать ограничения его свойств.
Базовая запись
cubrid_fetch_field(resource $result, int $field_offset = 0): object|falseСигнатура справочная, не исполняемая строка PHP 7.4. resource — request запроса native cubrid; | перечисляет возможные результаты. Функция доступна с PECL CUBRID 8.3.1. Это версия расширения, не требование установить PHP 8.3.1. Отдельный лабораторный профиль и запуск приведены в README полных программ.
| Параметр | Что передать |
|---|---|
| result | Живой request успешно выполненного SELECT; в документации это результат execute, а для num_fields также query/prepare. Это не connection и не прочитанный массив товара. |
| field_offset = 0 | Индекс выбранного поля, начиная с 0. Для трёх полей допустимы 0, 1 и 2. Индекс вне диапазона вызывает предупреждение и отказ; проверяйте количество до обращения. |
| Возврат | Как понимать |
|---|---|
| object | Описание одной колонки. Стрелка -> обращается к его свойствам, не к значениям товарной строки. |
| false | Отказ либо конец последовательного обхода без явного индекса. Отличайте эти случаи по контексту и немедленной диагностике. |
Несмотря на запись = 0 в краткой сигнатуре, пропуск аргумента имеет отдельный смысл: берётся следующее ещё не полученное поле. Явный индекс 0 выбирает первое поле и в закреплённом драйвере устанавливает следующую позицию на 1. Не считайте пропуск аргумента неизменным повтором первого столбца.
| Свойство | Официальный смысл и граница закреплённого профиля |
|---|---|
| name | Имя поля результата, включая AS. Отдельного orgname здесь нет. |
| table | Имя таблицы, к которой относится поле; для вычисления может быть пустой строкой. |
| def | Представление значения по умолчанию, а не значение текущей строки. При подготовке встречались строки "0", "1.25", "'ready'", "NULL", пустая строка и null. Не исполняйте это содержимое как PHP/SQL. |
| max_length | По документации максимальная длина. В исходнике 11.2.0.0002 установлено 0 без вычисления: для ограничения ввода это свойство ненадёжно. |
| not_null | 1 означает сообщённый запрет SQL NULL; 0 не заменяет проверку бизнес-требований. |
| primary_key | Сообщённый признак первичного ключа. Метаданные результата с псевдонимом могут не сохранить сведения исходного ограничения. |
| unique_key | Сообщённый признак уникального ключа; в проекте у обычного sku наблюдается 1. |
| multiple_key | По описанию признак неуникального ключа. Здесь вычисляется как !unique_key, поэтому 1 не доказывает существование индекса. |
| numeric | 1 для числового SQL-типа. Это не гарантия PHP-int или допустимости любого числового ввода. |
| blob | 1 для BLOB. Не является содержимым BLOB или размером файла. |
| type | Строка SQL-типа по классификации драйвера, например varchar или integer. |
| unsigned | Официальное свойство беззнаковости; этот драйвер всегда выставляет 0. CUBRID не поддерживает UNSIGNED как тип числовой колонки. |
| zerofill | Официальное свойство заполнения нулями; в данной реализации всегда 0, не правило отображения артикула. |
Применение 1: подсказка по выбранной колонке
$field = cubrid_fetch_field($request, 1);
if ($field === false) { throw new RuntimeException('Нет описания поля'); }
echo htmlspecialchars($field->name, ENT_QUOTES, 'UTF-8');
echo ' / ', htmlspecialchars($field->type, ENT_QUOTES, 'UTF-8');Для SELECT sku,title,qty получится title / varchar. Полный паспорт экспорта добавляет отдельную field_len=120 и реальную строку Кабель / 0. Объект метаданных не читается вместо товара: за товаром обращаются отдельным fetch строки.
Применение 2: сохранить описания для повторного заголовка
$count = cubrid_num_fields($request);
if ($count === false || $count < 0) { throw new RuntimeException('Нет количества полей'); }
$fields = [];
for ($i = 0; $i < $count; $i++) {
$field = cubrid_fetch_field($request, $i);
if ($field === false) { throw new RuntimeException('Нет описания'); }
$fields[] = get_object_vars($field);
}Сохранённый массив можно использовать в шапке таблицы и в диагностике формата без борьбы двух компонентов за общий указатель метаданных. Пример указателя демонстрирует, что явный и неявный fetch_field связаны, а товарный курсор независим. Обычный конец списка даёт false без ошибки, неверный явный индекс — false с предупреждением.
Не восстанавливайте полную схему базы из этого объекта. В подготовке SELECT id AS item_id сохранил not_null, но не выдал primary_key/unique_key, хотя исходный id был PRIMARY KEY. Наличие полезных метаданных не означает полноту DDL. Для правил ввода используйте явную политику приложения, для полной схемы — соответствующий каталог базы. Рядом cubrid_field_len, cubrid_field_flags и cubrid_field_seek.
cubrid_field_flagsПрочитать признаки ограничения и индекса, не подменяя ими правила приложения.
PECL CUBRID >= 8.3.0; профиль PHP согласуется отдельно. · cubrid
cubrid_field_flags(resource $result, int $field_offset): string|int|falseПрочитать признаки ограничения и индекса, не подменяя ими правила приложения.
Базовая запись
cubrid_field_flags(resource $result, int $field_offset): string|int|falseСигнатура справочная, не исполняемая строка PHP 7.4. resource — request запроса native cubrid; | перечисляет возможные результаты. Функция доступна с PECL CUBRID 8.3.0. Это версия расширения, не требование установить PHP 8.3.0. Отдельный лабораторный профиль и запуск приведены в README полных программ.
| Параметр | Что передать |
|---|---|
| result | Живой request успешно выполненного SELECT; в документации это результат execute, а для num_fields также query/prepare. Это не connection и не прочитанный массив товара. |
| field_offset | Индекс выбранного поля, начиная с 0. Для трёх полей допустимы 0, 1 и 2. Индекс вне диапазона вызывает предупреждение и отказ; проверяйте количество до обращения. |
| Возврат | Как понимать |
|---|---|
| string | Имена флагов через пробел. Пустая строка — допустимое отсутствие сообщённых флагов. |
| false | Недопустимый индекс, с предупреждением. |
| -1 | Документированный результат для не-SELECT; это не пустой набор флагов. Проверка индекса может завершиться раньше проверки типа SQL. |
| Флаг | Что он описывает |
|---|---|
| not_null | Запрет SQL NULL. |
| primary_key | Первичный ключ. |
| unique_key | Уникальный ключ. |
| foreign_key | Внешний ключ. |
| auto_increment | Автоматическое получение нового значения. |
| shared | Разделяемый атрибут. |
| reverse_index | Обратный индекс. |
| reverse_unique | Обратный уникальный индекс. |
| timestamp | SQL-тип TIMESTAMP. |
Применение 1: подсказка редактору об обязательности хранения
$flags = cubrid_field_flags($request, 3); // qty в выбранном списке
if (!is_string($flags)) { throw new RuntimeException('Флаги не прочитаны'); }
$tokens = $flags === '' ? [] : explode(' ', $flags);
$notNull = in_array('not_null', $tokens, true);
echo $notNull ? 'SQL NULL запрещён' : 'SQL NULL допустим';В правилах карточки qty имеет NOT NULL, но 0 принимается. Пустое название отсекается отдельным требованием публикации, хотя схема хранения позволяет черновик. Флаг не превращает HTML required в полную серверную проверку и не определяет права редактирования.
Применение 2: показать ограничение артикула в паспорте обмена
$flags = cubrid_field_flags($request, 0); // sku
if (!is_string($flags)) { throw new RuntimeException('Нет описания sku'); }
$isUnique = in_array('unique_key', explode(' ', $flags), true);
echo $isUnique ? 'Повтор артикула ограничен схемой' : 'Признак не сообщён';Паспорт экспорта получает unique_key для обычного sku. Это полезная подсказка до импорта, но фактическая вставка всё равно проверяет результат ограничения. Из отсутствия флага нельзя выводить отсутствие ограничения у исходной таблицы: AS/выражения и способ получения метаданных имеют значение.
Это строковые слова, а не числа для побитового &. Порядок слов не должен быть бизнес-условием: ищите отдельный токен. При отказе сначала сохраните код и сообщение, затем закрывайте request. Для nullable/ключей объекта cubrid_fetch_field отдельно учтите известные ограничения primary_key/multiple_key. Флаги не заменяют сведения CHECK, список разрешённых статусов, диапазон остатков или защиту от параллельных изменений.
cubrid_field_lenУзнать типовую ширину поля отдельно от длины конкретного значения.
PECL CUBRID >= 8.3.0; профиль PHP согласуется отдельно. · cubrid
cubrid_field_len(resource $result, int $field_offset): int|falseУзнать типовую ширину поля отдельно от длины конкретного значения.
Базовая запись
cubrid_field_len(resource $result, int $field_offset): int|falseСигнатура справочная, не исполняемая строка PHP 7.4. resource — request запроса native cubrid; | перечисляет возможные результаты. Функция доступна с PECL CUBRID 8.3.0. Это версия расширения, не требование установить PHP 8.3.0. Отдельный лабораторный профиль и запуск приведены в README полных программ.
| Параметр | Что передать |
|---|---|
| result | Живой request успешно выполненного SELECT; в документации это результат execute, а для num_fields также query/prepare. Это не connection и не прочитанный массив товара. |
| field_offset | Индекс выбранного поля, начиная с 0. Для трёх полей допустимы 0, 1 и 2. Индекс вне диапазона вызывает предупреждение и отказ; проверяйте количество до обращения. |
| Возврат | Как понимать |
|---|---|
| int | Максимальная/типовая ширина выбранного поля по данным драйвера; единица зависит от SQL-типа. |
| false | Не удалось получить ширину, в частности при неверном индексе с предупреждением. |
Для VARCHAR драйвер берёт precision описания: в нашей схеме title даёт 120. Для INT используется типовая текстовая ширина 11, хотя сам INTEGER хранится в 4 байтах и имеет собственный диапазон. Для NUMERIC закреплённая реализация прибавляет 2 к precision на знак и разделитель; в подготовке NUMERIC(10,2) дал 12. Для коллекционных типов используется внутренняя граница представления набора. Поэтому число нельзя всегда называть байтами памяти либо максимальным допустимым значением.
Применение 1: описать ожидаемую ширину экспортного поля
$name = cubrid_field_name($request, 1);
$type = cubrid_field_type($request, 1);
$width = cubrid_field_len($request, 1);
if (!is_string($name) || !is_string($type) || $width === false) {
throw new RuntimeException('Нет описания ширины');
}
echo $name, ' / ', $type, ' / ', $width; // title / varchar / 120Такой паспорт помогает согласовать поле с принимающей системой. Он не доказывает, что все текущие названия имеют 120 знаков. Самостоятельный пример показывает отдельные значения артикула, названия и нулевого остатка рядом с описанием.
Применение 2: разобрать расхождение ширины и реальных байтов
$declaredWidth = cubrid_field_len($request, 2); // title
$row = cubrid_fetch_assoc($request);
if ($declaredWidth === false || !is_array($row)) {
throw new RuntimeException('Нет названия или описания');
}
echo 'Ширина поля: ', $declaredWidth, "\n";
echo 'Байты значения: ', strlen($row['title']), "\n";В сценарии карточки выход — 120 и 12 для слова Кабель. VARCHAR задаёт символьную вместимость схемы; strlen PHP измеряет байты конкретной строки UTF-8. Для длины текущих полученных полей также существует cubrid_fetch_lengths. Не делите любое число метаданных на 2, 3 или 4 ради угаданной кодировки.
Не устанавливайте qty <= field_len(qty): 11 не является ограничением количества товаров. Не переносите значение в HTML maxlength без понимания типа и символьной проверки; диапазоны и требования задаются отдельно. Свойство fetch_field.max_length в этом драйвере имеет другое фактическое поведение — всегда 0 — и не заменяет функцию. Для полного паспорта используйте cubrid_field_type вместе с описанием схемы.
cubrid_field_nameПрочитать имя или псевдоним выбранной позиции SELECT.
PECL CUBRID >= 8.3.0; профиль PHP согласуется отдельно. · cubrid
cubrid_field_name(resource $result, int $field_offset): string|falseПрочитать имя или псевдоним выбранной позиции SELECT.
Базовая запись
cubrid_field_name(resource $result, int $field_offset): string|falseСигнатура справочная, не исполняемая строка PHP 7.4. resource — request запроса native cubrid; | перечисляет возможные результаты. Функция доступна с PECL CUBRID 8.3.0. Это версия расширения, не требование установить PHP 8.3.0. Отдельный лабораторный профиль и запуск приведены в README полных программ.
| Параметр | Что передать |
|---|---|
| result | Живой request успешно выполненного SELECT; в документации это результат execute, а для num_fields также query/prepare. Это не connection и не прочитанный массив товара. |
| field_offset | Индекс выбранного поля, начиная с 0. Для трёх полей допустимы 0, 1 и 2. Индекс вне диапазона вызывает предупреждение и отказ; проверяйте количество до обращения. |
| Возврат | Как понимать |
|---|---|
| string | Имя поля по выбранной позиции SELECT, включая псевдоним AS. |
| false | Официально описанный отказ, в частности неверный индекс с предупреждением. |
Применение 1: заголовки конкретной выгрузки
$count = cubrid_num_fields($request);
if ($count === false || $count < 0) { throw new RuntimeException('Нет полей'); }
$headers = [];
for ($i = 0; $i < $count; $i++) {
$name = cubrid_field_name($request, $i);
if (!is_string($name)) { throw new RuntimeException('Имя не прочитано'); }
$headers[] = $name;
}В каталоге полей это sku, title, qty в порядке будущей записи. Индекс относится к списку SELECT, а не к постоянному номеру колонки в CREATE TABLE. Перестановка SELECT меняет эти позиции. Для всех имён сразу можно использовать cubrid_column_names.
Применение 2: согласовать псевдоним с PHP-шаблоном
// SELECT title AS display_title, qty AS available FROM products ...
$label = cubrid_field_name($request, 0);
if ($label !== 'display_title') {
throw new RuntimeException('Формат карточки изменился');
}
$item = cubrid_fetch_assoc($request);
if (!is_array($item)) { throw new RuntimeException('Нет карточки'); }
echo htmlspecialchars($item[$label], ENT_QUOTES, 'UTF-8');Происхождение полей показывает display_title со значением Кабель и отдельно известное приложению исходное имя title. Функция не сообщает mysqli orgname и не разбирает SQL обратно. У выражения имя может быть его AS; поэтому читабельные уникальные псевдонимы лучше неоднозначных ключей JOIN.
Метаданные не делают произвольные имена от посетителя безопасными SQL-идентификаторами. Структуру запроса выбирают по разрешённой карте, значения связывают через bind. В исходнике 11.2.0.0002 также имеется ветка -1 для не-SELECT после проверки индекса, хотя краткий раздел возвратов страницы перечисляет только string/false. Мы проверяем is_string и применяем функцию к известному SELECT, не к UPDATE или закрытому request.
cubrid_field_seekВыбрать следующее описание колонки без перемещения товарных строк.
PECL CUBRID >= 8.3.0; профиль PHP согласуется отдельно. · cubrid
cubrid_field_seek(resource $result, int $field_offset = 0): boolВыбрать следующее описание колонки без перемещения товарных строк.
Базовая запись
cubrid_field_seek(resource $result, int $field_offset = 0): boolСигнатура справочная, не исполняемая строка PHP 7.4. resource — request запроса native cubrid; | перечисляет возможные результаты. Функция доступна с PECL CUBRID 8.3.0. Это версия расширения, не требование установить PHP 8.3.0. Отдельный лабораторный профиль и запуск приведены в README полных программ.
| Параметр | Что передать |
|---|---|
| result | Живой request успешно выполненного SELECT; в документации это результат execute, а для num_fields также query/prepare. Это не connection и не прочитанный массив товара. |
| field_offset = 0 | Индекс выбранного поля, начиная с 0. Для трёх полей допустимы 0, 1 и 2. Индекс вне диапазона вызывает предупреждение и отказ; проверяйте количество до обращения. |
| Возврат | Как понимать |
|---|---|
| true | Следующий неявный fetch_field будет читать указанную колонку. |
| false | Переход не выполнен; недопустимый индекс сопровождается предупреждением. |
Меняется указатель описаний полей. Товарные строки не перемещаются. Значение по умолчанию 0 возвращает описание к первому полю. Для трёх колонок индекс 3 уже недопустим, даже если в таблице тысячи товарных строк.
Применение 1: подсказка по выбранному столбцу
if (cubrid_field_seek($request, 1) !== true) {
throw new RuntimeException('Второго поля нет');
}
$field = cubrid_fetch_field($request);
if ($field === false) { throw new RuntimeException('Описание не прочитано'); }
echo $field->name; // title для SELECT sku,title,qtyВ полном сценарии после перехода к позиции 2 получается qty. Это полезно, когда компонент показывает справку по выбранной пользователем колонке: индекс предварительно сверяется с разрешённым диапазоном num_fields.
Применение 2: повторный заголовок после обхода данных
if (cubrid_field_seek($request) !== true) {
throw new RuntimeException('Нет начального поля');
}
$first = cubrid_fetch_field($request);
if ($first === false) { throw new RuntimeException('Нет описания'); }
// first описывает sku; товарный курсор остаётся на прежнем месте.Программа читает Кабель, работает с описаниями, затем читает Клемму. Это подтверждает независимость указателей. У пустого SELECT также можно прочитать описание title: отсутствие товаров не означает отсутствие колонок. Для перемещения строк используйте cubrid_data_seek или cubrid_move_cursor, учитывая их собственные правила.
Явный fetch_field(request,0) сам меняет следующий индекс на 1. Если несколько функций должны независимо перечитывать описания, сохраните их один раз в PHP-массив или передавайте владение request явно. Ошибочный offset в примере даёт false с кодом -20013/facility3, затем допустимый seek восстанавливает позицию. Проверять закрытый ресурс таким вызовом не требуется и небезопасно для старого расширения.
cubrid_field_tableПосмотреть доступное происхождение поля и отличить его от выражения.
PECL CUBRID >= 8.3.0; профиль PHP согласуется отдельно. · cubrid
cubrid_field_table(resource $result, int $field_offset): string|int|falseПосмотреть доступное происхождение поля и отличить его от выражения.
Базовая запись
cubrid_field_table(resource $result, int $field_offset): string|int|falseСигнатура справочная, не исполняемая строка PHP 7.4. resource — request запроса native cubrid; | перечисляет возможные результаты. Функция доступна с PECL CUBRID 8.3.0. Это версия расширения, не требование установить PHP 8.3.0. Отдельный лабораторный профиль и запуск приведены в README полных программ.
| Параметр | Что передать |
|---|---|
| result | Живой request успешно выполненного SELECT; в документации это результат execute, а для num_fields также query/prepare. Это не connection и не прочитанный массив товара. |
| field_offset | Индекс выбранного поля, начиная с 0. Для трёх полей допустимы 0, 1 и 2. Индекс вне диапазона вызывает предупреждение и отказ; проверяйте количество до обращения. |
| Возврат | Как понимать |
|---|---|
| string | Доступное имя исходной таблицы. В текущем профиле обычная колонка сообщает dba.<имя>; выражение может дать пустую строку. |
| false | Неверная позиция поля с предупреждением. |
| -1 | Официально описанный случай не-SELECT после проверки индекса. |
Применение 1: объяснить происхождение поля отчёта
$table = cubrid_field_table($request, 1);
$name = cubrid_field_name($request, 1);
if (!is_string($table) || !is_string($name)) {
throw new RuntimeException('Происхождение не прочитано');
}
echo htmlspecialchars($name, ENT_QUOTES, 'UTF-8'), ' / ';
echo $table === '' ? 'выражение без таблицы в метаданных'
: htmlspecialchars($table, ENT_QUOTES, 'UTF-8');В проекте редактора alias display_title по-прежнему связан с собственной таблицей, а вычисленная double_price не сообщает таблицу. Пользователь видит Кабель и 25800, а разработчик понимает, почему эти два поля нельзя автоматически редактировать одинаково.
Применение 2: диагностический перечень источников JOIN
$count = cubrid_num_fields($request);
if ($count === false || $count < 0) { throw new RuntimeException('Нет полей'); }
$sources = [];
for ($i = 0; $i < $count; $i++) {
$origin = cubrid_field_table($request, $i);
if (!is_string($origin)) { throw new RuntimeException('Нет источника'); }
$sources[$i] = $origin;
}Такой перечень помогает закрытому административному инструменту объяснить сложный SELECT. Он не превращается в автоматический UPDATE: две роли одной таблицы в self-JOIN могут сообщить одинаковое физическое имя, а вычисления и представления требуют отдельного договора. Для отображения берите cubrid_field_name, для разрешённых правок — собственную карту полей и права пользователя.
Пустой источник, false и -1 различаются строго. Имя базы/таблицы не является личным названием товара; на публичном экране обычно показывают подпись приложения, а технические имена оставляют диагностике. Совместимое имя функции с MySQL не гарантирует свойства orgtable/orgname из другого API. Ни table, ни flags не доказывают, что конкретный пользователь имеет право писать в исходную таблицу.
cubrid_field_typeУзнать SQL-тип конкретного поля для понятного описания или формата.
PECL CUBRID >= 8.3.0; профиль PHP согласуется отдельно. · cubrid
cubrid_field_type(resource $result, int $field_offset): string|int|falseУзнать SQL-тип конкретного поля для понятного описания или формата.
Базовая запись
cubrid_field_type(resource $result, int $field_offset): string|int|falseСигнатура справочная, не исполняемая строка PHP 7.4. resource — request запроса native cubrid; | перечисляет возможные результаты. Функция доступна с PECL CUBRID 8.3.0. Это версия расширения, не требование установить PHP 8.3.0. Отдельный лабораторный профиль и запуск приведены в README полных программ.
| Параметр | Что передать |
|---|---|
| result | Живой request успешно выполненного SELECT; в документации это результат execute, а для num_fields также query/prepare. Это не connection и не прочитанный массив товара. |
| field_offset | Индекс выбранного поля, начиная с 0. Для трёх полей допустимы 0, 1 и 2. Индекс вне диапазона вызывает предупреждение и отказ; проверяйте количество до обращения. |
| Возврат | Как понимать |
|---|---|
| string | SQL-тип выбранного поля, например varchar, integer или numeric. |
| false | Недопустимый индекс с предупреждением. |
| -1 | Документированная неподходящая SQL-команда, после проверки диапазона. |
Краткое описание PHP Manual приводит общие слова int/real/string, но его же пример и закреплённый type2str используют SQL-имена вроде char/varchar/integer. Выводите фактическую строку типа и сверяйте договор своего профиля. Это не gettype уже полученного PHP-значения и не команда преобразования.
Применение 1: описать числовое поле в паспорте
$type = cubrid_field_type($request, 2); // qty в SELECT sku,title,qty
if (!is_string($type)) { throw new RuntimeException('Нет SQL-типа'); }
echo 'Остаток хранится как ', $type; // integerПаспорт трёх полей показывает varchar для артикула и названия, integer для остатка. Товарная строка при этом возвращает qty как PHP-строку "0". Тип SQL позволяет осмысленно выбрать формат, но не оправдывает преобразование всех числоподобных артикулов в int.
Применение 2: проверить ожидаемый контракт цены
$type = cubrid_field_type($request, $pricePosition);
if ($type !== 'integer') {
throw new RuntimeException('В этом отчёте ожидается целая цена в копейках');
}
// Форматирование выбирается по согласованной модели денег, не по одному имени поля.В расчёте двойной цены источник price_cents и выражение умножения намеренно ограничены небольшими целыми копейками. Для DECIMAL/numeric нужно сохранить точность, а не механически перейти на float. Вычисление или CAST может дать тип, отличный от исходного поля; метаданные относятся к результату.
Закреплённый драйвер знает также smallint/bigint, float/double, monetary, date/time/timestamp/datetime, bit/varbit, nchar/varnchar, blob/clob, object, enum и коллекционные формы set/multiset/sequence. Само распознавание типа не реализует обработку LOB или коллекций за приложение. Длину интерпретируют вместе с типом через cubrid_field_len, а все типы сразу доступны через cubrid_column_types.
cubrid_num_fieldsПосчитать поля результата и безопасно ограничить обход метаданных.
PECL CUBRID >= 8.3.0; профиль PHP согласуется отдельно. · cubrid
cubrid_num_fields(resource $result): int|falseПосчитать поля результата и безопасно ограничить обход метаданных.
Базовая запись
cubrid_num_fields(resource $result): int|falseСигнатура справочная, не исполняемая строка PHP 7.4. resource — request запроса native cubrid; | перечисляет возможные результаты. Функция доступна с PECL CUBRID 8.3.0. Это версия расширения, не требование установить PHP 8.3.0. Отдельный лабораторный профиль и запуск приведены в README полных программ.
| Параметр | Что передать |
|---|---|
| result | Живой request успешно выполненного SELECT; в документации это результат execute, а для num_fields также query/prepare. Это не connection и не прочитанный массив товара. |
| Возврат | Как понимать |
|---|---|
| int, неотрицательный для SELECT | Количество полей данного результата. Не число товарных строк и не количество ключей BOTH. |
| -1 | SQL не SELECT; это отдельный отказ контекста, не минус одна колонка. |
| false | Получить число не удалось. |
Применение 1: ограничить обход паспорта полей
$count = cubrid_num_fields($request);
if ($count === false || $count < 0) {
throw new RuntimeException('Нет полей SELECT');
}
for ($i = 0; $i < $count; $i++) {
$name = cubrid_field_name($request, $i);
if (!is_string($name)) { throw new RuntimeException('Имя не прочитано'); }
echo $i, ': ', $name, "\n";
}Для экспортного списка выход содержит 0: sku, 1: title, 2: qty. Условие i < count не допускает лишнюю позицию 3. Если передали prepare, запрос должен относиться к корректному SELECT с доступным описанием; полный проект использует явно выполненный запрос.
Применение 2: сохранить структуру пустого экрана
$count = cubrid_num_fields($emptyRequest);
if ($count === false || $count < 0) {
throw new RuntimeException('Нет описания результата');
}
echo 'Столбцов в пустом списке: ', $count; // 3
// Отсутствие товарных строк проверяется отдельно через fetch или num_rows.Пустая выборка оставляет sku/title/qty доступными для заголовка, даже когда ни один id не подходит. Описание можно показать без фиктивной товарной строки. Указать ширину исходной таблицы 7 вместо выбранной ширины 3 было бы ошибкой.
Соседний cubrid_num_cols решает похожую задачу, но их ошибочные возвраты нельзя механически уравнивать: в закреплённом исходнике num_fields возвращает -1 для не-SELECT, num_cols — false. Оба результата необходимо проверять. Размер страницы относится к cubrid_num_rows, а число всех подходящих записей — к отдельному COUNT в SQL. Наличие полей не означает, что SELECT нашёл товары.
Источники и обсуждения
- PHP Manual: cubrid_fetch_field
- PHP Manual: cubrid_field_flags
- PHP Manual: cubrid_field_len
- PHP Manual: cubrid_field_name
- PHP Manual: cubrid_field_seek
- PHP Manual: cubrid_field_table
- PHP Manual: cubrid_field_type
- PHP Manual: cubrid_num_fields
- Native CUBRID 11.2.0.0002: реализация метаданных
- CUBRID: типы, ширины и точность
Код и руководство с собой
Скачайте самостоятельные примеры с исходными данными, инструкциями и ожидаемыми результатами. Примеры HTTP и фрагменты для проекта помечены отдельно: им нужно указанное окружение.
Код не исполняется на сайте. Скачайте нужный пример и запускайте его в своём локальном окружении.
Материалы сверены 2026-10-12. Примеры и объяснения написаны для этого руководства; источники и обсуждения доступны в каждой главе.


