Глава 98 · От первой C-переменной до полного API
FFI PHP: полный справочник CData, CType, памяти, DLL/SO и ABI
От первой C-переменной до безопасной обёртки native-библиотеки: все 47 официальных страниц, 33 метода, CType-константы, указатели, строки, callbacks, preload и реальные ошибки.
Сначала осязаемый результат: три числа лежат в C-памяти, PHP их читает
FFI нужен, когда полезная функция уже существует в DLL/SO или устройство поставляется с C API, а писать и собирать полноценное PHP-расширение пока нецелесообразно. Первый опыт не загружает чужую библиотеку: мы создаём C-массив фиксированной длины, записываем значения и получаем понятную сумму.
$ffi->new("int[3]")выделяет непрерывный C-буфер для трёх int- Индексы 0, 1 и 2 обращаются к фиксированным ячейкам; четвёртой ячейки нет
- PHP читает значения через FFI\CData и складывает обычные числа
- Когда owned CData больше не нужен, PHP освобождает его память
<?php
declare(strict_types=1);
$ffi = FFI::cdef();
$measurements = $ffi->new('int[3]');
$measurements[0] = 18;
$measurements[1] = 21;
$measurements[2] = 24;
echo 'count: ', count($measurements), "\n";
echo 'total: ', $measurements[0] + $measurements[1] + $measurements[2], "\n";
Ожидаемый результат
count: 3
total: 63
Результат виден без C-компилятора и внешней DLL. Сходство с PHP-массивом ограничено: C-массив нельзя расширить, и выход за границу опаснее обычной ошибки индекса.
Когда FFI даёт реальный выигрыш, а когда выбрать другой инструмент
| Задача | Подход | Почему |
|---|---|---|
| Поставщик дал DLL/SO и C header для сканера, прибора или кодека | FFI | Можно вызвать существующий стабильный C ABI без написания Zend extension. |
| Нужно один раз запустить Python/Node/C CLI и получить JSON | proc_open/exec | Отдельный процесс изолирует адресное пространство; FFI для этого не нужен. |
| Нужен переносимый HTTP/API-клиент | PHP/cURL/Composer-пакет | Сетевой протокол выше уровнем, безопаснее и проще развернуть. |
| Высоконагруженное расширение с глубоким доступом к Zend API | Нативное PHP-расширение | FFI не заменяет extension API и хуже подходит для постоянного публичного контракта. |
| Обычная обработка массивов/строк внутри приложения | PHP | Переход через FFI добавляет ABI, память и риск без полезной границы. |
FFI выполняет native-код внутри того же процесса PHP. Это позволяет передавать указатели без сериализации, но ошибка памяти может уронить весь worker. Вызов через CLI/сервис медленнее на границе, зато процесс можно ограничить, перезапустить и наблюдать отдельно.
Четыре сущности, которые нельзя смешивать: объявление, тип, память и указатель
| Сущность | Физический смысл | Пример |
|---|---|---|
FFI | Привязка объявлений C к типам/символам библиотеки | $ffi = FFI::cdef(...) |
FFI\CType | Схема размещения: kind, size, alignment, поля, параметры | $type = $ffi->type("Order") |
FFI\CData | Конкретные байты/указатель, живущие по правилам owned/unmanaged | $row = $ffi->new("Order") |
| C-указатель | Адрес, который не сообщает длину и обычно не владеет памятью | $ptr = FFI::addr($row) |
<?php
declare(strict_types=1);
$ffi = FFI::cdef('typedef struct { int id; double price; int stock; } ProductRow;');
$product = $ffi->new('ProductRow');
$product->id = 104;
$product->price = 1290.50;
$product->stock = 7;
echo "product {$product->id}: {$product->price}, stock {$product->stock}\n";
Ожидаемый результат
product 104: 1290.5, stock 7
Структура похожа на органайзер с подписанными ячейками, но расположение определяет ABI: между полями возможен padding. Имена/типы/offset читаются через CType, а не угадываются.
Установка и режимы: почему «extension загружено» ещё не означает «веб-коду всё разрешено»
| Проверка | Что должно быть |
|---|---|
| Сборка Linux/macOS | PHP собран с --with-ffi, установлена libffi. |
| Windows | В php.ini конкретного SAPI подключён совместимый php_ffi.dll. |
extension_loaded("FFI") | Расширение действительно загружено этим CLI/FPM/Apache-процессом. |
ini_get("ffi.enable") | false, true либо рекомендуемая ограниченная политика preload. |
ini_get("ffi.preload") | Список доверенных header-файлов для startup preload, если используется scope. |
Значение preload разрешает FFI API в CLI и предзагруженных файлах; обычный веб-код получает подготовленные CData/scope вместо права разбирать произвольный header. Директивы имеют уровень INI_SYSTEM. Локальные проверки этой главы включают FFI только параметрами отдельного процесса и не меняют общий php.ini.
Навигация от задачи: какой метод открыть
| Мне нужно… | Начать с | Проверить рядом |
|---|---|---|
| Описать функции DLL/SO строкой | FFI::cdef | FFI::load, режим ffi.enable |
| Разобрать header один раз при старте | FFI::load | FFI::scope, opcache.preload |
| Выделить scalar/array/struct | FFI::new | FFI::free, owned/persistent |
| Передать out-параметр | FFI::addr | FFI::isNull, время жизни источника |
| Превратить C char* в PHP string | FFI::string | FFI::memcpy, длина/NUL/кодировка |
| Проверить размер и layout | FFI::sizeof | FFI::alignof, getStructFieldOffset |
| Исследовать неизвестный CType | FFI\CType::getKind | После kind — array/pointer/struct/function методы |
| Понять сигнатуру callback | FFI\CType::getFuncParameterCount | FFI\CType::getFuncReturnType, ABI |
Практический слой: один объект прячет platform name и повторное cdef
В рабочем сервисе вызовы FFI не размазывают по контроллерам. Обёртка один раз выбирает библиотеку, объявляет ровно используемые символы и отдаёт метод с обычным PHP-типом. Ниже системная abs — безопасная маленькая модель такой границы; у реального прибора рядом будут версия протокола, диапазоны, коды ошибок и тестовый fixture.
<?php
declare(strict_types=1);
final class NativeMath
{
private FFI $ffi;
public function __construct()
{
$library = match (PHP_OS_FAMILY) {
'Windows' => 'msvcrt.dll',
'Darwin' => 'libSystem.B.dylib',
default => 'libc.so.6',
};
$this->ffi = FFI::cdef('int abs(int value);', $library);
}
public function absolute(int $value): int
{
return $this->ffi->abs($value);
}
}
$math = new NativeMath();
echo $math->absolute(-27), "\n";
Ожидаемый результат
27
Остальному приложению не нужно знать имя DLL/SO и C-сигнатуру. В production объект создают через контейнер/фабрику и не принимают название библиотеки от клиента.
Этот выигрыш связан с композицией и dependency injection: native-адаптер можно заменить тестовым без загрузки DLL.
Владение и время жизни: owned, unmanaged, persistent и производные указатели
| Создание/операция | Кто освобождает | Главная ловушка |
|---|---|---|
$ffi->new($type) | PHP после исчезновения последней ссылки | Производный pointer/cast не обязан удержать owner; owner храните явно. |
$ffi->new($type, false) | Ваш код через FFI::free ровно один раз | Утечка, double free, use-after-free. |
persistent: true | Жизненный цикл процесса/preload | Память остаётся между запросами worker; нельзя привязывать к данным одного пользователя. |
| Указатель, вернувшийся из DLL | Определяет документация DLL | Нельзя автоматически free память чужим allocator. |
addr/cast | Не владеют исходной памятью | Адрес остаётся, когда источник уже уничтожен. |
Реальная сложность: PHP array строк нельзя просто передать как const char**
C-функция с параметром const char *const *words ждёт массив указателей, а каждый указатель — отдельный живой NUL-terminated буфер. Обычный PHP array хранит zval и не совпадает с таким layout. Нужно создать оба уровня и удерживать buffers до конца native-вызова.
<?php
declare(strict_types=1);
$words = ['red', 'green', 'blue'];
$buffers = [];
$ffi = FFI::cdef();
$pointers = $ffi->new('char*[' . count($words) . ']');
foreach ($words as $index => $word) {
$buffers[$index] = $ffi->new('char[' . (strlen($word) + 1) . ']');
$bytes = $word . "\0";
FFI::memcpy($buffers[$index], $bytes, strlen($bytes));
$pointers[$index] = $ffi->cast('char*', FFI::addr($buffers[$index][0]));
}
foreach ($pointers as $pointer) {
echo FFI::string($pointer), "\n";
}
Ожидаемый результат
red
green
blue
Массив buffers не является мусором: он удерживает владельцев памяти, на которую смотрит pointers. Вызов DLL поместили бы между сборкой и последним чтением; после него объекты owned освободятся автоматически.
C-строка, бинарный буфер и кодировка — три разных договора
| Договор | Как читать | Где ошибка |
|---|---|---|
char* + NUL | FFI::string($ptr) читает до первого нулевого байта | Если NUL нет в доступной памяти, чтение выходит за границу. |
void*/char* + length | FFI::string($ptr, $length) копирует ровно length байтов | Длина больше буфера читает чужую память. |
| Текст API | После копирования отдельно применяют известную кодировку | char не означает UTF-8; iconv/mbstring требует правильной исходной кодировки. |
| Бинарный результат | Оставляют строкой байтов; для транспорта hex/Base64 | Нельзя использовать strlen Unicode-символов как число элементов wide-char. |
Связанные главы: строки и байты, границы кодировок, многобайтовый текст.
Структуры и ABI: почему совпавшие имена полей ещё ничего не доказывают
Layout зависит от разрядности, компилятора, packing, calling convention и типов вроде long/size_t. Для передачи структуры фиксируют оригинальный header и целевую ABI, затем проверяют kind/size/alignment/offset/type. Ручное «на моей машине поле было на байте 8» — не переносимый договор.
| Вопрос | Инструмент |
|---|---|
| Сколько байтов занимает тип? | FFI::sizeof / FFI\CType::getSize |
| Как выровнять начало? | FFI::alignof / FFI\CType::getAlignment |
| Какие поля объявлены? | FFI\CType::getStructFieldNames |
| Где лежит поле? | FFI\CType::getStructFieldOffset |
| Каков его тип? | FFI\CType::getStructFieldType |
| Как вызывается функция? | FFI\CType::getFuncABI и getFuncParameter* |
Ошибки по слоям: что можно поймать, а что способно завершить процесс
<?php
declare(strict_types=1);
try {
FFI::cdef('this is not a C declaration');
} catch (FFI\ParserException $error) {
echo "C parse error\n";
}
try {
$ffi = FFI::cdef();
$ffi->type('int')->getArrayLength();
} catch (FFI\Exception $error) {
echo "type mismatch\n";
}
Ожидаемый результат
C parse error
type mismatch
Обе ошибки остаются внутри проверяемой модели FFI. Разыменование протухшего указателя, неверная длина memcpy или несовместимая ABI могут не дать PHP шанса выполнить catch.
| Слой | Пример | Реакция |
|---|---|---|
| PHP-вызов | string вместо int-параметра метода | TypeError/ValueError; исправить валидацию. |
| C parser | неполная/неподдерживаемая декларация | FFI\ParserException; сверить минимальный header. |
| FFI contract | нет scope/символа, метод CType не того kind | FFI\Exception; диагностировать библиотеку/схему. |
| Native ABI/память | неверный pointer, размер, calling convention | Crash/corruption; воспроизводить вне web worker, включить guard process. |
| Бизнес-результат DLL | код ошибки/NULL | Читать документацию библиотеки; isNull и код ошибки — отдельные проверки. |
Callbacks PHP → C: работают не везде, дороже вызова и удерживают ресурсы
Официальный пример показывает присваивание PHP Closure C-указателю функции и одновременно предупреждает: поддержка зависит от платформы libffi, механизм неэффективен и оставляет ресурсы до конца request. Поэтому callback используют только когда C API действительно требует его, минимизируют число/время жизни и не выбрасывают PHP-исключение через C-границу.
<?php
declare(strict_types=1);
$ffi = FFI::cdef();
$holder = $ffi->new('struct { int (*apply)(int value); }');
$holder->apply = static fn (int $value): int => $value * 3;
echo ($holder->apply)(7), "\n";
Ожидаемый результат
21
Этот локальный runtime поддерживает callback. Для production сначала проверяют целевую платформу; Closure и holder держат живыми столько, сколько C-код способен вызвать указатель.
Preloading и scope: разобрать доверенный header на старте, а не в каждом запросе
Официальный complete example связывает четыре части: системный ini, header с FFI_SCOPE/FFI_LIB, preload.php с FFI::load и прикладной wrapper с FFI::scope. Смысл — заранее ограничить декларации и не парсить их в веб-запросе. На Windows имя библиотеки будет другим; opcache.preload_user и права процесса настраиваются отдельно.
php.ini:
ffi.enable=preload
opcache.preload=/app/preload.php
native.h:
#define FFI_SCOPE "NATIVE_MATH"
#define FFI_LIB "libc.so.6"
int abs(int value);
preload.php:
<?php
FFI::load(__DIR__ . '/native.h');
application.php:
<?php
$ffi = FFI::scope('NATIVE_MATH');
echo $ffi->abs(-8), "\n";
Это конфигурационный проект, а не один самодостаточный CLI-файл. Его проверяют при старте конкретного FPM/Apache окружения: успешный application.php печатает 8.
Связанные методы: FFI::load и FFI::scope. Значение ffi.preload может загружать список header-файлов; при opcache.preload_user официальный мануал отмечает ограничение для FFI::load во время startup.
Модель угроз: FFI — привилегия процесса, а не функция для пользовательского конструктора
- Allow-list. Библиотеки, header, scope и вызываемые операции задаёт код/deployment, а не GET/POST/JSON.
- Минимальный header. Объявляйте только используемые символы; это уменьшает поверхность ошибки и аудита.
- Отдельный worker. Рискованную/нестабильную vendor DLL разумно вынести в локальный сервис с таймаутом и рестартом.
- Ограниченные права. Native-код получает права PHP-процесса, доступ к памяти и системным ресурсам.
- Версионный комплект. Header, DLL/SO, архитектура, calling convention и wrapper развёртываются вместе.
- Никаких секретов в dump. FFI-структуры/указатели не отправляют в var_dump публичного ответа.
Производительность: измерять весь путь и кешировать описание, а не обещать ускорение
Стоимость состоит из парсинга C declarations, динамической загрузки/поиска символов, преобразования PHP↔C, копирования буферов и собственно native-функции. FFI оправдан, когда тяжёлая полезная работа уже эффективно реализована в библиотеке. Для мелкой арифметики переход может быть дороже PHP.
| Приём | Практическая причина |
|---|---|
| Создать binding один раз на объект/процесс | Не повторять cdef и поиск символов внутри цикла строк заказа. |
| Передавать крупный буфер с явной длиной | Уменьшить число переходов, не теряя bounds contract. |
| Измерять hrtime вокруг законченной операции | Сравнивать одинаковый результат с учётом копирования и ошибок. |
| Не включать persistent без модели worker | Экономия allocation не оправдывает межзапросную утечку состояния. |
Инструмент измерения: hrtime(). Производительность не отменяет проверку памяти и ABI.
Повторяющиеся жизненные проблемы из обсуждений разработчиков
| Симптом | Настоящая причина | Что проверять |
|---|---|---|
| PHP array не подходит к const char** | zval-массив не является C-массивом указателей | Создать char buffers + char*[], удерживать owners, передать count. |
| Failed resolving C function | Символ не экспортирован, неверная библиотека/header либо смешаны FFI_SCOPE и cdef | nm/dumpbin, архитектура, имя символа, минимальный header, один способ загрузки. |
| Attempt to perform assign pointer to owned C data | Перепутаны владение и уровень указателя | Отдельный owner buffer, совместимый cast, жизнь owner дольше pointer. |
| Heap corrupted после free | Освободили managed/вложенный/чужой pointer или дважды | Кто alloc/free по C API; ручной free только своего unmanaged allocation. |
| Работает в C++, падает в PHP | Различается ABI, name mangling, struct layout, calling convention | extern "C", header, compiler ABI, разрядность, field offsets. |
| Try/catch не сработал | Процесс упал в native-коде до PHP exception | CLI fixture, guard process, минимальный вход, debugger/sanitizer библиотеки. |
Обсуждения используются как карта реальных затруднений. Сигнатуры и нормативное поведение этой главы берутся из PHP Manual и php-src 8.5.11; чужие ответы не копируются как готовый контракт.
Полная карта классов: FFI, CData, CType и два уровня исключений
| Тип | Что хранит / как получается |
|---|---|
FFI | Привязку C declarations/library; cdef, load или scope. |
FFI\CData | Native scalar/array/struct/pointer и перегруженные операции доступа; напрямую через new/return DLL. |
FFI\CType | Описание C type; type/typeof/arrayType и специализированные get*. |
FFI\Exception | Ошибки операций/типов/scope FFI; наследник Error. |
FFI\ParserException | Ошибка разбора C declarations; наследник FFI\Exception. |
CData и CType нельзя создавать обычным new FFI\CData(). Их выдаёт FFI. У CData официальная страница описывает перегруженный доступ к полям/индексам/вызовам, поэтому отсутствие обычных методов в Reflection не означает отсутствие поведения.
Все 38 runtime-констант: biggest alignment, kinds, attributes и ABI
FFI::__BIGGEST_ALIGNMENT__ в PHP 8.5.11 равен 8 на зафиксированной x64 Windows-сборке. Это характеристика runtime, не универсальная константа всех платформ.
TYPE_* — семейство CType
| Константа | PHP 8.5.11 | Как читать |
|---|---|---|
FFI\CType::TYPE_VOID | 0 | код, который интерпретируют только в соответствующем семействе |
FFI\CType::TYPE_FLOAT | 1 | код, который интерпретируют только в соответствующем семействе |
FFI\CType::TYPE_DOUBLE | 2 | код, который интерпретируют только в соответствующем семействе |
FFI\CType::TYPE_UINT8 | 3 | код, который интерпретируют только в соответствующем семействе |
FFI\CType::TYPE_SINT8 | 4 | код, который интерпретируют только в соответствующем семействе |
FFI\CType::TYPE_UINT16 | 5 | код, который интерпретируют только в соответствующем семействе |
FFI\CType::TYPE_SINT16 | 6 | код, который интерпретируют только в соответствующем семействе |
FFI\CType::TYPE_UINT32 | 7 | код, который интерпретируют только в соответствующем семействе |
FFI\CType::TYPE_SINT32 | 8 | код, который интерпретируют только в соответствующем семействе |
FFI\CType::TYPE_UINT64 | 9 | код, который интерпретируют только в соответствующем семействе |
FFI\CType::TYPE_SINT64 | 10 | код, который интерпретируют только в соответствующем семействе |
FFI\CType::TYPE_ENUM | 11 | enum |
FFI\CType::TYPE_BOOL | 12 | код, который интерпретируют только в соответствующем семействе |
FFI\CType::TYPE_CHAR | 13 | код, который интерпретируют только в соответствующем семействе |
FFI\CType::TYPE_POINTER | 14 | указатель |
FFI\CType::TYPE_FUNC | 15 | сигнатура функции |
FFI\CType::TYPE_ARRAY | 16 | фиксированный массив |
FFI\CType::TYPE_STRUCT | 17 | struct/union |
ATTR_* — битовая маска свойств
| Константа | PHP 8.5.11 | Как читать |
|---|---|---|
FFI\CType::ATTR_CONST | 1 | const-qualified type |
FFI\CType::ATTR_INCOMPLETE_TAG | 2 | код, который интерпретируют только в соответствующем семействе |
FFI\CType::ATTR_VARIADIC | 4 | variadic function |
FFI\CType::ATTR_INCOMPLETE_ARRAY | 8 | код, который интерпретируют только в соответствующем семействе |
FFI\CType::ATTR_VLA | 16 | код, который интерпретируют только в соответствующем семействе |
FFI\CType::ATTR_UNION | 32 | union |
FFI\CType::ATTR_PACKED | 64 | packed layout |
FFI\CType::ATTR_MS_STRUCT | 128 | код, который интерпретируют только в соответствующем семействе |
FFI\CType::ATTR_GCC_STRUCT | 256 | код, который интерпретируют только в соответствующем семействе |
ABI_* — calling convention
| Константа | PHP 8.5.11 | Как читать |
|---|---|---|
FFI\CType::ABI_DEFAULT | 0 | ABI по умолчанию текущей платформы |
FFI\CType::ABI_CDECL | 1 | cdecl |
FFI\CType::ABI_FASTCALL | 2 | fastcall |
FFI\CType::ABI_THISCALL | 3 | код, который интерпретируют только в соответствующем семействе |
FFI\CType::ABI_STDCALL | 4 | stdcall |
FFI\CType::ABI_PASCAL | 5 | код, который интерпретируют только в соответствующем семействе |
FFI\CType::ABI_REGISTER | 6 | код, который интерпретируют только в соответствующем семействе |
FFI\CType::ABI_MS | 7 | код, который интерпретируют только в соответствующем семействе |
FFI\CType::ABI_SYSV | 8 | код, который интерпретируют только в соответствующем семействе |
FFI\CType::ABI_VECTORCALL | 9 | vectorcall |
Полный справочник методов по категориям
Загрузка и scope
FFI::cdef— Разобрать объявления C и при необходимости связать их с DLL/SO, получив объект вызова библиотеки.FFI::load— Загрузить объявления из отдельного заголовка с FFI_SCOPE/FFI_LIB вместо длинной строки в PHP.FFI::scope— Получить уже разобранную при preloading именованную привязку без повторного парсинга заголовка.
Память и указатели
FFI::new— Выделить C-память заданного типа и явно выбрать управляемое или ручное владение.FFI::free— Освободить ровно один ранее созданный unmanaged-буфер и больше его не использовать.FFI::cast— Посмотреть на ту же область памяти через другой совместимый C-тип без копирования и без передачи владения.FFI::addr— Получить указатель на существующий CData, например для out-параметра C-функции.
Типы, размер и layout
FFI::type— Разобрать C-декларацию типа в объект FFI\CType для повторного создания и анализа.FFI::typeof— Узнать фактический C-тип уже созданного FFI\CData.FFI::arrayType— Собрать многомерный C-массив из базового CType и массива размеров.FFI::sizeof— Узнать число байтов, занимаемых CData или CType на текущей ABI-платформе.FFI::alignof— Узнать требуемое выравнивание C-типа или значения на текущей ABI-платформе.
Буферы и проверки
FFI::memcpy— Скопировать точное число сырых байтов между PHP-строкой/CData и C-буфером.FFI::memcmp— Лексикографически сравнить точное число сырых байтов двух областей памяти.FFI::memset— Заполнить точное число байтов C-буфера одним байтовым значением.FFI::string— Скопировать C-буфер char в обычную PHP-строку по длине или до нулевого байта.FFI::isNull— Отличить нулевой C-указатель от указателя на реальную область памяти.
Инспекция FFI\CType
FFI\CType::getName— Получить каноническое имя описанного C-типа.FFI\CType::getKind— Получить код семейства CType: scalar, pointer, array, function или struct/union.FFI\CType::getSize— Получить размер CType в байтах без создания CData.FFI\CType::getAlignment— Получить требуемое выравнивание CType в байтах.FFI\CType::getAttributes— Получить битовую маску const/variadic/union/packed и других атрибутов типа.FFI\CType::getEnumKind— Узнать целочисленный вид, которым текущая ABI представляет enum.FFI\CType::getArrayElementType— Перейти от CType массива к типу одного элемента.FFI\CType::getArrayLength— Получить число элементов одного измерения CType массива.FFI\CType::getPointerType— Перейти от CType указателя к типу, на который он указывает.FFI\CType::getStructFieldNames— Получить имена полей struct/union в порядке объявления.FFI\CType::getStructFieldOffset— Получить байтовое смещение названного поля struct/union с учётом padding.FFI\CType::getStructFieldType— Получить CType названного поля struct/union.FFI\CType::getFuncABI— Получить код calling convention типа C-функции.FFI\CType::getFuncReturnType— Получить CType возвращаемого значения типа C-функции.FFI\CType::getFuncParameterCount— Получить число параметров типа C-функции.FFI\CType::getFuncParameterType— Получить CType параметра C-функции по нулевому индексу.
Маршрут обучения: от безопасной памяти к своей native-интеграции
| Шаг | Практический результат | Критерий готовности |
|---|---|---|
| 1. scalar/array/struct | Создать CData и вывести его поля | Понимаете фиксированный размер и отличие PHP array. |
| 2. CType/layout | Проверить kind/size/alignment/offset | Не хардкодите ABI чужой платформы. |
| 3. strings/buffers | Передать bytes + length/NUL | Различаете бинарные байты, текст и encoding. |
| 4. pointers/lifetime | Out-параметр и char** с owners | Можете назвать владельца и момент освобождения каждого буфера. |
| 5. cdef/load | Вызвать один чистый символ тестовой библиотеки | Header, DLL/SO, архитектура и результат зафиксированы. |
| 6. wrapper/tests | Обычный PHP-интерфейс + fake adapter | Контроллер не знает FFI; ошибки преобразованы в domain result. |
| 7. preload/isolation | Scope или отдельный native worker | Веб-пользователь не управляет declarations/path, crash локализован. |
Граница полноты этой ветки
| Инвентарь | Покрытие |
|---|---|
| Официальные страницы book.ffi | 47/47, включая setup, три examples и пять class/exception страниц. |
| Официальные страницы методов | 33/33 отдельных карточки с сигнатурой, параметрами, результатом, риском и собственным примером. |
| Runtime-типы | 5/5: FFI, CData, CType, Exception, ParserException. |
| CType-константы | 37/37 плюс FFI::__BIGGEST_ALIGNMENT__. |
| Исполнение | Новые определения проверяются отдельным PHP 8.5.11 процессом с process-only FFI DLL; внешняя production DLL не заявлена. |
Функции и методы этой темы
Откройте карточку, чтобы увидеть договор функции, примеры, ограничения и связанные инструменты.
FFI::cdefРазобрать объявления C и при необходимости связать их с DLL/SO, получив объект вызова библиотеки.
public static function FFI::cdef(string $code = "", ?string $lib = null): FFIРазобрать объявления C и при необходимости связать их с DLL/SO, получив объект вызова библиотеки.
| Параметр | Что именно передать |
|---|---|
$code | Последовательность деклараций C. Обычные include и произвольные макросы препроцессора не поддерживаются. По умолчанию: ''. |
$lib | Путь/имя совместимой shared library либо null для поиска символов в глобальной области на поддерживаемой платформе. По умолчанию: null. |
| Часть контракта | Что получить |
|---|---|
| Сигнатура | public static function FFI::cdef(string $code = "", ?string $lib = null): FFI |
| Результат | Объект FFI, через который доступны объявленные типы, переменные и функции. |
| Ошибки PHP | Неверные PHP-типы дают TypeError/ValueError; ошибка C-декларации — FFI\ParserException; неподходящий CType, scope, символ или операция — FFI\Exception. Нарушение ABI/памяти может завершить процесс без catch. |
| Доступность | PHP 7.4+; пример проверен изолированно на PHP 8.5.11 с process-only ffi.enable=1. |
<?php
declare(strict_types=1);
function cRuntimeLibrary(): string
{
return match (PHP_OS_FAMILY) {
'Windows' => 'msvcrt.dll',
'Darwin' => 'libSystem.B.dylib',
default => 'libc.so.6',
};
}
$ffi = FFI::cdef('int abs(int value);', cRuntimeLibrary());
echo $ffi->abs(-17), "\n";
Ожидаемый результат
17
Объявление содержит ровно нужный символ. Имя runtime-библиотеки выбирается по ОС; произвольный путь от HTTP-клиента здесь недопустим.
Вернуться к карте FFI; базовые понятия: переменная, массив, функция, исключение.
FFI::loadЗагрузить объявления из отдельного заголовка с FFI_SCOPE/FFI_LIB вместо длинной строки в PHP.
public static function FFI::load(string $filename): ?FFIЗагрузить объявления из отдельного заголовка с FFI_SCOPE/FFI_LIB вместо длинной строки в PHP.
| Параметр | Что именно передать |
|---|---|
$filename | Локальный доверенный header. Специальные FFI_SCOPE и FFI_LIB разрешены; путь пользователя сюда не передают. |
| Часть контракта | Что получить |
|---|---|
| Сигнатура | public static function FFI::load(string $filename): ?FFI |
| Результат | Объект FFI либо null для header, предназначенного только для регистрации именованного scope при preload. |
| Ошибки PHP | Неверные PHP-типы дают TypeError/ValueError; ошибка C-декларации — FFI\ParserException; неподходящий CType, scope, символ или операция — FFI\Exception. Нарушение ABI/памяти может завершить процесс без catch. |
| Доступность | PHP 7.4+; пример проверен изолированно на PHP 8.5.11 с process-only ffi.enable=1. |
<?php
declare(strict_types=1);
function cRuntimeLibrary(): string
{
return match (PHP_OS_FAMILY) {
'Windows' => 'msvcrt.dll',
'Darwin' => 'libSystem.B.dylib',
default => 'libc.so.6',
};
}
$header = '#define FFI_LIB "' . cRuntimeLibrary() . '"' . "\nint abs(int value);\n";
$path = __DIR__ . '/manual_math.h';
file_put_contents($path, $header);
$ffi = FFI::load($path);
echo $ffi->abs(-9), "\n";
Ожидаемый результат
9
FFI_LIB — специально поддерживаемая директива load. Обычный include/macros FFI parser не выполняет; header хранится вместе с кодом приложения.
Вернуться к карте FFI; базовые понятия: переменная, массив, функция, исключение.
FFI::scopeПолучить уже разобранную при preloading именованную привязку без повторного парсинга заголовка.
public static function FFI::scope(string $name): FFIПолучить уже разобранную при preloading именованную привязку без повторного парсинга заголовка.
| Параметр | Что именно передать |
|---|---|
$name | Имя scope или поля — точный идентификатор из header/типа, а не произвольное имя операции приложения. |
| Часть контракта | Что получить |
|---|---|
| Сигнатура | public static function FFI::scope(string $name): FFI |
| Результат | Объект FFI, через который доступны объявленные типы, переменные и функции. |
| Ошибки PHP | Неверные PHP-типы дают TypeError/ValueError; ошибка C-декларации — FFI\ParserException; неподходящий CType, scope, символ или операция — FFI\Exception. Нарушение ABI/памяти может завершить процесс без catch. |
| Доступность | PHP 7.4+; пример проверен изолированно на PHP 8.5.11 с process-only ffi.enable=1. |
<?php
declare(strict_types=1);
try {
FFI::scope('MANUAL_SCOPE_NOT_PRELOADED');
} catch (FFI\Exception $error) {
echo "scope not loaded\n";
}
Ожидаемый результат
scope not loaded
Рабочий scope создаётся на старте через ffi.preload/FFI_SCOPE. Здесь показан реальный отказ текущего процесса, который приложение обязано диагностировать.
Вернуться к карте FFI; базовые понятия: переменная, массив, функция, исключение.
FFI::newВыделить C-память заданного типа и явно выбрать управляемое или ручное владение.
public function FFI::new(FFI\CType|string $type, bool $owned = true, bool $persistent = false): ?FFI\CDataВыделить C-память заданного типа и явно выбрать управляемое или ручное владение.
| Параметр | Что именно передать |
|---|---|
$type | C-декларация либо уже созданный FFI\CType. Размеры и уровень указателя должны совпадать с реальной ABI. |
$owned | true связывает время жизни памяти с CData; false требует ровно одного FFI::free(). По умолчанию: true. |
$persistent | Постоянное выделение для preload/долгоживущего процесса; не делает указатель безопасным и требует отдельной дисциплины жизненного цикла. По умолчанию: false. |
| Часть контракта | Что получить |
|---|---|
| Сигнатура | public function FFI::new(FFI\CType|string $type, bool $owned = true, bool $persistent = false): ?FFI\CData |
| Результат | Новый FFI\CData. Его тип и владение определяет конкретный метод; это не обычная PHP-переменная. |
| Ошибки PHP | Неверные PHP-типы дают TypeError/ValueError; ошибка C-декларации — FFI\ParserException; неподходящий CType, scope, символ или операция — FFI\Exception. Нарушение ABI/памяти может завершить процесс без catch. |
| Доступность | PHP 7.4+; пример проверен изолированно на PHP 8.5.11 с process-only ffi.enable=1. |
<?php
declare(strict_types=1);
$ffi = FFI::cdef();
$numbers = $ffi->new('int[3]');
$numbers[0] = 4;
$numbers[1] = 7;
$numbers[2] = 9;
echo $numbers[0] + $numbers[1] + $numbers[2], "\n";
Ожидаемый результат
20
Это C-память фиксированной длины, хотя синтаксис индексов похож на PHP-массив. Индекс 3 уже вышел бы за границу.
Вернуться к карте FFI; базовые понятия: переменная, массив, функция, исключение.
FFI::freeОсвободить ровно один ранее созданный unmanaged-буфер и больше его не использовать.
public static function FFI::free(FFI\CData &$ptr): voidОсвободить ровно один ранее созданный unmanaged-буфер и больше его не использовать.
| Параметр | Что именно передать |
|---|---|
$ptr по ссылке | CData/CType или исходное число/указатель по контракту метода. Источник обязан жить дольше любых производных указателей/cast. |
| Часть контракта | Что получить |
|---|---|
| Сигнатура | public static function FFI::free(FFI\CData &$ptr): void |
| Результат | Полезного значения нет; видимый результат — изменённая или освобождённая область памяти. |
| Ошибки PHP | Неверные PHP-типы дают TypeError/ValueError; ошибка C-декларации — FFI\ParserException; неподходящий CType, scope, символ или операция — FFI\Exception. Нарушение ABI/памяти может завершить процесс без catch. |
| Доступность | PHP 7.4+; пример проверен изолированно на PHP 8.5.11 с process-only ffi.enable=1. |
<?php
declare(strict_types=1);
$ffi = FFI::cdef();
$value = $ffi->new('int', owned: false);
$value->cdata = 42;
echo "before free: {$value->cdata}\n";
FFI::free($value);
echo "freed\n";
Ожидаемый результат
before free: 42
freed
После free переменную намеренно не читаем и не освобождаем повторно. Для owned:true ручной free не нужен.
Вернуться к карте FFI; базовые понятия: переменная, массив, функция, исключение.
FFI::castПосмотреть на ту же область памяти через другой совместимый C-тип без копирования и без передачи владения.
public function FFI::cast(FFI\CType|string $type, FFI\CData|int|float|bool|null &$ptr): ?FFI\CDataПосмотреть на ту же область памяти через другой совместимый C-тип без копирования и без передачи владения.
| Параметр | Что именно передать |
|---|---|
$type | C-декларация либо уже созданный FFI\CType. Размеры и уровень указателя должны совпадать с реальной ABI. |
$ptr по ссылке | CData/CType или исходное число/указатель по контракту метода. Источник обязан жить дольше любых производных указателей/cast. |
| Часть контракта | Что получить |
|---|---|
| Сигнатура | public function FFI::cast(FFI\CType|string $type, FFI\CData|int|float|bool|null &$ptr): ?FFI\CData |
| Результат | Новый FFI\CData. Его тип и владение определяет конкретный метод; это не обычная PHP-переменная. |
| Ошибки PHP | Неверные PHP-типы дают TypeError/ValueError; ошибка C-декларации — FFI\ParserException; неподходящий CType, scope, символ или операция — FFI\Exception. Нарушение ABI/памяти может завершить процесс без catch. |
| Доступность | PHP 7.4+; пример проверен изолированно на PHP 8.5.11 с process-only ffi.enable=1. |
<?php
declare(strict_types=1);
$ffi = FFI::cdef();
$value = $ffi->new('int');
$value->cdata = 21;
$pointer = $ffi->cast('int*', FFI::addr($value));
echo $pointer[0], "\n";
Ожидаемый результат
21
Cast не копирует 21 и не продлевает жизнь value. Пример хранит исходный CData до последнего чтения pointer.
Вернуться к карте FFI; базовые понятия: переменная, массив, функция, исключение.
FFI::typeРазобрать C-декларацию типа в объект FFI\CType для повторного создания и анализа.
public function FFI::type(string $type): ?FFI\CTypeРазобрать C-декларацию типа в объект FFI\CType для повторного создания и анализа.
| Параметр | Что именно передать |
|---|---|
$type | C-декларация либо уже созданный FFI\CType. Размеры и уровень указателя должны совпадать с реальной ABI. |
| Часть контракта | Что получить |
|---|---|
| Сигнатура | public function FFI::type(string $type): ?FFI\CType |
| Результат | Описание FFI\CType; само по себе память под значение не выделяет. |
| Ошибки PHP | Неверные PHP-типы дают TypeError/ValueError; ошибка C-декларации — FFI\ParserException; неподходящий CType, scope, символ или операция — FFI\Exception. Нарушение ABI/памяти может завершить процесс без catch. |
| Доступность | PHP 7.4+; пример проверен изолированно на PHP 8.5.11 с process-only ffi.enable=1. |
<?php
declare(strict_types=1);
$ffi = FFI::cdef('typedef struct { int id; double total; char code[8]; } OrderRow;');
$type = $ffi->type('OrderRow');
echo $type->getKind() === FFI\CType::TYPE_STRUCT ? "struct\n" : "other type\n";
echo $type->getSize() > 0 ? "size known\n" : "incomplete type\n";
Ожидаемый результат
struct
size known
CType — схема памяти. Конкретную OrderRow создаёт отдельный new; это разделяет проверку договора и данные.
Вернуться к карте FFI; базовые понятия: переменная, массив, функция, исключение.
FFI::typeofУзнать фактический C-тип уже созданного FFI\CData.
public static function FFI::typeof(FFI\CData &$ptr): FFI\CTypeУзнать фактический C-тип уже созданного FFI\CData.
| Параметр | Что именно передать |
|---|---|
$ptr по ссылке | CData/CType или исходное число/указатель по контракту метода. Источник обязан жить дольше любых производных указателей/cast. |
| Часть контракта | Что получить |
|---|---|
| Сигнатура | public static function FFI::typeof(FFI\CData &$ptr): FFI\CType |
| Результат | Описание FFI\CType; само по себе память под значение не выделяет. |
| Ошибки PHP | Неверные PHP-типы дают TypeError/ValueError; ошибка C-декларации — FFI\ParserException; неподходящий CType, scope, символ или операция — FFI\Exception. Нарушение ABI/памяти может завершить процесс без catch. |
| Доступность | PHP 7.4+; пример проверен изолированно на PHP 8.5.11 с process-only ffi.enable=1. |
<?php
declare(strict_types=1);
$ffi = FFI::cdef();
$values = $ffi->new('double[2]');
$type = FFI::typeof($values);
echo $type->getKind() === FFI\CType::TYPE_ARRAY ? "array\n" : "not array\n";
echo $type->getArrayLength(), " elements\n";
Ожидаемый результат
array
2 elements
typeof читает фактическую схему CData; он не выводит значения элементов.
Вернуться к карте FFI; базовые понятия: переменная, массив, функция, исключение.
FFI::arrayTypeСобрать многомерный C-массив из базового CType и массива размеров.
public static function FFI::arrayType(FFI\CType $type, array $dimensions): FFI\CTypeСобрать многомерный C-массив из базового CType и массива размеров.
| Параметр | Что именно передать |
|---|---|
$type | C-декларация либо уже созданный FFI\CType. Размеры и уровень указателя должны совпадать с реальной ABI. |
$dimensions | Положительные размеры каждого измерения, например [2, 3]. Они определяют реальный объём C-памяти. |
| Часть контракта | Что получить |
|---|---|
| Сигнатура | public static function FFI::arrayType(FFI\CType $type, array $dimensions): FFI\CType |
| Результат | Описание FFI\CType; само по себе память под значение не выделяет. |
| Ошибки PHP | Неверные PHP-типы дают TypeError/ValueError; ошибка C-декларации — FFI\ParserException; неподходящий CType, scope, символ или операция — FFI\Exception. Нарушение ABI/памяти может завершить процесс без catch. |
| Доступность | PHP 7.4+; пример проверен изолированно на PHP 8.5.11 с process-only ffi.enable=1. |
<?php
declare(strict_types=1);
$ffi = FFI::cdef();
$matrixType = FFI::arrayType($ffi->type('int'), [2, 3]);
$matrix = $ffi->new($matrixType);
$matrix[1][2] = 11;
echo $matrixType->getArrayLength(), 'x', $matrixType->getArrayElementType()->getArrayLength(), "\n";
echo $matrix[1][2], "\n";
Ожидаемый результат
2x3
11
Размеры становятся частью C-типа. Это не динамический PHP-массив: расширить матрицу после выделения нельзя.
Вернуться к карте FFI; базовые понятия: переменная, массив, функция, исключение.
FFI::addrПолучить указатель на существующий CData, например для out-параметра C-функции.
public static function FFI::addr(FFI\CData &$ptr): FFI\CDataПолучить указатель на существующий CData, например для out-параметра C-функции.
| Параметр | Что именно передать |
|---|---|
$ptr по ссылке | CData/CType или исходное число/указатель по контракту метода. Источник обязан жить дольше любых производных указателей/cast. |
| Часть контракта | Что получить |
|---|---|
| Сигнатура | public static function FFI::addr(FFI\CData &$ptr): FFI\CData |
| Результат | Новый FFI\CData. Его тип и владение определяет конкретный метод; это не обычная PHP-переменная. |
| Ошибки PHP | Неверные PHP-типы дают TypeError/ValueError; ошибка C-декларации — FFI\ParserException; неподходящий CType, scope, символ или операция — FFI\Exception. Нарушение ABI/памяти может завершить процесс без catch. |
| Доступность | PHP 7.4+; пример проверен изолированно на PHP 8.5.11 с process-only ffi.enable=1. |
<?php
declare(strict_types=1);
$ffi = FFI::cdef();
$count = $ffi->new('int');
$count->cdata = 15;
$pointer = FFI::addr($count);
$pointer[0] += 5;
echo $count->cdata, "\n";
Ожидаемый результат
20
Так моделируется C out-параметр: функция получает адрес и пишет в ту же ячейку. count обязан оставаться живым.
Вернуться к карте FFI; базовые понятия: переменная, массив, функция, исключение.
FFI::sizeofУзнать число байтов, занимаемых CData или CType на текущей ABI-платформе.
public static function FFI::sizeof(FFI\CData|FFI\CType &$ptr): intУзнать число байтов, занимаемых CData или CType на текущей ABI-платформе.
| Параметр | Что именно передать |
|---|---|
$ptr по ссылке | CData/CType или исходное число/указатель по контракту метода. Источник обязан жить дольше любых производных указателей/cast. |
| Часть контракта | Что получить |
|---|---|
| Сигнатура | public static function FFI::sizeof(FFI\CData|FFI\CType &$ptr): int |
| Результат | Целое число в единицах метода; размеры/offset/alignment зависят от ABI и не должны быть захардкожены по примеру с другой платформы. |
| Ошибки PHP | Неверные PHP-типы дают TypeError/ValueError; ошибка C-декларации — FFI\ParserException; неподходящий CType, scope, символ или операция — FFI\Exception. Нарушение ABI/памяти может завершить процесс без catch. |
| Доступность | PHP 7.4+; пример проверен изолированно на PHP 8.5.11 с process-only ffi.enable=1. |
<?php
declare(strict_types=1);
$ffi = FFI::cdef();
$one = $ffi->type('int');
$four = $ffi->type('int[4]');
echo FFI::sizeof($four) === 4 * FFI::sizeof($one) ? "4 elements\n" : "ABI differs\n";
Ожидаемый результат
4 elements
Вывод не обещает, что int всегда равен четырём байтам: он проверяет отношение в текущей ABI.
Вернуться к карте FFI; базовые понятия: переменная, массив, функция, исключение.
FFI::alignofУзнать требуемое выравнивание C-типа или значения на текущей ABI-платформе.
public static function FFI::alignof(FFI\CData|FFI\CType &$ptr): intУзнать требуемое выравнивание C-типа или значения на текущей ABI-платформе.
| Параметр | Что именно передать |
|---|---|
$ptr по ссылке | CData/CType или исходное число/указатель по контракту метода. Источник обязан жить дольше любых производных указателей/cast. |
| Часть контракта | Что получить |
|---|---|
| Сигнатура | public static function FFI::alignof(FFI\CData|FFI\CType &$ptr): int |
| Результат | Целое число в единицах метода; размеры/offset/alignment зависят от ABI и не должны быть захардкожены по примеру с другой платформы. |
| Ошибки PHP | Неверные PHP-типы дают TypeError/ValueError; ошибка C-декларации — FFI\ParserException; неподходящий CType, scope, символ или операция — FFI\Exception. Нарушение ABI/памяти может завершить процесс без catch. |
| Доступность | PHP 7.4+; пример проверен изолированно на PHP 8.5.11 с process-only ffi.enable=1. |
<?php
declare(strict_types=1);
$ffi = FFI::cdef('typedef struct { int id; double total; char code[8]; } OrderRow;');
$type = $ffi->type('OrderRow');
$alignment = FFI::alignof($type);
echo $alignment > 0 ? "positive alignment\n" : "alignment error\n";
echo $type->getSize() % $alignment === 0 ? "size aligned\n" : "check ABI\n";
Ожидаемый результат
positive alignment
size aligned
Конкретное число отличается между ABI. Для безопасного обмена структурой используют фактические sizeof/alignof/offset, а не цифры из чужого компьютера.
Вернуться к карте FFI; базовые понятия: переменная, массив, функция, исключение.
FFI::memcpyСкопировать точное число сырых байтов между PHP-строкой/CData и C-буфером.
public static function FFI::memcpy(FFI\CData &$to, FFI\CData|string &$from, int $size): voidСкопировать точное число сырых байтов между PHP-строкой/CData и C-буфером.
| Параметр | Что именно передать |
|---|---|
$to по ссылке | Начало целевого C-буфера достаточного размера. |
$from по ссылке | Начало исходного C-буфера либо PHP-строка с как минимум указанным количеством байтов. |
$size | Число байтов, которое заведомо помещается во всех участвующих областях. |
| Часть контракта | Что получить |
|---|---|
| Сигнатура | public static function FFI::memcpy(FFI\CData &$to, FFI\CData|string &$from, int $size): void |
| Результат | Полезного значения нет; видимый результат — изменённая или освобождённая область памяти. |
| Ошибки PHP | Неверные PHP-типы дают TypeError/ValueError; ошибка C-декларации — FFI\ParserException; неподходящий CType, scope, символ или операция — FFI\Exception. Нарушение ABI/памяти может завершить процесс без catch. |
| Доступность | PHP 7.4+; пример проверен изолированно на PHP 8.5.11 с process-only ffi.enable=1. |
<?php
declare(strict_types=1);
$ffi = FFI::cdef();
$buffer = $ffi->new('char[6]');
$source = "hello\0";
FFI::memcpy($buffer, $source, strlen($source));
echo FFI::string($buffer), "\n";
Ожидаемый результат
hello
Размер 6 совпадает с буфером и включает NUL. Без проверки длины memcpy не защищает от переполнения.
Вернуться к карте FFI; базовые понятия: переменная, массив, функция, исключение.
FFI::memcmpЛексикографически сравнить точное число сырых байтов двух областей памяти.
public static function FFI::memcmp(FFI\CData|string &$ptr1, FFI\CData|string &$ptr2, int $size): intЛексикографически сравнить точное число сырых байтов двух областей памяти.
| Параметр | Что именно передать |
|---|---|
$ptr1 по ссылке | Первая область памяти или PHP-строка. |
$ptr2 по ссылке | Вторая область памяти или PHP-строка. |
$size | Число байтов, которое заведомо помещается во всех участвующих областях. |
| Часть контракта | Что получить |
|---|---|
| Сигнатура | public static function FFI::memcmp(FFI\CData|string &$ptr1, FFI\CData|string &$ptr2, int $size): int |
| Результат | Отрицательное число, 0 или положительное число. Для равенства проверяют строго === 0; конкретную величину не используют. |
| Ошибки PHP | Неверные PHP-типы дают TypeError/ValueError; ошибка C-декларации — FFI\ParserException; неподходящий CType, scope, символ или операция — FFI\Exception. Нарушение ABI/памяти может завершить процесс без catch. |
| Доступность | PHP 7.4+; пример проверен изолированно на PHP 8.5.11 с process-only ffi.enable=1. |
<?php
declare(strict_types=1);
$first = 'abc';
$same = 'abc';
$later = 'abd';
echo FFI::memcmp($first, $same, 3) === 0 ? "equal\n" : "different\n";
echo FFI::memcmp($first, $later, 3) < 0 ? "abc before abd\n" : "other order\n";
Ожидаемый результат
equal
abc before abd
Для равенства важен только ноль; конкретная отрицательная величина реализационно зависима.
Вернуться к карте FFI; базовые понятия: переменная, массив, функция, исключение.
FFI::memsetЗаполнить точное число байтов C-буфера одним байтовым значением.
public static function FFI::memset(FFI\CData &$ptr, int $value, int $size): voidЗаполнить точное число байтов C-буфера одним байтовым значением.
| Параметр | Что именно передать |
|---|---|
$ptr по ссылке | CData/CType или исходное число/указатель по контракту метода. Источник обязан жить дольше любых производных указателей/cast. |
$value | Байт заполнения; C использует младшие 8 бит числового значения. |
$size | Число байтов, которое заведомо помещается во всех участвующих областях. |
| Часть контракта | Что получить |
|---|---|
| Сигнатура | public static function FFI::memset(FFI\CData &$ptr, int $value, int $size): void |
| Результат | Полезного значения нет; видимый результат — изменённая или освобождённая область памяти. |
| Ошибки PHP | Неверные PHP-типы дают TypeError/ValueError; ошибка C-декларации — FFI\ParserException; неподходящий CType, scope, символ или операция — FFI\Exception. Нарушение ABI/памяти может завершить процесс без catch. |
| Доступность | PHP 7.4+; пример проверен изолированно на PHP 8.5.11 с process-only ffi.enable=1. |
<?php
declare(strict_types=1);
$ffi = FFI::cdef();
$buffer = $ffi->new('char[4]');
FFI::memset($buffer, ord('A'), FFI::sizeof($buffer));
echo FFI::string($buffer, 4), "\n";
Ожидаемый результат
AAAA
Передаётся байт 65, а не строка A. Явная длина позволяет прочитать буфер без завершающего NUL.
Вернуться к карте FFI; базовые понятия: переменная, массив, функция, исключение.
FFI::stringСкопировать C-буфер char в обычную PHP-строку по длине или до нулевого байта.
public static function FFI::string(FFI\CData &$ptr, ?int $size = null): stringСкопировать C-буфер char в обычную PHP-строку по длине или до нулевого байта.
| Параметр | Что именно передать |
|---|---|
$ptr по ссылке | CData/CType или исходное число/указатель по контракту метода. Источник обязан жить дольше любых производных указателей/cast. |
$size | Число байтов, которое заведомо помещается во всех участвующих областях. По умолчанию: null. |
| Часть контракта | Что получить |
|---|---|
| Сигнатура | public static function FFI::string(FFI\CData &$ptr, ?int $size = null): string |
| Результат | Новая PHP-строка — копия указанного числа байтов либо байтов до первого NUL. |
| Ошибки PHP | Неверные PHP-типы дают TypeError/ValueError; ошибка C-декларации — FFI\ParserException; неподходящий CType, scope, символ или операция — FFI\Exception. Нарушение ABI/памяти может завершить процесс без catch. |
| Доступность | PHP 7.4+; пример проверен изолированно на PHP 8.5.11 с process-only ffi.enable=1. |
<?php
declare(strict_types=1);
$ffi = FFI::cdef();
$buffer = $ffi->new('char[3]');
$bytes = "A\0B";
FFI::memcpy($buffer, $bytes, 3);
echo bin2hex(FFI::string($buffer, 3)), "\n";
echo FFI::string($buffer), "\n";
Ожидаемый результат
410042
A
С длиной возвращаются A, NUL и B; без длины чтение останавливается на первом NUL. Это ключевая граница бинарных данных.
Вернуться к карте FFI; базовые понятия: переменная, массив, функция, исключение.
FFI::isNullОтличить нулевой C-указатель от указателя на реальную область памяти.
public static function FFI::isNull(FFI\CData &$ptr): boolОтличить нулевой C-указатель от указателя на реальную область памяти.
| Параметр | Что именно передать |
|---|---|
$ptr по ссылке | CData/CType или исходное число/указатель по контракту метода. Источник обязан жить дольше любых производных указателей/cast. |
| Часть контракта | Что получить |
|---|---|
| Сигнатура | public static function FFI::isNull(FFI\CData &$ptr): bool |
| Результат | true только для нулевого C-указателя, иначе false. |
| Ошибки PHP | Неверные PHP-типы дают TypeError/ValueError; ошибка C-декларации — FFI\ParserException; неподходящий CType, scope, символ или операция — FFI\Exception. Нарушение ABI/памяти может завершить процесс без catch. |
| Доступность | PHP 7.4+; пример проверен изолированно на PHP 8.5.11 с process-only ffi.enable=1. |
<?php
declare(strict_types=1);
$ffi = FFI::cdef();
$null = $ffi->cast('void*', 0);
$value = $ffi->new('int');
$live = FFI::addr($value);
echo FFI::isNull($null) ? "null\n" : "not null\n";
echo FFI::isNull($live) ? "null\n" : "live address\n";
Ожидаемый результат
null
live address
Ненулевой адрес ещё не доказывает, что он действителен и достаточно велик; isNull решает только один вопрос.
Вернуться к карте FFI; базовые понятия: переменная, массив, функция, исключение.
FFI\CType::getNameПолучить каноническое имя описанного C-типа.
public function FFI\CType::getName(): stringПолучить каноническое имя описанного C-типа.
| Параметр | Что именно передать |
|---|---|
| Параметров нет | Метод читает свойства самого CType; сначала убедитесь, что это подходящее семейство типа. |
| Часть контракта | Что получить |
|---|---|
| Сигнатура | public function FFI\CType::getName(): string |
| Результат | Каноническое строковое имя C-типа в представлении текущего FFI parser. |
| Ошибки PHP | Неверные PHP-типы дают TypeError/ValueError; ошибка C-декларации — FFI\ParserException; неподходящий CType, scope, символ или операция — FFI\Exception. Нарушение ABI/памяти может завершить процесс без catch. |
| Доступность | PHP 7.4+; пример проверен изолированно на PHP 8.5.11 с process-only ffi.enable=1. |
<?php
declare(strict_types=1);
$ffi = FFI::cdef();
$type = $ffi->type('int32_t');
echo $type->getName(), "\n";
Ожидаемый результат
int32_t
Имя помогает строить отчёт о договоре, но совместимость ABI проверяют также size/alignment и исходный header.
Вернуться к карте FFI; базовые понятия: переменная, массив, функция, исключение.
FFI\CType::getKindПолучить код семейства CType: scalar, pointer, array, function или struct/union.
public function FFI\CType::getKind(): intПолучить код семейства CType: scalar, pointer, array, function или struct/union.
| Параметр | Что именно передать |
|---|---|
| Параметров нет | Метод читает свойства самого CType; сначала убедитесь, что это подходящее семейство типа. |
| Часть контракта | Что получить |
|---|---|
| Сигнатура | public function FFI\CType::getKind(): int |
| Результат | Метаданные CType: число/маска либо следующий FFI\CType. Метод не создаёт CData и не вызывает внешнюю библиотеку. |
| Ошибки PHP | Неверные PHP-типы дают TypeError/ValueError; ошибка C-декларации — FFI\ParserException; неподходящий CType, scope, символ или операция — FFI\Exception. Нарушение ABI/памяти может завершить процесс без catch. |
| Доступность | PHP 8.1+; пример проверен изолированно на PHP 8.5.11 с process-only ffi.enable=1. |
<?php
declare(strict_types=1);
$ffi = FFI::cdef();
$type = $ffi->type('int[4]');
echo $type->getKind() === FFI\CType::TYPE_ARRAY ? "array\n" : "not array\n";
Ожидаемый результат
array
Проверка kind должна предшествовать специализированным getArray* методам.
Вернуться к карте FFI; базовые понятия: переменная, массив, функция, исключение.
FFI\CType::getSizeПолучить размер CType в байтах без создания CData.
public function FFI\CType::getSize(): intПолучить размер CType в байтах без создания CData.
| Параметр | Что именно передать |
|---|---|
| Параметров нет | Метод читает свойства самого CType; сначала убедитесь, что это подходящее семейство типа. |
| Часть контракта | Что получить |
|---|---|
| Сигнатура | public function FFI\CType::getSize(): int |
| Результат | Целое число в единицах метода; размеры/offset/alignment зависят от ABI и не должны быть захардкожены по примеру с другой платформы. |
| Ошибки PHP | Неверные PHP-типы дают TypeError/ValueError; ошибка C-декларации — FFI\ParserException; неподходящий CType, scope, символ или операция — FFI\Exception. Нарушение ABI/памяти может завершить процесс без catch. |
| Доступность | PHP 8.1+; пример проверен изолированно на PHP 8.5.11 с process-only ffi.enable=1. |
<?php
declare(strict_types=1);
$ffi = FFI::cdef('typedef struct { int id; double total; char code[8]; } OrderRow;');
$type = $ffi->type('OrderRow');
echo $type->getSize() === FFI::sizeof($type) ? "sizes match\n" : "check type\n";
echo $type->getSize() > 0 ? "complete type\n" : "incomplete type\n";
Ожидаемый результат
sizes match
complete type
Число зависит от padding и ABI; в интерфейсе показываем проверенный факт текущего процесса.
Вернуться к карте FFI; базовые понятия: переменная, массив, функция, исключение.
FFI\CType::getAlignmentПолучить требуемое выравнивание CType в байтах.
public function FFI\CType::getAlignment(): intПолучить требуемое выравнивание CType в байтах.
| Параметр | Что именно передать |
|---|---|
| Параметров нет | Метод читает свойства самого CType; сначала убедитесь, что это подходящее семейство типа. |
| Часть контракта | Что получить |
|---|---|
| Сигнатура | public function FFI\CType::getAlignment(): int |
| Результат | Целое число в единицах метода; размеры/offset/alignment зависят от ABI и не должны быть захардкожены по примеру с другой платформы. |
| Ошибки PHP | Неверные PHP-типы дают TypeError/ValueError; ошибка C-декларации — FFI\ParserException; неподходящий CType, scope, символ или операция — FFI\Exception. Нарушение ABI/памяти может завершить процесс без catch. |
| Доступность | PHP 8.1+; пример проверен изолированно на PHP 8.5.11 с process-only ffi.enable=1. |
<?php
declare(strict_types=1);
$ffi = FFI::cdef('typedef struct { int id; double total; char code[8]; } OrderRow;');
$type = $ffi->type('OrderRow');
echo $type->getAlignment() === FFI::alignof($type) ? "alignment matches\n" : "check ABI\n";
echo $type->getAlignment() > 0 ? "positive\n" : "error\n";
Ожидаемый результат
alignment matches
positive
Alignment нужен для корректного размещения структуры в буфере; это не декоративное число.
Вернуться к карте FFI; базовые понятия: переменная, массив, функция, исключение.
FFI\CType::getAttributesПолучить битовую маску const/variadic/union/packed и других атрибутов типа.
public function FFI\CType::getAttributes(): intПолучить битовую маску const/variadic/union/packed и других атрибутов типа.
| Параметр | Что именно передать |
|---|---|
| Параметров нет | Метод читает свойства самого CType; сначала убедитесь, что это подходящее семейство типа. |
| Часть контракта | Что получить |
|---|---|
| Сигнатура | public function FFI\CType::getAttributes(): int |
| Результат | Метаданные CType: число/маска либо следующий FFI\CType. Метод не создаёт CData и не вызывает внешнюю библиотеку. |
| Ошибки PHP | Неверные PHP-типы дают TypeError/ValueError; ошибка C-декларации — FFI\ParserException; неподходящий CType, scope, символ или операция — FFI\Exception. Нарушение ABI/памяти может завершить процесс без catch. |
| Доступность | PHP 8.1+; пример проверен изолированно на PHP 8.5.11 с process-only ffi.enable=1. |
<?php
declare(strict_types=1);
$ffi = FFI::cdef();
$type = $ffi->type('const int');
$attributes = $type->getAttributes();
echo ($attributes & FFI\CType::ATTR_CONST) !== 0 ? "const\n" : "mutable\n";
Ожидаемый результат
mutable
Маску проверяют побитовым &: равенство всей маски одной константе потеряло бы остальные флаги.
Вернуться к карте FFI; базовые понятия: переменная, массив, функция, исключение.
FFI\CType::getEnumKindУзнать целочисленный вид, которым текущая ABI представляет enum.
public function FFI\CType::getEnumKind(): intУзнать целочисленный вид, которым текущая ABI представляет enum.
| Параметр | Что именно передать |
|---|---|
| Параметров нет | Метод читает свойства самого CType; сначала убедитесь, что это подходящее семейство типа. |
| Часть контракта | Что получить |
|---|---|
| Сигнатура | public function FFI\CType::getEnumKind(): int |
| Результат | Метаданные CType: число/маска либо следующий FFI\CType. Метод не создаёт CData и не вызывает внешнюю библиотеку. |
| Ошибки PHP | Неверные PHP-типы дают TypeError/ValueError; ошибка C-декларации — FFI\ParserException; неподходящий CType, scope, символ или операция — FFI\Exception. Нарушение ABI/памяти может завершить процесс без catch. |
| Доступность | PHP 8.1+; пример проверен изолированно на PHP 8.5.11 с process-only ffi.enable=1. |
<?php
declare(strict_types=1);
$ffi = FFI::cdef('typedef enum { MODE_STOP = 0, MODE_RUN = 1 } DeviceMode;');
$type = $ffi->type('DeviceMode');
$kind = $type->getEnumKind();
echo in_array($kind, [FFI\CType::TYPE_SINT32, FFI\CType::TYPE_UINT32], true)
? "32-bit enum\n" : "other ABI\n";
Ожидаемый результат
32-bit enum
Не подменяйте enum обычным int по предположению: фиксируйте header и проверяйте фактическое представление.
Вернуться к карте FFI; базовые понятия: переменная, массив, функция, исключение.
FFI\CType::getArrayElementTypeПерейти от CType массива к типу одного элемента.
public function FFI\CType::getArrayElementType(): FFI\CTypeПерейти от CType массива к типу одного элемента.
| Параметр | Что именно передать |
|---|---|
| Параметров нет | Метод читает свойства самого CType; сначала убедитесь, что это подходящее семейство типа. |
| Часть контракта | Что получить |
|---|---|
| Сигнатура | public function FFI\CType::getArrayElementType(): FFI\CType |
| Результат | Метаданные CType: число/маска либо следующий FFI\CType. Метод не создаёт CData и не вызывает внешнюю библиотеку. |
| Ошибки PHP | Неверные PHP-типы дают TypeError/ValueError; ошибка C-декларации — FFI\ParserException; неподходящий CType, scope, символ или операция — FFI\Exception. Нарушение ABI/памяти может завершить процесс без catch. |
| Доступность | PHP 8.1+; пример проверен изолированно на PHP 8.5.11 с process-only ffi.enable=1. |
<?php
declare(strict_types=1);
$ffi = FFI::cdef();
$array = $ffi->type('double[4]');
$element = $array->getArrayElementType();
echo $element->getKind() === FFI\CType::TYPE_DOUBLE ? "double\n" : "other element\n";
Ожидаемый результат
double
В многомерном массиве результат может снова быть TYPE_ARRAY; проход повторяют по каждому измерению.
Вернуться к карте FFI; базовые понятия: переменная, массив, функция, исключение.
FFI\CType::getArrayLengthПолучить число элементов одного измерения CType массива.
public function FFI\CType::getArrayLength(): intПолучить число элементов одного измерения CType массива.
| Параметр | Что именно передать |
|---|---|
| Параметров нет | Метод читает свойства самого CType; сначала убедитесь, что это подходящее семейство типа. |
| Часть контракта | Что получить |
|---|---|
| Сигнатура | public function FFI\CType::getArrayLength(): int |
| Результат | Целое число в единицах метода; размеры/offset/alignment зависят от ABI и не должны быть захардкожены по примеру с другой платформы. |
| Ошибки PHP | Неверные PHP-типы дают TypeError/ValueError; ошибка C-декларации — FFI\ParserException; неподходящий CType, scope, символ или операция — FFI\Exception. Нарушение ABI/памяти может завершить процесс без catch. |
| Доступность | PHP 8.1+; пример проверен изолированно на PHP 8.5.11 с process-only ffi.enable=1. |
<?php
declare(strict_types=1);
$ffi = FFI::cdef();
$type = $ffi->type('uint16_t[5]');
echo $type->getArrayLength(), " elements\n";
Ожидаемый результат
5 elements
Это длина одного измерения CType, не число заполненных элементов и не strlen.
Вернуться к карте FFI; базовые понятия: переменная, массив, функция, исключение.
FFI\CType::getPointerTypeПерейти от CType указателя к типу, на который он указывает.
public function FFI\CType::getPointerType(): FFI\CTypeПерейти от CType указателя к типу, на который он указывает.
| Параметр | Что именно передать |
|---|---|
| Параметров нет | Метод читает свойства самого CType; сначала убедитесь, что это подходящее семейство типа. |
| Часть контракта | Что получить |
|---|---|
| Сигнатура | public function FFI\CType::getPointerType(): FFI\CType |
| Результат | Метаданные CType: число/маска либо следующий FFI\CType. Метод не создаёт CData и не вызывает внешнюю библиотеку. |
| Ошибки PHP | Неверные PHP-типы дают TypeError/ValueError; ошибка C-декларации — FFI\ParserException; неподходящий CType, scope, символ или операция — FFI\Exception. Нарушение ABI/памяти может завершить процесс без catch. |
| Доступность | PHP 8.1+; пример проверен изолированно на PHP 8.5.11 с process-only ffi.enable=1. |
<?php
declare(strict_types=1);
$ffi = FFI::cdef();
$pointer = $ffi->type('int*');
$target = $pointer->getPointerType();
echo $target->getKind() === FFI\CType::TYPE_SINT32 ? "int32\n" : $target->getName() . "\n";
Ожидаемый результат
int32
Тип цели не подтверждает действительность адреса. Перед чтением отдельно проверяют null, владение и длину.
Вернуться к карте FFI; базовые понятия: переменная, массив, функция, исключение.
FFI\CType::getStructFieldNamesПолучить имена полей struct/union в порядке объявления.
public function FFI\CType::getStructFieldNames(): arrayПолучить имена полей struct/union в порядке объявления.
| Параметр | Что именно передать |
|---|---|
| Параметров нет | Метод читает свойства самого CType; сначала убедитесь, что это подходящее семейство типа. |
| Часть контракта | Что получить |
|---|---|
| Сигнатура | public function FFI\CType::getStructFieldNames(): array |
| Результат | Массив имён полей в порядке объявления struct/union. |
| Ошибки PHP | Неверные PHP-типы дают TypeError/ValueError; ошибка C-декларации — FFI\ParserException; неподходящий CType, scope, символ или операция — FFI\Exception. Нарушение ABI/памяти может завершить процесс без catch. |
| Доступность | PHP 8.1+; пример проверен изолированно на PHP 8.5.11 с process-only ffi.enable=1. |
<?php
declare(strict_types=1);
$ffi = FFI::cdef('typedef struct { int id; double total; char code[8]; } OrderRow;');
$type = $ffi->type('OrderRow');
echo implode(', ', $type->getStructFieldNames()), "\n";
Ожидаемый результат
id, total, code
Имена приходят из C-декларации. Они помогают сопоставить формат, но не заменяют проверку offset/type.
Вернуться к карте FFI; базовые понятия: переменная, массив, функция, исключение.
FFI\CType::getStructFieldOffsetПолучить байтовое смещение названного поля struct/union с учётом padding.
public function FFI\CType::getStructFieldOffset(string $name): intПолучить байтовое смещение названного поля struct/union с учётом padding.
| Параметр | Что именно передать |
|---|---|
$name | Имя scope или поля — точный идентификатор из header/типа, а не произвольное имя операции приложения. |
| Часть контракта | Что получить |
|---|---|
| Сигнатура | public function FFI\CType::getStructFieldOffset(string $name): int |
| Результат | Целое число в единицах метода; размеры/offset/alignment зависят от ABI и не должны быть захардкожены по примеру с другой платформы. |
| Ошибки PHP | Неверные PHP-типы дают TypeError/ValueError; ошибка C-декларации — FFI\ParserException; неподходящий CType, scope, символ или операция — FFI\Exception. Нарушение ABI/памяти может завершить процесс без catch. |
| Доступность | PHP 8.1+; пример проверен изолированно на PHP 8.5.11 с process-only ffi.enable=1. |
<?php
declare(strict_types=1);
$ffi = FFI::cdef('typedef struct { int id; double total; char code[8]; } OrderRow;');
$type = $ffi->type('OrderRow');
$id = $type->getStructFieldOffset('id');
$total = $type->getStructFieldOffset('total');
echo $id === 0 ? "id starts at 0\n" : "unexpected layout\n";
echo $total > $id ? "total follows id\n" : "check ABI\n";
Ожидаемый результат
id starts at 0
total follows id
Мы не хардкодим число offset: компилятор ABI может вставить padding перед double.
Вернуться к карте FFI; базовые понятия: переменная, массив, функция, исключение.
FFI\CType::getStructFieldTypeПолучить CType названного поля struct/union.
public function FFI\CType::getStructFieldType(string $name): FFI\CTypeПолучить CType названного поля struct/union.
| Параметр | Что именно передать |
|---|---|
$name | Имя scope или поля — точный идентификатор из header/типа, а не произвольное имя операции приложения. |
| Часть контракта | Что получить |
|---|---|
| Сигнатура | public function FFI\CType::getStructFieldType(string $name): FFI\CType |
| Результат | Метаданные CType: число/маска либо следующий FFI\CType. Метод не создаёт CData и не вызывает внешнюю библиотеку. |
| Ошибки PHP | Неверные PHP-типы дают TypeError/ValueError; ошибка C-декларации — FFI\ParserException; неподходящий CType, scope, символ или операция — FFI\Exception. Нарушение ABI/памяти может завершить процесс без catch. |
| Доступность | PHP 8.1+; пример проверен изолированно на PHP 8.5.11 с process-only ffi.enable=1. |
<?php
declare(strict_types=1);
$ffi = FFI::cdef('typedef struct { int id; double total; char code[8]; } OrderRow;');
$type = $ffi->type('OrderRow');
$field = $type->getStructFieldType('total');
echo $field->getKind() === FFI\CType::TYPE_DOUBLE ? "double\n" : "other type\n";
Ожидаемый результат
double
Перед записью гидратор может проверить схему поля. Это всё равно не разрешает передавать непроверенные имена полей от клиента.
Вернуться к карте FFI; базовые понятия: переменная, массив, функция, исключение.
FFI\CType::getFuncABIПолучить код calling convention типа C-функции.
public function FFI\CType::getFuncABI(): intПолучить код calling convention типа C-функции.
| Параметр | Что именно передать |
|---|---|
| Параметров нет | Метод читает свойства самого CType; сначала убедитесь, что это подходящее семейство типа. |
| Часть контракта | Что получить |
|---|---|
| Сигнатура | public function FFI\CType::getFuncABI(): int |
| Результат | Метаданные CType: число/маска либо следующий FFI\CType. Метод не создаёт CData и не вызывает внешнюю библиотеку. |
| Ошибки PHP | Неверные PHP-типы дают TypeError/ValueError; ошибка C-декларации — FFI\ParserException; неподходящий CType, scope, символ или операция — FFI\Exception. Нарушение ABI/памяти может завершить процесс без catch. |
| Доступность | PHP 8.1+; пример проверен изолированно на PHP 8.5.11 с process-only ffi.enable=1. |
<?php
declare(strict_types=1);
$ffi = FFI::cdef('typedef int (*calculator_t)(double value, int mode);');
$type = $ffi->type('calculator_t')->getPointerType();
echo $type->getKind() === FFI\CType::TYPE_FUNC ? "function\n" : "not function\n";
echo $type->getFuncABI() === FFI\CType::ABI_DEFAULT ? "ABI default\n" : "special ABI\n";
Ожидаемый результат
function
special ABI
Неправильная calling convention особенно опасна на Windows: стек/регистры могут не совпасть даже при одинаковых параметрах.
Вернуться к карте FFI; базовые понятия: переменная, массив, функция, исключение.
FFI\CType::getFuncReturnTypeПолучить CType возвращаемого значения типа C-функции.
public function FFI\CType::getFuncReturnType(): FFI\CTypeПолучить CType возвращаемого значения типа C-функции.
| Параметр | Что именно передать |
|---|---|
| Параметров нет | Метод читает свойства самого CType; сначала убедитесь, что это подходящее семейство типа. |
| Часть контракта | Что получить |
|---|---|
| Сигнатура | public function FFI\CType::getFuncReturnType(): FFI\CType |
| Результат | Метаданные CType: число/маска либо следующий FFI\CType. Метод не создаёт CData и не вызывает внешнюю библиотеку. |
| Ошибки PHP | Неверные PHP-типы дают TypeError/ValueError; ошибка C-декларации — FFI\ParserException; неподходящий CType, scope, символ или операция — FFI\Exception. Нарушение ABI/памяти может завершить процесс без catch. |
| Доступность | PHP 8.1+; пример проверен изолированно на PHP 8.5.11 с process-only ffi.enable=1. |
<?php
declare(strict_types=1);
$ffi = FFI::cdef('typedef int (*calculator_t)(double value, int mode);');
$type = $ffi->type('calculator_t')->getPointerType();
$return = $type->getFuncReturnType();
echo $return->getKind() === FFI\CType::TYPE_SINT32 ? "returns int32\n" : $return->getName() . "\n";
Ожидаемый результат
returns int32
Return type входит в ABI. Объявление void вместо int или наоборот нельзя исправить приведением результата в PHP.
Вернуться к карте FFI; базовые понятия: переменная, массив, функция, исключение.
FFI\CType::getFuncParameterCountПолучить число параметров типа C-функции.
public function FFI\CType::getFuncParameterCount(): intПолучить число параметров типа C-функции.
| Параметр | Что именно передать |
|---|---|
| Параметров нет | Метод читает свойства самого CType; сначала убедитесь, что это подходящее семейство типа. |
| Часть контракта | Что получить |
|---|---|
| Сигнатура | public function FFI\CType::getFuncParameterCount(): int |
| Результат | Целое число в единицах метода; размеры/offset/alignment зависят от ABI и не должны быть захардкожены по примеру с другой платформы. |
| Ошибки PHP | Неверные PHP-типы дают TypeError/ValueError; ошибка C-декларации — FFI\ParserException; неподходящий CType, scope, символ или операция — FFI\Exception. Нарушение ABI/памяти может завершить процесс без catch. |
| Доступность | PHP 8.1+; пример проверен изолированно на PHP 8.5.11 с process-only ffi.enable=1. |
<?php
declare(strict_types=1);
$ffi = FFI::cdef('typedef int (*calculator_t)(double value, int mode);');
$type = $ffi->type('calculator_t')->getPointerType();
echo $type->getFuncParameterCount(), " parameters\n";
Ожидаемый результат
2 parameters
Для variadic-функции фиксированная часть и ATTR_VARIADIC рассматриваются отдельно.
Вернуться к карте FFI; базовые понятия: переменная, массив, функция, исключение.
FFI\CType::getFuncParameterTypeПолучить CType параметра C-функции по нулевому индексу.
public function FFI\CType::getFuncParameterType(int $index): FFI\CTypeПолучить CType параметра C-функции по нулевому индексу.
| Параметр | Что именно передать |
|---|---|
$index | Нулевой индекс параметра функции; должен быть меньше getFuncParameterCount(). |
| Часть контракта | Что получить |
|---|---|
| Сигнатура | public function FFI\CType::getFuncParameterType(int $index): FFI\CType |
| Результат | Метаданные CType: число/маска либо следующий FFI\CType. Метод не создаёт CData и не вызывает внешнюю библиотеку. |
| Ошибки PHP | Неверные PHP-типы дают TypeError/ValueError; ошибка C-декларации — FFI\ParserException; неподходящий CType, scope, символ или операция — FFI\Exception. Нарушение ABI/памяти может завершить процесс без catch. |
| Доступность | PHP 8.1+; пример проверен изолированно на PHP 8.5.11 с process-only ffi.enable=1. |
<?php
declare(strict_types=1);
$ffi = FFI::cdef('typedef int (*calculator_t)(double value, int mode);');
$type = $ffi->type('calculator_t')->getPointerType();
$first = $type->getFuncParameterType(0);
$second = $type->getFuncParameterType(1);
echo $first->getKind() === FFI\CType::TYPE_DOUBLE ? "0: double\n" : "0: other\n";
echo $second->getKind() === FFI\CType::TYPE_SINT32 ? "1: int32\n" : "1: other\n";
Ожидаемый результат
0: double
1: int32
Перед getFuncParameterType проверяют count; индекс 2 в этой сигнатуре выбросит FFI\Exception.
Вернуться к карте FFI; базовые понятия: переменная, массив, функция, исключение.
Источники и обсуждения
- PHP Manual: Foreign Function Interface
- PHP Manual: C Data Handles
- PHP Manual: C Type Handles
- PHP Manual: FFI Exceptions
- PHP Manual: FFI Parser Exceptions
- PHP Manual: Main interface to C code and data
- PHP Manual: FFI\CType::getAlignment
- PHP Manual: FFI\CType::getArrayElementType
- PHP Manual: FFI\CType::getArrayLength
- PHP Manual: FFI\CType::getAttributes
- PHP Manual: FFI\CType::getEnumKind
- PHP Manual: FFI\CType::getFuncABI
- PHP Manual: FFI\CType::getFuncParameterCount
- PHP Manual: FFI\CType::getFuncParameterType
- PHP Manual: FFI\CType::getFuncReturnType
- PHP Manual: FFI\CType::getKind
- PHP Manual: FFI\CType::getName
- PHP Manual: FFI\CType::getPointerType
- PHP Manual: FFI\CType::getSize
- PHP Manual: FFI\CType::getStructFieldNames
- PHP Manual: FFI\CType::getStructFieldOffset
- PHP Manual: FFI\CType::getStructFieldType
- PHP Manual: FFI::addr
- PHP Manual: FFI::alignof
- PHP Manual: FFI::arrayType
- PHP Manual: FFI::cast
- PHP Manual: FFI::cdef
- PHP Manual: Runtime Configuration
- PHP Manual: Basic FFI usage
- PHP Manual: PHP Callbacks
- PHP Manual: A Complete PHP/FFI/preloading Example
- PHP Manual: Examples
- PHP Manual: FFI::free
- PHP Manual: Installation
- PHP Manual: FFI::isNull
- PHP Manual: FFI::load
- PHP Manual: FFI::memcmp
- PHP Manual: FFI::memcpy
- PHP Manual: FFI::memset
- PHP Manual: FFI::new
- PHP Manual: Requirements
- PHP Manual: FFI::scope
- PHP Manual: Installing/Configuring
- PHP Manual: FFI::sizeof
- PHP Manual: FFI::string
- PHP Manual: FFI::type
- PHP Manual: FFI::typeof
- php-src 8.5.11: ext/ffi/ffi.stub.php
- php-src 8.5.11: ext/ffi/ffi.c
- Stack Overflow: PHP-массив строк и const char** — время жизни каждого буфера — обсуждение проблемы
- Stack Overflow: Failed resolving C function — scope/lib и экспорт символа — обсуждение проблемы
- Stack Overflow: ручное освобождение void*[] и риск повреждения heap — обсуждение проблемы
- Stack Overflow: загрузка несовместимой shared library и падение процесса — обсуждение проблемы
- php-src issue: несовместимые struct-типы и авария/утечка — обсуждение проблемы