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

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

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

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

Глава 108 · После первых SELECT и массива результата

Старый MySQL API: перенести метаданные полей и списки таблиц

Имена и aliases, типы и битовые флаги, символы и байты, курсор описаний, каталог пустой таблицы и видимость схемы. Двенадцать исторических контрактов с современными программами.

Данные, описание результата и каталог — три разных задачи

При переносе старого сайта мало заменить mysql_query на mysqli_query. Генератор CSV или редактор форм мог использовать описание колонок: имя, тип, ширину, ключи. Начнём с отчёта о кружке, у которого имя в таблице name, а заголовок результата product_name. Нужен понятный результат: данные остаются прежними, а код правильно отличает имя для вывода от структуры хранения.

УровеньЧто содержитКак читаем сейчас
Данные строки1, Кружка, 250.00fetch_row / fetch_assoc
Описание SELECTname=product_name, orgname=name, table=pfetch_field / fetch_fields
Схема таблицыVARCHAR(40), NOT NULL, PRIMARY KEYINFORMATION_SCHEMA / SHOW COLUMNS
Список объектовДоступные базы/таблицыSCHEMATA / TABLES / SHOW
Не смешиваем карту и содержимое
  1. Таблица хранит name=Кружка
  2. SELECT p.name AS product_name выбирает значение и даёт ему заголовок
  3. Metadata описывает заголовок и происхождение
  4. Fetch читает само значение Кружка

Метаданные — описание, похожее на подписи колонок в бланке; это не сами заполненные строки. Аналогия ограничена: вычисляемое выражение SELECT может не иметь единственного исходного столбца. Полезно знать массивы и таблицы, типы и связи, но смысл каждого обращения показан в малом фрагменте перед полной программой.

Как запустить современный пример и прочитать отчёт

Полные программы выполняются на PHP 8.2+ с mysqli/mysqlnd и отдельной локальной учебной базой MySQL 8.4/InnoDB. Контрольное окружение — PHP 8.5.11/MySQL 8.4.13. Устаревшее ext/mysql не устанавливается, PHP 5 не нужен. Начальную настройку см. в подключении PHP к MySQL.

Распакуйте архив, задайте PHPMAN_MYSQL_HOST, PHPMAN_MYSQL_PORT, PHPMAN_MYSQL_DATABASE, PHPMAN_MYSQL_USER, PHPMAN_MYSQL_PASSWORD в окружении своего терминала и выполните php example.php. На контрольном стенде используется localhost:33070; у вас порт может быть другим. Реквизиты в архив не входят. README и mysql108-metadata-helper.php включены в каждый архив.

Создаются только собственные mysql108_meta_* и mysql108_diag_* таблицы в выделенной базе. Занятое имя вызывает отказ CREATE и не попадает в список очистки. finally удаляет только успешно созданные этим запуском таблицы; после аварийного завершения процесса они могут остаться. Запускать это в базе рабочего сайта не следует. Права на базу ограничены; CREATE/DROP DATABASE ни один пример не выполняет.

Что вы получаете после запуска
  1. example.php выполняет современные запросы MySQLi
  2. result.json: точные таблицы результата
  3. observations.json: реальные версии, ID и счётчики
  4. result.html: те же таблицы и наблюдения, удобно читать в браузере
  5. metrics.json: локальные проверки и контрольные суммы

Версии, ID и показания счётчиков не придумываются: они поступают из текущего запуска и показаны в result.html. В тексте главы таблица «Что получится» содержит устойчивые свойства и учебные данные; переменные показания находятся в сохранённом фактическом результате. Это CLI-проверка PHP/MySQL, не отправка HTML-формы и не тест HTTP.

Отличить заголовок отчёта от исходного столбца

Старый экспорт строит заголовки через mysql_field_name, а затем пытается по этим же строкам найти исходные поля таблицы. После AS product_name это уже разные имена. Покажем и удобный заголовок, и происхождение значения.

Исходные данные

Таблица mysql108_meta_aliases

idnameprice
1Кружка250.00

Что получится

Имена выходных и исходных полей

nameorgnametableorgtable
product_ididpmysql108_meta_aliases
product_namenamepmysql108_meta_aliases
pricepricepmysql108_meta_aliases

Данные отчёта

product_idproduct_nameprice
1Кружка250.00

Малый фрагмент: сначала смысл действия

$result = $db->query('SELECT p.name AS product_name FROM mysql108_meta_aliases AS p');
$field = $result->fetch_field();
echo $field->name;    // product_name
echo $field->orgname; // name

Это фрагмент внутри показанного сценария: $db — уже установленное соединение; $result — результат соответствующего SELECT. Полный запуск ниже самостоятельно создаёт нужные входные таблицы. Если показан SQL, его выполняет query/execute_query из полной программы.

Результат SELECT имеет свою структуру: три выходных поля располагаются в указанном запросом порядке. Объект metadata описывает столбец, а fetch_row читает значения строки. AS меняет name, но orgname хранит исходное имя обычного столбца; alias таблицы p виден в table, исходное имя — в orgtable. Стрелка -> обращается к свойству объекта поля. Вызов fetch_fields возвращает массив таких объектов, по одному на выбранный столбец.

Одна колонка проходит два уровня имён
  1. Таблица mysql108_meta_aliases: name = Кружка
  2. SQL: p.name AS product_name
  3. Поле результата: name=product_name; orgname=name
  4. HTML/CSV: заголовок product_name; значение Кружка

Не определяйте SQL для UPDATE прямо по metadata клиентского отчёта: выражения, JOIN и вычисляемые поля могут не иметь единственной исходной колонки. Для вычисления price*2 поля table/orgtable могут быть пустыми. Сначала задайте разрешённую модель редактирования. Для денежных данных SQL DECIMAL остаётся строковым десятичным значением в этом чтении; метаданные не превращают PHP float в точную валюту.

Ошибки и ограничения

Не путайте регистр имени, alias и название физической таблицы. Тип mysqli — числовой MYSQLI_TYPE_*; старые проверки type === "int" не перенесутся автоматически. PHP-тип прочитанного значения и SQL-тип — разные сведения.

Полная самостоятельная программа PHP 8 и входные файлы
Отличить заголовок отчёта от исходного столбцаСамостоятельный пример
<?php
declare(strict_types=1);
require __DIR__.'/mysql108-metadata-helper.php';
$db=legacy108Connect();$other=null;$created=[];$blocks=[];$checks=[];$observations=[];
try {
legacy108Create($db,$created,'mysql108_meta_aliases','id INT PRIMARY KEY, name VARCHAR(40) NOT NULL, price DECIMAL(8,2) NOT NULL');
$db->query("INSERT INTO mysql108_meta_aliases VALUES(1,'Кружка',250.00)");
$result=$db->query('SELECT p.id AS product_id,p.name AS product_name,p.price FROM mysql108_meta_aliases AS p');
$fields=$result->fetch_fields();$rows=[];foreach($fields as $f){$rows[]=[$f->name,$f->orgname,$f->table,$f->orgtable];}
$data=$result->fetch_row();$result->free();
$blocks=[legacy108Block('Имена выходных и исходных полей',['name','orgname','table','orgtable'],$rows),legacy108Block('Данные отчёта',['product_id','product_name','price'],[array_map('strval',$data)])];
$checks=['three_fields'=>count($fields)===3,'alias_and_origin'=>$rows[1]===['product_name','name','p','mysql108_meta_aliases'],'data_preserved'=>(string)$data[0]==='1'&&$data[1]==='Кружка'];
$observations=[['Тип id из metadata',(string)$fields[0]->type],['Тип price из metadata',(string)$fields[2]->type]];
legacy108Report('mysql108-meta-aliases',$blocks,$checks,$observations,$db,[]);
} finally {legacy108Cleanup($db,$other,$created);}
echo "mysql108-meta-aliases: saved result.html and result.json\n";
Ожидаемый результат
mysql108-meta-aliases: saved result.html and result.json

Код использует mysqli, создаёт показанные учебные данные и сохраняет реальные result.html/result.json/observations.json. Уведомление консоли сообщает только о сохранении; полезный результат — таблицы выше и фактический HTML-файл. Helper и README включены в архив.

Скачать таблицы JSON · Открыть фактический результат · Скачать реальные наблюдения

Попробуйте сами. Добавьте p.price*2 AS double_price. В новом результате отдельно покажите name/orgname/table/orgtable этого выражения. Не обещайте, что по вычислению можно автоматически восстановить один редактируемый столбец.

Перенести строковые флаги в явные проверки битов

В старом редакторе форма ищет слова primary_key и not_null в строке mysql_field_flags. После перехода mysqli возвращает число. Из этого числа нужно извлечь конкретные свойства, сохранив nullable-поле заметки.

Исходные данные

Объявленная схема

ПолеОпределение
idINT UNSIGNED PRIMARY KEY AUTO_INCREMENT
skuVARCHAR(12) NOT NULL UNIQUE
noteVARCHAR(30) NULL

Что получится

Проверяем свойства, а не всю числовую маску

СтолбецСвойствоЕсть
idPRIMARY KEYда
idUNSIGNEDда
idAUTO_INCREMENTда
skuNOT NULLда
skuUNIQUEда
noteNOT NULLнет

Малый фрагмент: сначала смысл действия

$field = $result->fetch_field_direct(0);
$isPrimary = ($field->flags & MYSQLI_PRI_KEY_FLAG) !== 0;

Это фрагмент внутри показанного сценария: $db — уже установленное соединение; $result — результат соответствующего SELECT. Полный запуск ниже самостоятельно создаёт нужные входные таблицы. Если показан SQL, его выполняет query/execute_query из полной программы.

Число flags — битовая маска: отдельным свойствам соответствуют отдельные биты. Операция & оставляет общие биты двух чисел; сравнение !== 0 означает «нужный бит установлен». MYSQLI_PRI_KEY_FLAG — именованная маска PRIMARY KEY. В отличие от равенства всей маске, эта проверка продолжает работать, если сервер сообщает и другие свойства поля. Полная числовая маска сохранена в наблюдениях, но договор примера проверяет только выбранные признаки.

ID одновременно PRIMARY KEY, UNSIGNED и AUTO_INCREMENT. SKU обязателен и уникален. Note допускает NULL, поэтому NOT_NULL_FLAG у него отсутствует. Битовая маска описывает серверную структуру, а не все правила формы: корректность артикула, разрешённые переходы статуса и права пользователя задаются приложением. UNIQUE допускает разные правила для NULL; здесь SKU явно NOT NULL.

Ошибки и ограничения

Не передавайте flags в explode и не сравнивайте всё число с одним MYSQLI_*_FLAG. Смысл multi-column индекса сложнее одного поля; для полного состава индекса нужен отдельный запрос к каталогу. Для nullable-поля отсутствие NOT NULL не означает, что пустая строка равна NULL.

Полная самостоятельная программа PHP 8 и входные файлы
Перенести строковые флаги в явные проверки битовСамостоятельный пример
<?php
declare(strict_types=1);
require __DIR__.'/mysql108-metadata-helper.php';
$db=legacy108Connect();$other=null;$created=[];$blocks=[];$checks=[];$observations=[];
try {
legacy108Create($db,$created,'mysql108_meta_flags','id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, sku VARCHAR(12) NOT NULL UNIQUE, note VARCHAR(30) NULL');
$db->query("INSERT INTO mysql108_meta_flags(sku,note) VALUES('A-100',NULL)");
$result=$db->query('SELECT id,sku,note FROM mysql108_meta_flags');$f=$result->fetch_fields();$result->free();
$tests=[['id','PRIMARY KEY',($f[0]->flags&MYSQLI_PRI_KEY_FLAG)!==0],['id','UNSIGNED',($f[0]->flags&MYSQLI_UNSIGNED_FLAG)!==0],['id','AUTO_INCREMENT',($f[0]->flags&MYSQLI_AUTO_INCREMENT_FLAG)!==0],['sku','NOT NULL',($f[1]->flags&MYSQLI_NOT_NULL_FLAG)!==0],['sku','UNIQUE',($f[1]->flags&MYSQLI_UNIQUE_KEY_FLAG)!==0],['note','NOT NULL',($f[2]->flags&MYSQLI_NOT_NULL_FLAG)!==0]];
$rows=array_map(fn($x)=>[$x[0],$x[1],legacy108Yes($x[2])],$tests);
$blocks=[legacy108Block('Проверяем свойства, а не всю числовую маску',['Столбец','Свойство','Есть'],$rows)];
$checks=['primary'=>$tests[0][2],'unsigned'=>$tests[1][2],'auto'=>$tests[2][2],'required'=>$tests[3][2],'unique'=>$tests[4][2],'nullable'=>!$tests[5][2]];
foreach($f as $field){$observations[]=[$field->name.' raw flags',(string)$field->flags];}
legacy108Report('mysql108-meta-flags',$blocks,$checks,$observations,$db,[]);
} finally {legacy108Cleanup($db,$other,$created);}
echo "mysql108-meta-flags: saved result.html and result.json\n";
Ожидаемый результат
mysql108-meta-flags: saved result.html and result.json

Код использует mysqli, создаёт показанные учебные данные и сохраняет реальные result.html/result.json/observations.json. Уведомление консоли сообщает только о сохранении; полезный результат — таблицы выше и фактический HTML-файл. Helper и README включены в архив.

Скачать таблицы JSON · Открыть фактический результат · Скачать реальные наблюдения

Попробуйте сами. Сделайте note NOT NULL DEFAULT "" и сравните только её NOT_NULL_FLAG. Затем объясните, почему обязательность столбца не проверяет непустой пользовательский текст.

Не принять байты поля за maxlength формы

Разработчик автоматически подставляет length из metadata в maxlength HTML-поля и получает 48 вместо ожидаемых 12. Разделим вместимость столбца в символах, предел в байтах и байты конкретного значения.

Исходные данные

Два значения

label
Кот
AB

Что получится

Договор VARCHAR(12) с utf8mb4

Максимум символовМаксимум байтов
1248

Фактические значения

labelCHAR_LENGTHБайты полученной строки
Кот36
AB22

Малый фрагмент: сначала смысл действия

SELECT CHARACTER_MAXIMUM_LENGTH, CHARACTER_OCTET_LENGTH
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
  AND TABLE_NAME = 'mysql108_meta_widths' AND COLUMN_NAME = 'label';

Это фрагмент внутри показанного сценария: $db — уже установленное соединение; $result — результат соответствующего SELECT. Полный запуск ниже самостоятельно создаёт нужные входные таблицы. Если показан SQL, его выполняет query/execute_query из полной программы.

VARCHAR(12) с utf8mb4 допускает до 12 символов, для которых может потребоваться до 48 байтов. INFORMATION_SCHEMA.COLUMNS сообщает CHARACTER_MAXIMUM_LENGTH и CHARACTER_OCTET_LENGTH раздельно. В значении Кот три символа и шесть UTF-8 байтов; AB содержит два и два. CHAR_LENGTH выполняется сервером над значением, а result->lengths сообщает байтовую длину текущей уже прочитанной строки результата.

mysqli metadata length — ширина поля результата в байтах; она зависит и от кодировки соединения. Она не равна длине текущего значения. max_length с PHP 8.1 всегда 0: старый код, рассчитывающий по нему ширину отчёта, нужно пересмотреть. Даже ограничение HTML maxlength не является универсально идентичным MySQL CHAR_LENGTH: браузер считает кодовые единицы UTF-16, а пользовательский видимый символ может состоять из нескольких кодовых точек. Серверная проверка договора обязательна.

Ошибки и ограничения

Не делите любую длину на 4: типы, бинарные поля и кодировки различаются. Для нужной таблицы явно ограничивайте TABLE_SCHEMA и TABLE_NAME, иначе одноимённые таблицы разных баз смешаются. Максимум фактически полученных строк считайте по выбранной выборке, а не считайте max_length готовой статистикой.

Полная самостоятельная программа PHP 8 и входные файлы
Не принять байты поля за maxlength формыСамостоятельный пример
<?php
declare(strict_types=1);
require __DIR__.'/mysql108-metadata-helper.php';
$db=legacy108Connect();$other=null;$created=[];$blocks=[];$checks=[];$observations=[];
try {
legacy108Create($db,$created,'mysql108_meta_widths','id INT PRIMARY KEY, label VARCHAR(12)');
$db->query("INSERT INTO mysql108_meta_widths VALUES(1,'Кот'),(2,'AB')");
$schema=legacy108Read($db,'SELECT CHARACTER_MAXIMUM_LENGTH,CHARACTER_OCTET_LENGTH FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=? AND COLUMN_NAME=?',['mysql108_meta_widths','label'])[0];
$result=$db->query('SELECT label,CHAR_LENGTH(label) FROM mysql108_meta_widths ORDER BY id');$field=$result->fetch_field_direct(0);$rows=[];
while($row=$result->fetch_row()){$lengths=$result->lengths;$rows[]=[$row[0],(string)$row[1],(string)$lengths[0]];}$result->free();
$blocks=[legacy108Block('Договор VARCHAR(12) с utf8mb4',['Максимум символов','Максимум байтов'],[$schema]),legacy108Block('Фактические значения',['label','CHAR_LENGTH','Байты полученной строки'],$rows)];
$checks=['schema_characters'=>$schema[0]==='12','schema_bytes'=>$schema[1]==='48','unicode'=>$rows[0]===['Кот','3','6'],'ascii'=>$rows[1]===['AB','2','2']];
$observations=[['mysqli metadata length',(string)$field->length],['mysqli metadata max_length (PHP 8.1+)',(string)$field->max_length]];
legacy108Report('mysql108-meta-widths',$blocks,$checks,$observations,$db,[]);
} finally {legacy108Cleanup($db,$other,$created);}
echo "mysql108-meta-widths: saved result.html and result.json\n";
Ожидаемый результат
mysql108-meta-widths: saved result.html and result.json

Код использует mysqli, создаёт показанные учебные данные и сохраняет реальные result.html/result.json/observations.json. Уведомление консоли сообщает только о сохранении; полезный результат — таблицы выше и фактический HTML-файл. Helper и README включены в архив.

Скачать таблицы JSON · Открыть фактический результат · Скачать реальные наблюдения

Попробуйте сами. Добавьте строку с emoji и сравните CHAR_LENGTH, OCTET_LENGTH и PHP strlen. Затем ограничьте выборку одной строкой и объясните, почему схема VARCHAR(12) при этом не изменилась.

Практический вопрос: Why does fetch_fields length differ from the declared CHAR/VARCHAR length?. Разработчик получает ширину в байтах и пытается использовать её как maxlength формы. Наш пример отдельно показывает символы схемы, максимальные байты и длину фактического UTF-8 значения. Обсуждение задаёт ситуацию; семантика сверена с PHP/MySQL, программа и её учебные данные написаны отдельно.

Перемещаться по полям, не теряя строки результата

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

Исходные данные

Результат SELECT

idskutitle
7A-100Кружка

Что получится

Отдельный курсор метаданных

ДействиеРезультат
fetch_field()id
field_seek(2), затем fetch_field()title
fetch_field_direct(1)sku
fetch_field() после концаfalse
Первое поле первой строки7

Малый фрагмент: сначала смысл действия

$result->field_seek(2); // Номер третьего столбца, не третьей строки.
$field = $result->fetch_field();
echo $field->name;      // title

Это фрагмент внутри показанного сценария: $db — уже установленное соединение; $result — результат соответствующего SELECT. Полный запуск ниже самостоятельно создаёт нужные входные таблицы. Если показан SQL, его выполняет query/execute_query из полной программы.

Нумерация полей начинается с нуля: id — 0, sku — 1, title — 2. fetch_field без номера берёт описание у текущего указателя и продвигает его. field_seek(2) переставляет только указатель метаданных; следующий fetch_field читает title. fetch_field_direct(1) обращается к конкретному полю, не меняя этот указатель. После конца fetch_field возвращает false. При этом первое чтение строки по-прежнему даёт id=7.

data_seek относится к строкам буферизованного результата, field_seek — к описаниям столбцов. Массив fetch_fields часто проще ручного курсора, если нужны все заголовки: foreach перебирает уже явный набор объектов. Прямой индекс полезен, если схема SELECT известна и нужен один столбец.

Ошибки и ограничения

Проверяйте границу 0 <= offset < field_count до доступа. Старое предупреждение или false для неправильного offset не следует механически переносить в современный код: mysqli может отклонить неверный аргумент исключением. Курсор метаданных не листает товары и не отменяет запрос.

Полная самостоятельная программа PHP 8 и входные файлы
Перемещаться по полям, не теряя строки результатаСамостоятельный пример
<?php
declare(strict_types=1);
require __DIR__.'/mysql108-metadata-helper.php';
$db=legacy108Connect();$other=null;$created=[];$blocks=[];$checks=[];$observations=[];
try {
legacy108Create($db,$created,'mysql108_meta_cursor','id INT PRIMARY KEY, sku VARCHAR(12), title VARCHAR(30)');
$db->query("INSERT INTO mysql108_meta_cursor VALUES(7,'A-100','Кружка')");
$result=$db->query('SELECT id,sku,title FROM mysql108_meta_cursor');
$first=$result->fetch_field()->name;$result->field_seek(2);$third=$result->fetch_field()->name;
$direct=$result->fetch_field_direct(1)->name;$end=$result->fetch_field();$row=$result->fetch_row();$result->free();
$blocks=[legacy108Block('Отдельный курсор метаданных',['Действие','Результат'],[['fetch_field()',$first],['field_seek(2), затем fetch_field()',$third],['fetch_field_direct(1)',$direct],['fetch_field() после конца',$end===false?'false':'unexpected'],['Первое поле первой строки',(string)$row[0]]])];
$checks=['first'=>$first==='id','seek'=>$third==='title','direct'=>$direct==='sku','end'=>$end===false,'rows_not_moved'=>(string)$row[0]==='7'];
legacy108Report('mysql108-meta-cursor',$blocks,$checks,$observations,$db,[]);
} finally {legacy108Cleanup($db,$other,$created);}
echo "mysql108-meta-cursor: saved result.html and result.json\n";
Ожидаемый результат
mysql108-meta-cursor: saved result.html and result.json

Код использует mysqli, создаёт показанные учебные данные и сохраняет реальные result.html/result.json/observations.json. Уведомление консоли сообщает только о сохранении; полезный результат — таблицы выше и фактический HTML-файл. Helper и README включены в архив.

Скачать таблицы JSON · Открыть фактический результат · Скачать реальные наблюдения

Попробуйте сами. Переставьте SELECT в порядок title,id,sku и заново подпишите индексы. Исправьте только намеренную точку обращения, а затем покажите вариант foreach(fetch_fields()) без жёсткого номера.

Получить схему таблицы, даже если в ней нет товаров

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

Исходные данные

План создания

idnameqty
INT PRIMARY KEYVARCHAR(12) NOT NULLINT NOT NULL DEFAULT 0

Что получится

Описание пустой таблицы

COLUMN_NAMEDATA_TYPEIS_NULLABLECOLUMN_KEY
idintNOPRI
namevarcharNO
qtyintNO

Данные и описание — разные результаты

ПоказательКоличество
Строк данных0
Столбцов по SHOW COLUMNS3

Малый фрагмент: сначала смысл действия

SHOW COLUMNS FROM mysql108_meta_catalog;

Это фрагмент внутри показанного сценария: $db — уже установленное соединение; $result — результат соответствующего SELECT. Полный запуск ниже самостоятельно создаёт нужные входные таблицы. Если показан SQL, его выполняет query/execute_query из полной программы.

SHOW COLUMNS возвращает строки-описания: Field, Type, Null, Key, Default, Extra. Это обычная таблица результата, а не специальный старый resource mysql_list_fields. INFORMATION_SCHEMA.COLUMNS даёт именованные колонки каталога; фильтр TABLE_SCHEMA=DATABASE() закрепляет выбранную базу, TABLE_NAME=? получает имя как значение параметра, ORDER BY ORDINAL_POSITION сохраняет порядок определения полей.

Пустой SELECT id,name,qty возвращает ноль строк данных, но схема всё равно имеет три столбца. Для отчёта по произвольному SELECT подходят fetch_fields; для точного определения таблицы — каталог или SHOW COLUMNS. DATA_TYPE даёт базовое имя вроде varchar, COLUMN_TYPE — более подробное объявление. COLUMN_KEY — краткая подсказка, а не полное описание составных индексов или всех ограничений.

Ошибки и ограничения

Знак ? в запросе к INFORMATION_SCHEMA подставляет значение TABLE_NAME, а не SQL-идентификатор. В SHOW COLUMNS FROM ? так подставить имя таблицы нельзя. При динамическом FROM выбирайте имя из разрешённого списка; в самостоятельной программе имя фиксировано.

Полная самостоятельная программа PHP 8 и входные файлы
Получить схему таблицы, даже если в ней нет товаровСамостоятельный пример
<?php
declare(strict_types=1);
require __DIR__.'/mysql108-metadata-helper.php';
$db=legacy108Connect();$other=null;$created=[];$blocks=[];$checks=[];$observations=[];
try {
legacy108Create($db,$created,'mysql108_meta_catalog','id INT PRIMARY KEY, name VARCHAR(12) NOT NULL, qty INT NOT NULL DEFAULT 0');
$rows=legacy108Read($db,'SELECT COLUMN_NAME,DATA_TYPE,IS_NULLABLE,COLUMN_KEY FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=? ORDER BY ORDINAL_POSITION',['mysql108_meta_catalog']);
$empty=legacy108Read($db,'SELECT id,name,qty FROM mysql108_meta_catalog');
$show=legacy108Read($db,'SHOW COLUMNS FROM mysql108_meta_catalog');
$blocks=[legacy108Block('Описание пустой таблицы',['COLUMN_NAME','DATA_TYPE','IS_NULLABLE','COLUMN_KEY'],$rows),legacy108Block('Данные и описание — разные результаты',['Показатель','Количество'],[['Строк данных',(string)count($empty)],['Столбцов по SHOW COLUMNS',(string)count($show)]])];
$checks=['empty'=>$empty===[],'three_columns'=>count($rows)===3,'ordered_names'=>array_column($rows,0)===['id','name','qty'],'show_agrees'=>array_column($show,0)===array_column($rows,0)];
legacy108Report('mysql108-meta-catalog',$blocks,$checks,$observations,$db,[]);
} finally {legacy108Cleanup($db,$other,$created);}
echo "mysql108-meta-catalog: saved result.html and result.json\n";
Ожидаемый результат
mysql108-meta-catalog: saved result.html and result.json

Код использует mysqli, создаёт показанные учебные данные и сохраняет реальные result.html/result.json/observations.json. Уведомление консоли сообщает только о сохранении; полезный результат — таблицы выше и фактический HTML-файл. Helper и README включены в архив.

Скачать таблицы JSON · Открыть фактический результат · Скачать реальные наблюдения

Попробуйте сами. Добавьте nullable-поле comment VARCHAR(100) и выведите CHARACTER_MAXIMUM_LENGTH. Затем разработайте понятную ошибку импорта, если обязательного qty нет, вместо попытки угадать столбец по позиции.

Различить выбранную базу и список доступных таблиц

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

Исходные данные

Две созданные таблицы

ИмяПоле
mysql108_meta_listing_aid INT PRIMARY KEY
mysql108_meta_listing_bid INT PRIMARY KEY

Что получится

Проверка контекста

ВопросОтвет
DATABASE() совпадает с настройкойда
Выбранная схема видна в каталогеда

Только две таблицы этого примера

TABLE_NAME
mysql108_meta_listing_a
mysql108_meta_listing_b

Малый фрагмент: сначала смысл действия

SELECT DATABASE();
SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = DATABASE()
  AND TABLE_NAME IN ('mysql108_meta_listing_a','mysql108_meta_listing_b')
ORDER BY TABLE_NAME;

Это фрагмент внутри показанного сценария: $db — уже установленное соединение; $result — результат соответствующего SELECT. Полный запуск ниже самостоятельно создаёт нужные входные таблицы. Если показан SQL, его выполняет query/execute_query из полной программы.

DATABASE() отвечает на вопрос о текущем контексте конкретного соединения; вне выбранной схемы результат может быть NULL. SCHEMATA содержит доступные сведения о схемах. TABLES описывает таблицы и представления; TABLE_SCHEMA и TABLE_NAME — разные колонки. В примере оба имени таблиц передаются параметрами условия IN, а результат сортируется по имени. Имена базы и таблиц не интерпретируются как номера строк каталога.

SHOW DATABASES и каталог показывают только то, что разрешено видеть текущему аккаунту. Отсутствие имени в списке не доказывает, что схемы физически нет. Для списка конкретного приложения обычно достаточно одной выделенной схемы и фильтра по нужным объектам. mysql_tablename извлекал имя из строки старого списка, а mysql_field_table — происхождение выходного столбца SELECT: это принципиально разные операции.

Ошибки и ограничения

Не публикуйте полный каталог сервера на диагностической странице сайта. Не принимайте первый результат SHOW DATABASES за текущую базу. Одинаковые имена таблиц встречаются в разных схемах; фильтр только по TABLE_NAME недостаточен.

Полная самостоятельная программа PHP 8 и входные файлы
Различить выбранную базу и список доступных таблицСамостоятельный пример
<?php
declare(strict_types=1);
require __DIR__.'/mysql108-metadata-helper.php';
$db=legacy108Connect();$other=null;$created=[];$blocks=[];$checks=[];$observations=[];
try {
legacy108Create($db,$created,'mysql108_meta_listing_a','id INT PRIMARY KEY');
legacy108Create($db,$created,'mysql108_meta_listing_b','id INT PRIMARY KEY');
$current=legacy108Read($db,'SELECT DATABASE()')[0][0];
$visible=legacy108Read($db,'SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME=DATABASE()');
$tables=legacy108Read($db,'SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME IN (?,?) ORDER BY TABLE_NAME',['mysql108_meta_listing_a','mysql108_meta_listing_b']);
$same=$current===getenv('PHPMAN_MYSQL_DATABASE');$available=count($visible)===1&&$visible[0][0]===$current;
$blocks=[legacy108Block('Проверка контекста',['Вопрос','Ответ'],[['DATABASE() совпадает с настройкой',legacy108Yes($same)],['Выбранная схема видна в каталоге',legacy108Yes($available)]]),legacy108Block('Только две таблицы этого примера',['TABLE_NAME'],$tables)];
$checks=['selected_schema'=>$same,'visible_schema'=>$available,'owned_only'=>$tables===[['mysql108_meta_listing_a'],['mysql108_meta_listing_b']]];
$observations=[['Фактическое имя выбранной учебной базы',$current]];
legacy108Report('mysql108-meta-listing',$blocks,$checks,$observations,$db,[]);
} finally {legacy108Cleanup($db,$other,$created);}
echo "mysql108-meta-listing: saved result.html and result.json\n";
Ожидаемый результат
mysql108-meta-listing: saved result.html and result.json

Код использует mysqli, создаёт показанные учебные данные и сохраняет реальные result.html/result.json/observations.json. Уведомление консоли сообщает только о сохранении; полезный результат — таблицы выше и фактический HTML-файл. Helper и README включены в архив.

Скачать таблицы JSON · Открыть фактический результат · Скачать реальные наблюдения

Попробуйте сами. Измените SQL списка так, чтобы он возвращал только mysql108_meta_listing_b. Проверьте, что DATABASE() не поменялся: фильтрация списка не выбирает другую схему.

Практический вопрос: How to determine which MySQL database has been selected?. Путаются выбранная база, перечень доступных схем и сведения о хосте. Программа проверяет DATABASE() отдельно от каталога. Обсуждение задаёт ситуацию; семантика сверена с PHP/MySQL, программа и её учебные данные написаны отдельно.

Исторические функции: отдельные контракты и путь переноса

Каждая карточка отдельно разбирает параметры, возврат, ограничения, исторический контекст и два случая современного применения. Исторический фрагмент не запускается; запускаемые программы главы используют mysqli.

ФункцияЗадачаВерсия устаревания
mysql_fetch_fieldПрочитать описание одного выходного столбца отчётаPHP5.5.0 → удаление7.0
mysql_field_flagsУзнать свойства колонки, по которым старый редактор строил формуPHP5.5.0 → удаление7.0
mysql_field_lenПолучить объявленную длину поля, не длину текущего товараPHP5.5.0 → удаление7.0
mysql_field_nameВосстановить заголовок выбранной колонки старого отчётаPHP5.5.0 → удаление7.0
mysql_field_seekВыбрать, описание какого поля будет прочитано следующимPHP5.5.0 → удаление7.0
mysql_field_tableУзнать, с какой таблицей связан столбец результата JOINPHP5.5.0 → удаление7.0
mysql_field_typeРазобраться со старым переключателем типа поляPHP5.5.0 → удаление7.0
mysql_list_fieldsПолучить старый указатель описания столбцов таблицыPHP5.4.0 → удаление7.0
mysql_list_tablesПеренести старый список объектов одной базыPHP4.3.0 → удаление7.0
mysql_tablenameПрочитать имя таблицы из строки старого спискаPHP5.5.0 → удаление7.0
mysql_db_nameПрочитать имя базы из результата mysql_list_dbsPHP5.5.0 → удаление7.0
mysql_list_dbsПеречислить доступные базы старого сервераPHP5.5.0 → удаление7.0

Следующий шаг: перенести реальный отчёт

Возьмите небольшой старый отчёт и запишите отдельно его заголовки, исходные поля и ожидаемые строки. Замените получение metadata, сохранив эти три договора. Затем проверьте чтение строк и буферизацию и диагностику конкретного подключения. Не переносите динамический SELECT* и редактирование неизвестных полей только потому, что старый код так работал.

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

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

mysql_fetch_fieldПрочитать описание одного выходного столбца отчёта

PHP 4/5; deprecated 5.5.0; removed PHP 7.0 · mysql (removed)

mysql_fetch_field(resource $result, int $field_offset = 0): object

Прочитать описание одного выходного столбца отчёта.

ПараметрИсторическое значение и смысл
resultОткрытый resource результата старого mysql_query; не SQL-строка, не массив и не объект mysqli_result. Для специальных списков источник указан отдельно.
field_offset = 0Номер поля начинается с нуля. В показанной исторической сигнатуре default=0, но пропущенный аргумент означает чтение следующего ещё не полученного описания через внутренний указатель; явно переданный 0 обращается к первому полю.

Возврат и отказ. Объект описания поля. Его свойства: name — выходное имя; table — таблица или её alias; max_length — максимальная длина; not_null, primary_key, unique_key, multiple_key — признаки обязательности и ключей; numeric, blob — признаки числового/BLOB-поля; type — старое текстовое имя типа; unsigned и zerofill — дополнительные признаки. Историческая страница формально описывает успешный объект; её пример отдельно проверяет отсутствие метаданных.

Границы и исторические примечания. Имена чувствительны к регистру; при AS возвращалось имя alias, а не обязательно физическое имя. Это описание SELECT, а не универсальная схема таблицы. Старые max_length и type нельзя копировать в современные сравнения без пересмотра.

Исторический фрагмент mysql_fetch_field — удалён в PHP 7, не запускаетсяФрагмент или команда
<?php
// Исторический контекст PHP 4/5. НЕ выполнять в PHP 7/8.
$meta = mysql_fetch_field($result, 0);
echo $meta->name;

Это фрагмент для узнавания старого кода, не самостоятельная программа и не проверка выполнения mysql_*. Переменные $link/$result/$list обозначают прежние ресурсы, созданные окружающим кодом. Современные запускаемые программы указаны в двух случаях переноса ниже.

Современный путь. mysqli_result::fetch_field() или fetch_fields(); прямой индекс — fetch_field_direct(). Современные orgname/orgtable сохраняют происхождение обычного поля, flags заменяет набор старых булевых свойств, type становится MYSQLI_TYPE_*. В PHP 8.1+ max_length всегда 0. PDOStatement::getColumnMeta — отдельный зависящий от драйвера контракт, а не одинаковый объект.

Два случая переноса и видимый результат

Заголовки CSV после AS. Показываем product_name пользователю, а name оставляем для объяснения происхождения колонки. Открыть исходные данные, результат и полную современную программу.

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

Общий маршрут переноса: подключение, кодировка и выбор API; запросы, ошибки и строки результата. Современные операции mysqli имеют отдельные карточки справочника.

mysql_field_flagsУзнать свойства колонки, по которым старый редактор строил форму

PHP 4/5; deprecated 5.5.0; removed PHP 7.0 · mysql (removed)

mysql_field_flags(resource $result, int $field_offset): string|false

Узнать свойства колонки, по которым старый редактор строил форму.

ПараметрИсторическое значение и смысл
resultОткрытый resource результата старого mysql_query; не SQL-строка, не массив и не объект mysqli_result. Для специальных списков источник указан отдельно.
field_offsetИндекс выходного столбца от 0 до mysql_num_fields(result)-1. Несуществующий индекс вызывает E_WARNING; это индекс поля, не строки.

Возврат и отказ. Строка слов, разделённых одним пробелом, либо false при отказе. Возможные слова: not_null, primary_key, unique_key, multiple_key, blob, unsigned, zerofill, binary, enum, auto_increment, timestamp; набор зависел от версии MySQL.

Границы и исторические примечания. Старый alias mysql_fieldflags также устарел. Проверка слов описывала свойства поля, но не правила пользователя и не полный состав составного индекса.

Исторический фрагмент mysql_field_flags — удалён в PHP 7, не запускаетсяФрагмент или команда
<?php
// Исторический контекст PHP 4/5. НЕ выполнять в PHP 7/8.
$words = mysql_field_flags($result, 0);
if ($words !== false) { $flags = explode(" ", $words); }

Это фрагмент для узнавания старого кода, не самостоятельная программа и не проверка выполнения mysql_*. Переменные $link/$result/$list обозначают прежние ресурсы, созданные окружающим кодом. Современные запускаемые программы указаны в двух случаях переноса ниже.

Современный путь. В mysqli fetch_field_direct(index)->flags возвращает битовую маску. Проверяйте ($flags & MYSQLI_NOT_NULL_FLAG) !== 0 и другие нужные именованные биты. Нельзя передать число в старый explode или сравнить всю маску с одним битом.

Два случая переноса и видимый результат

Отключить редактирование AUTO_INCREMENT. Проверяем отдельные признаки id и не ошибаемся при сочетании PRIMARY KEY с UNSIGNED. Открыть исходные данные, результат и полную современную программу.

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

Общий маршрут переноса: подключение, кодировка и выбор API; запросы, ошибки и строки результата. Современные операции mysqli имеют отдельные карточки справочника.

mysql_field_lenПолучить объявленную длину поля, не длину текущего товара

PHP 4/5; deprecated 5.5.0; removed PHP 7.0 · mysql (removed)

mysql_field_len(resource $result, int $field_offset): int|false

Получить объявленную длину поля, не длину текущего товара.

ПараметрИсторическое значение и смысл
resultОткрытый resource результата старого mysql_query; не SQL-строка, не массив и не объект mysqli_result. Для специальных списков источник указан отдельно.
field_offsetИндекс выходного столбца от 0 до mysql_num_fields(result)-1. Несуществующий индекс вызывает E_WARNING; это индекс поля, не строки.

Возврат и отказ. Целая длина поля по заданному индексу или false при отказе. Официальный пример связывает её с определением поля в схеме. Для длины значений конкретной строки служила другая функция — mysql_fetch_lengths.

Границы и исторические примечания. Старый alias mysql_fieldlen. Название length не даёт права считать число пользовательскими символами или автоматически ставить его в HTML maxlength. Единицы и кодировка важны при миграции.

Исторический фрагмент mysql_field_len — удалён в PHP 7, не запускаетсяФрагмент или команда
<?php
// Исторический контекст PHP 4/5. НЕ выполнять в PHP 7/8.
$declared = mysql_field_len($result, 0);
// Это не strlen значения из текущей строки.

Это фрагмент для узнавания старого кода, не самостоятельная программа и не проверка выполнения mysql_*. Переменные $link/$result/$list обозначают прежние ресурсы, созданные окружающим кодом. Современные запускаемые программы указаны в двух случаях переноса ниже.

Современный путь. fetch_field_direct(index)->length описывает байтовую ширину результата. Для VARCHAR(n) используйте INFORMATION_SCHEMA.COLUMNS с CHARACTER_MAXIMUM_LENGTH и CHARACTER_OCTET_LENGTH. Для текущей строки — fetch_lengths/lengths; для подсчёта символов выбранного значения — CHAR_LENGTH в MySQL.

Два случая переноса и видимый результат

Подсказка допустимой длины формы. VARCHAR(12) и metadata length=48 не означают одинаковое количество символов. Открыть исходные данные, результат и полную современную программу.

Проверка договора CSV до чтения строк. Схему получаем даже из пустой таблицы; заполненность таблицы не меняет её определение. Открыть исходные данные, результат и полную современную программу.

Общий маршрут переноса: подключение, кодировка и выбор API; запросы, ошибки и строки результата. Современные операции mysqli имеют отдельные карточки справочника.

mysql_field_nameВосстановить заголовок выбранной колонки старого отчёта

PHP 4/5; deprecated 5.5.0; removed PHP 7.0 · mysql (removed)

mysql_field_name(resource $result, int $field_offset): string|false

Восстановить заголовок выбранной колонки старого отчёта.

ПараметрИсторическое значение и смысл
resultОткрытый resource результата старого mysql_query; не SQL-строка, не массив и не объект mysqli_result. Для специальных списков источник указан отдельно.
field_offsetИндекс выходного столбца от 0 до mysql_num_fields(result)-1. Несуществующий индекс вызывает E_WARNING; это индекс поля, не строки.

Возврат и отказ. Имя выходного поля по индексу или false при отказе. Имя чувствительно к регистру.

Границы и исторические примечания. Старый alias mysql_fieldname. Номер относится к SELECT-списку: изменение порядка запроса меняет соответствие индексов. AS задаёт имя результата; это не гарантированное исходное имя в схеме.

Исторический фрагмент mysql_field_name — удалён в PHP 7, не запускаетсяФрагмент или команда
<?php
// Исторический контекст PHP 4/5. НЕ выполнять в PHP 7/8.
$heading = mysql_field_name($result, 0);
echo $heading;

Это фрагмент для узнавания старого кода, не самостоятельная программа и не проверка выполнения mysql_*. Переменные $link/$result/$list обозначают прежние ресурсы, созданные окружающим кодом. Современные запускаемые программы указаны в двух случаях переноса ниже.

Современный путь. fetch_field_direct(index)->name; если необходимо происхождение обычного поля, отдельно orgname. Для всей строки имён удобен fetch_fields. Динамическое построение SQL по именам отчёта должно иметь разрешённый список, а не доверять пришедшему из браузера заголовку.

Два случая переноса и видимый результат

Показать понятный заголовок выгрузки. Выходное product_name отделено от исходного name. Открыть исходные данные, результат и полную современную программу.

Обновить старый индексный генератор. Изменение SELECT title,id,sku заставляет пересмотреть номер, а обход fetch_fields делает порядок явным. Открыть исходные данные, результат и полную современную программу.

Общий маршрут переноса: подключение, кодировка и выбор API; запросы, ошибки и строки результата. Современные операции mysqli имеют отдельные карточки справочника.

mysql_field_seekВыбрать, описание какого поля будет прочитано следующим

PHP 4/5; deprecated 5.5.0; removed PHP 7.0 · mysql (removed)

mysql_field_seek(resource $result, int $field_offset): bool

Выбрать, описание какого поля будет прочитано следующим.

ПараметрИсторическое значение и смысл
resultОткрытый resource результата старого mysql_query; не SQL-строка, не массив и не объект mysqli_result. Для специальных списков источник указан отдельно.
field_offsetИндекс выходного столбца от 0 до mysql_num_fields(result)-1. Несуществующий индекс вызывает E_WARNING; это индекс поля, не строки.

Возврат и отказ. true при успешном перемещении, false при отказе. Следующий mysql_fetch_field без явно заданного offset читает поле с установленного места.

Границы и исторические примечания. Это указатель описаний столбцов; mysql_data_seek работает с товарными строками. Перемещение не выполняет новый SQL и не меняет таблицу. Неиспользуемый или освобождённый resource не является допустимым результатом.

Исторический фрагмент mysql_field_seek — удалён в PHP 7, не запускаетсяФрагмент или команда
<?php
// Исторический контекст PHP 4/5. НЕ выполнять в PHP 7/8.
if (mysql_field_seek($result, 2)) {
    $meta = mysql_fetch_field($result);
}

Это фрагмент для узнавания старого кода, не самостоятельная программа и не проверка выполнения mysql_*. Переменные $link/$result/$list обозначают прежние ресурсы, созданные окружающим кодом. Современные запускаемые программы указаны в двух случаях переноса ниже.

Современный путь. mysqli_result::field_seek(index), затем fetch_field(). Для одноразового чтения лучше fetch_field_direct(index), для всех описаний — fetch_fields(). PDO row-cursor нельзя объявлять эквивалентом курсора метаданных: это другой уровень данных.

Два случая переноса и видимый результат

Перейти к третьему заголовку. Индекс2 выбирает title, но первая строка данных ещё не прочитана. Открыть исходные данные, результат и полную современную программу.

Обойти поля для подписи отчёта. Массив fetch_fields позволяет получить все заголовки и происхождение без ручного переставления указателя. Открыть исходные данные, результат и полную современную программу.

Общий маршрут переноса: подключение, кодировка и выбор API; запросы, ошибки и строки результата. Современные операции mysqli имеют отдельные карточки справочника.

mysql_field_tableУзнать, с какой таблицей связан столбец результата JOIN

PHP 4/5; deprecated 5.5.0; removed PHP 7.0 · mysql (removed)

mysql_field_table(resource $result, int $field_offset): string

Узнать, с какой таблицей связан столбец результата JOIN.

ПараметрИсторическое значение и смысл
resultОткрытый resource результата старого mysql_query; не SQL-строка, не массив и не объект mysqli_result. Для специальных списков источник указан отдельно.
field_offsetИндекс выходного столбца от 0 до mysql_num_fields(result)-1. Несуществующий индекс вызывает E_WARNING; это индекс поля, не строки.

Возврат и отказ. Имя таблицы успешного выходного поля. Официальная историческая сигнатура объявляет string; неверный индекс описан через E_WARNING, не следует придумывать для всех случаев универсальный false-контракт.

Границы и исторические примечания. Старый alias mysql_fieldtable. Речь о происхождении колонки, не о получении списка таблиц. Alias таблицы и вычисляемое выражение требуют отдельного понимания; не все результаты SELECT принадлежат одному физическому полю.

Исторический фрагмент mysql_field_table — удалён в PHP 7, не запускаетсяФрагмент или команда
<?php
// Исторический контекст PHP 4/5. НЕ выполнять в PHP 7/8.
$table = mysql_field_table($result, 0);
$field = mysql_field_name($result, 0);

Это фрагмент для узнавания старого кода, не самостоятельная программа и не проверка выполнения mysql_*. Переменные $link/$result/$list обозначают прежние ресурсы, созданные окружающим кодом. Современные запускаемые программы указаны в двух случаях переноса ниже.

Современный путь. fetch_field_direct(index)->table и orgtable. Первое может содержать alias, второе — исходную таблицу; для выражения сведения о таблице могут быть пустыми. Для списка объектов схемы используйте INFORMATION_SCHEMA.TABLES или SHOW TABLES.

Два случая переноса и видимый результат

Указать происхождение столбца в JOIN-отчёте. table=p и orgtable=mysql108_meta_aliases отвечают на разные вопросы. Открыть исходные данные, результат и полную современную программу.

Отделить происхождение от каталога. Список двух таблиц приложения получается отдельным SQL, без осмотра случайного SELECT. Открыть исходные данные, результат и полную современную программу.

Общий маршрут переноса: подключение, кодировка и выбор API; запросы, ошибки и строки результата. Современные операции mysqli имеют отдельные карточки справочника.

mysql_field_typeРазобраться со старым переключателем типа поля

PHP 4/5; deprecated 5.5.0; removed PHP 7.0 · mysql (removed)

mysql_field_type(resource $result, int $field_offset): string

Разобраться со старым переключателем типа поля.

ПараметрИсторическое значение и смысл
resultОткрытый resource результата старого mysql_query; не SQL-строка, не массив и не объект mysqli_result. Для специальных списков источник указан отдельно.
field_offsetИндекс выходного столбца от 0 до mysql_num_fields(result)-1. Несуществующий индекс вызывает E_WARNING; это индекс поля, не строки.

Возврат и отказ. Текстовый тип, например int, real, string, blob и другие типы, описанные в MySQL. Историческая сигнатура string и предупреждение при неверном индексе не равны современной числовой маске типов.

Границы и исторические примечания. Старый alias mysql_fieldtype. Тип SQL-поля, формат бизнес-значения и тип PHP-значения после fetch различаются. DECIMAL для цены не следует превращать в float только потому, что старый код искал слово real.

Исторический фрагмент mysql_field_type — удалён в PHP 7, не запускаетсяФрагмент или команда
<?php
// Исторический контекст PHP 4/5. НЕ выполнять в PHP 7/8.
$kind = mysql_field_type($result, 0);
// Старое сравнение $kind === "int" относится к ext/mysql.

Это фрагмент для узнавания старого кода, не самостоятельная программа и не проверка выполнения mysql_*. Переменные $link/$result/$list обозначают прежние ресурсы, созданные окружающим кодом. Современные запускаемые программы указаны в двух случаях переноса ниже.

Современный путь. mysqli metadata ->type содержит числовой MYSQLI_TYPE_*; сопоставляйте нужные константы, а не строки старого API. Для полного определения столбца TABLE используйте DATA_TYPE/COLUMN_TYPE в INFORMATION_SCHEMA. PDO getColumnMeta имеет другой набор ключей и поддержку драйвера.

Два случая переноса и видимый результат

Перенос форматирования цены. Сохраняем десятичную строку 250.00 и отдельно читаем фактический код SQL-типа. Открыть исходные данные, результат и полную современную программу.

Проверить схему загрузки. DATA_TYPE явно показывает int/varchar независимо от того, есть ли в таблице строки. Открыть исходные данные, результат и полную современную программу.

Общий маршрут переноса: подключение, кодировка и выбор API; запросы, ошибки и строки результата. Современные операции mysqli имеют отдельные карточки справочника.

mysql_list_fieldsПолучить старый указатель описания столбцов таблицы

PHP 4/5; deprecated 5.4.0; removed PHP 7.0 · mysql (removed)

mysql_list_fields(string $database_name, string $table_name, resource $link_identifier = NULL): resource

Получить старый указатель описания столбцов таблицы.

ПараметрИсторическое значение и смысл
database_nameИмя базы, в которой находится таблица.
table_nameИмя таблицы, описание которой нужно получить.
link_identifier = NULLResource старого подключения. При пропуске выбиралось последнее соединение mysql_connect; если его не было, делалась попытка mysql_connect без аргументов. Неудача установить соединение давала E_WARNING. В новом коде передавайте конкретный объект mysqli.

Возврат и отказ. Resource указателя описаний при успехе, false при отказе. Его передавали mysql_field_flags, mysql_field_len, mysql_field_name, mysql_field_type. Это не массив строк товаров.

Границы и исторические примечания. Функция отдельно deprecated уже с PHP 5.4.0; alias mysql_listfields. Ещё старая документация советовала SQL SHOW COLUMNS FROM table [LIKE pattern]. SHOW COLUMNS возвращает обычные строки-описания и требует другого чтения, чем старый специальный указатель.

Исторический фрагмент mysql_list_fields — удалён в PHP 7, не запускаетсяФрагмент или команда
<?php
// Исторический контекст PHP 4/5. НЕ выполнять в PHP 7/8.
$fields = mysql_list_fields("shop", "products", $link);
// Старый специальный resource метаданных.

Это фрагмент для узнавания старого кода, не самостоятельная программа и не проверка выполнения mysql_*. Переменные $link/$result/$list обозначают прежние ресурсы, созданные окружающим кодом. Современные запускаемые программы указаны в двух случаях переноса ниже.

Современный путь. SHOW COLUMNS либо INFORMATION_SCHEMA.COLUMNS через mysqli/PDO. При переносе меняются не только имя вызова, но и форма результата: Field/Type/Null/Key/Default/Extra — данные строк каталога. Подстановка имён SQL-таблиц и параметров значений имеет разные правила.

Два случая переноса и видимый результат

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

Получить лимиты текста для договора. INFORMATION_SCHEMA различает число символов и максимальный объём байтов. Открыть исходные данные, результат и полную современную программу.

Общий маршрут переноса: подключение, кодировка и выбор API; запросы, ошибки и строки результата. Современные операции mysqli имеют отдельные карточки справочника.

mysql_list_tablesПеренести старый список объектов одной базы

PHP 4/5; deprecated 4.3.0; removed PHP 7.0 · mysql (removed)

mysql_list_tables(string $database, resource $link_identifier = NULL): resource|false

Перенести старый список объектов одной базы.

ПараметрИсторическое значение и смысл
databaseИмя базы, таблицы которой перечисляются.
link_identifier = NULLResource старого подключения. При пропуске выбиралось последнее соединение mysql_connect; если его не было, делалась попытка mysql_connect без аргументов. Неудача установить соединение давала E_WARNING. В новом коде передавайте конкретный объект mysqli.

Возврат и отказ. Resource результата со списком при успехе либо false при отказе. Его читали mysql_tablename по номеру строки или обычными fetch-функциями старого API.

Границы и исторические примечания. Deprecated с PHP 4.3.0, alias mysql_listtables. Рекомендованная уже тогда SQL-форма — SHOW TABLES [FROM db_name] [LIKE pattern]. Список зависит от прав и не означает, что текущая выбранная база поменялась.

Исторический фрагмент mysql_list_tables — удалён в PHP 7, не запускаетсяФрагмент или команда
<?php
// Исторический контекст PHP 4/5. НЕ выполнять в PHP 7/8.
$list = mysql_list_tables("shop", $link);
// Чтение строк: mysql_tablename($list, $row).

Это фрагмент для узнавания старого кода, не самостоятельная программа и не проверка выполнения mysql_*. Переменные $link/$result/$list обозначают прежние ресурсы, созданные окружающим кодом. Современные запускаемые программы указаны в двух случаях переноса ниже.

Современный путь. SHOW TABLES через mysqli/PDO либо INFORMATION_SCHEMA.TABLES с явным TABLE_SCHEMA. Если нужны только собственные объекты, задавайте фильтр; полная структура сервера не обязательна пользователю приложения.

Два случая переноса и видимый результат

Показать только таблицы модуля. Два разрешённых имени возвращаются в заданном ORDER BY. Открыть исходные данные, результат и полную современную программу.

После выбора таблицы проверить её схему. Список имён и список столбцов — два разных запроса и два отдельных договора. Открыть исходные данные, результат и полную современную программу.

Общий маршрут переноса: подключение, кодировка и выбор API; запросы, ошибки и строки результата. Современные операции mysqli имеют отдельные карточки справочника.

mysql_tablenameПрочитать имя таблицы из строки старого списка

PHP 4/5; deprecated 5.5.0; removed PHP 7.0 · mysql (removed)

mysql_tablename(resource $result, int $i): string|false

Прочитать имя таблицы из строки старого списка.

ПараметрИсторическое значение и смысл
resultResource, полученный mysql_list_tables; не результат произвольного SELECT товаров.
iЦелый номер строки/таблицы списка, начиная с0. Количество строк узнавалось mysql_num_rows.

Возврат и отказ. Имя таблицы по номеру строки либо false при отказе. Вместо неё список можно было читать обычным mysql_fetch_array.

Границы и исторические примечания. Название часто путают с mysql_field_table, но здесь выбирается строка списка таблиц. Позиция не является постоянным идентификатором объекта; порядок списка может изменяться.

Исторический фрагмент mysql_tablename — удалён в PHP 7, не запускаетсяФрагмент или команда
<?php
// Исторический контекст PHP 4/5. НЕ выполнять в PHP 7/8.
$name = mysql_tablename($list, 0);
// Первая строка списка таблиц, не первое поле SELECT.

Это фрагмент для узнавания старого кода, не самостоятельная программа и не проверка выполнения mysql_*. Переменные $link/$result/$list обозначают прежние ресурсы, созданные окружающим кодом. Современные запускаемые программы указаны в двух случаях переноса ниже.

Современный путь. Получите SHOW TABLES и читайте fetch_row()[0] в цикле либо выберите TABLE_NAME из INFORMATION_SCHEMA.TABLES. Для точного имени используйте условие, а не случайный номер строки.

Два случая переноса и видимый результат

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

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

Общий маршрут переноса: подключение, кодировка и выбор API; запросы, ошибки и строки результата. Современные операции mysqli имеют отдельные карточки справочника.

mysql_db_nameПрочитать имя базы из результата mysql_list_dbs

PHP 4/5; deprecated 5.5.0; removed PHP 7.0 · mysql (removed)

mysql_db_name(resource $result, int $row, mixed $field = NULL): string

Прочитать имя базы из результата mysql_list_dbs.

ПараметрИсторическое значение и смысл
resultResource результата mysql_list_dbs.
rowИндекс строки списка баз, начиная с0.
field = NULLИмя поля результата; необязательный третий аргумент исторического API.

Возврат и отказ. Имя базы при успехе, false при отказе (это дополнительно указано в тексте Return Values, хотя историческая сигнатура показывает string). Для причины отказа предлагался mysql_error.

Границы и исторические примечания. Alias mysql_dbname. Функция не отвечала «какая база выбрана сейчас»: она извлекала строку списка. Предложение SELECT DATABASE() на официальной странице относится только к задаче текущей схемы, не ко всему перечислению.

Исторический фрагмент mysql_db_name — удалён в PHP 7, не запускаетсяФрагмент или команда
<?php
// Исторический контекст PHP 4/5. НЕ выполнять в PHP 7/8.
$name = mysql_db_name($databaseList, 0);
// Это первый элемент списка, а не обязательно текущая база.

Это фрагмент для узнавания старого кода, не самостоятельная программа и не проверка выполнения mysql_*. Переменные $link/$result/$list обозначают прежние ресурсы, созданные окружающим кодом. Современные запускаемые программы указаны в двух случаях переноса ниже.

Современный путь. Текущая схема: SELECT DATABASE(). Список видимых схем: SHOW DATABASES или INFORMATION_SCHEMA.SCHEMATA, затем обычное чтение строк. При отсутствии выбранной схемы DATABASE() может вернуть NULL.

Два случая переноса и видимый результат

Устранить ошибку выбора базы в старой админке. Сравниваем DATABASE() с настройкой отдельно от видимости схемы. Открыть исходные данные, результат и полную современную программу.

Проверить контекст перед административным планом. Показываем выбранную схему, но не подменяем этим проверку прав CREATE/DROP DATABASE. Открыть исходные данные, результат и полную современную программу.

Общий маршрут переноса: подключение, кодировка и выбор API; запросы, ошибки и строки результата. Современные операции mysqli имеют отдельные карточки справочника.

mysql_list_dbsПеречислить доступные базы старого сервера

PHP 4/5; deprecated 5.5.0; removed PHP 7.0 · mysql (removed)

mysql_list_dbs(resource $link_identifier = NULL): resource

Перечислить доступные базы старого сервера.

ПараметрИсторическое значение и смысл
link_identifier = NULLResource старого подключения. При пропуске выбиралось последнее соединение mysql_connect; если его не было, делалась попытка mysql_connect без аргументов. Неудача установить соединение давала E_WARNING. В новом коде передавайте конкретный объект mysqli.

Возврат и отказ. Resource результата при успехе, false при отказе. Официальная сигнатура resource не перечисляет false, но текст возврата его оговаривает. Результат читался как таблица, в частности через mysql_db_name или обычные fetch-функции.

Границы и исторические примечания. Alias mysql_listdbs. Доступность списка зависит от аккаунта и прав; нельзя считать его полным инвентарём физического сервера. mysql_select_db выбирала контекст, а list_dbs только перечисляла.

Исторический фрагмент mysql_list_dbs — удалён в PHP 7, не запускаетсяФрагмент или команда
<?php
// Исторический контекст PHP 4/5. НЕ выполнять в PHP 7/8.
$list = mysql_list_dbs($link);
if ($list !== false) { $firstName = mysql_db_name($list, 0); }

Это фрагмент для узнавания старого кода, не самостоятельная программа и не проверка выполнения mysql_*. Переменные $link/$result/$list обозначают прежние ресурсы, созданные окружающим кодом. Современные запускаемые программы указаны в двух случаях переноса ниже.

Современный путь. SHOW DATABASES либо запрос к INFORMATION_SCHEMA.SCHEMATA. Для задачи «где я сейчас» достаточно DATABASE(), а для приложения обычно не требуется список чужих схем.

Два случая переноса и видимый результат

Проверить видимость собственной схемы. Фильтр SCHEMA_NAME=DATABASE() не открывает весь каталог пользователю. Открыть исходные данные, результат и полную современную программу.

Отделить наличие схемы от права удалить её. Чтение каталога и административный DDL требуют разных решений. Открыть исходные данные, результат и полную современную программу.

Общий маршрут переноса: подключение, кодировка и выбор API; запросы, ошибки и строки результата. Современные операции mysqli имеют отдельные карточки справочника.

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

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

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

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

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