Александр Некрасов · Автономное руководство

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

Разделы этой страницы
  1. FFI PHP: полный справочник CData, CType, памяти, DLL/SO и ABI
  2. Сначала осязаемый результат: три числа лежат в C-памяти, PHP их читает
  3. Когда FFI даёт реальный выигрыш, а когда выбрать другой инструмент
  4. Четыре сущности, которые нельзя смешивать: объявление, тип, память и указатель
  5. Установка и режимы: почему «extension загружено» ещё не означает «веб-коду всё разрешено»
  6. Навигация от задачи: какой метод открыть
  7. Практический слой: один объект прячет platform name и повторное cdef
  8. Владение и время жизни: owned, unmanaged, persistent и производные указатели
  9. Реальная сложность: PHP array строк нельзя просто передать как const char**
  10. C-строка, бинарный буфер и кодировка — три разных договора
  11. Структуры и ABI: почему совпавшие имена полей ещё ничего не доказывают
  12. Ошибки по слоям: что можно поймать, а что способно завершить процесс
  13. Callbacks PHP → C: работают не везде, дороже вызова и удерживают ресурсы
  14. Preloading и scope: разобрать доверенный header на старте, а не в каждом запросе
  15. Модель угроз: FFI — привилегия процесса, а не функция для пользовательского конструктора
  16. Производительность: измерять весь путь и кешировать описание, а не обещать ускорение
  17. Повторяющиеся жизненные проблемы из обсуждений разработчиков
  18. Полная карта классов: FFI, CData, CType и два уровня исключений
  19. Все 38 runtime-констант: biggest alignment, kinds, attributes и ABI
  20. Полный справочник методов по категориям
  21. Маршрут обучения: от безопасной памяти к своей native-интеграции
  22. Граница полноты этой ветки
  23. Функции и методы этой темы
  24. Код и руководство с собой
PHP 8.5.11149 глав4458 карточек справочника
Дерево руководства

Глава 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-массив фиксированной длины, записываем значения и получаем понятную сумму.

Что происходит в памяти
  1. $ffi->new("int[3]") выделяет непрерывный C-буфер для трёх int
  2. Индексы 0, 1 и 2 обращаются к фиксированным ячейкам; четвёртой ячейки нет
  3. PHP читает значения через FFI\CData и складывает обычные числа
  4. Когда owned CData больше не нужен, PHP освобождает его память
Создать C-массив и получить суммуСамостоятельный пример
<?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 и получить JSONproc_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)
Создать одну C-запись товара и прочитать поляСамостоятельный пример
<?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/macOSPHP собран с --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::cdefFFI::load, режим ffi.enable
Разобрать header один раз при стартеFFI::loadFFI::scope, opcache.preload
Выделить scalar/array/structFFI::newFFI::free, owned/persistent
Передать out-параметрFFI::addrFFI::isNull, время жизни источника
Превратить C char* в PHP stringFFI::stringFFI::memcpy, длина/NUL/кодировка
Проверить размер и layoutFFI::sizeofFFI::alignof, getStructFieldOffset
Исследовать неизвестный CTypeFFI\CType::getKindПосле kind — array/pointer/struct/function методы
Понять сигнатуру callbackFFI\CType::getFuncParameterCountFFI\CType::getFuncReturnType, ABI

Практический слой: один объект прячет platform name и повторное cdef

В рабочем сервисе вызовы FFI не размазывают по контроллерам. Обёртка один раз выбирает библиотеку, объявляет ровно используемые символы и отдаёт метод с обычным PHP-типом. Ниже системная abs — безопасная маленькая модель такой границы; у реального прибора рядом будут версия протокола, диапазоны, коды ошибок и тестовый fixture.

Спрятать системную библиотеку за PHP-методомСамостоятельный пример
<?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-вызова.

Собрать char*[] и прочитать строки обратноСамостоятельный пример
<?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* + NULFFI::string($ptr) читает до первого нулевого байтаЕсли NUL нет в доступной памяти, чтение выходит за границу.
void*/char* + lengthFFI::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*

Ошибки по слоям: что можно поймать, а что способно завершить процесс

Отличить ошибку parser от неподходящей операции CTypeСамостоятельный пример
<?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 не того kindFFI\Exception; диагностировать библиотеку/схему.
Native ABI/памятьневерный pointer, размер, calling conventionCrash/corruption; воспроизводить вне web worker, включить guard process.
Бизнес-результат DLLкод ошибки/NULLЧитать документацию библиотеки; isNull и код ошибки — отдельные проверки.

Callbacks PHP → C: работают не везде, дороже вызова и удерживают ресурсы

Официальный пример показывает присваивание PHP Closure C-указателю функции и одновременно предупреждает: поддержка зависит от платформы libffi, механизм неэффективен и оставляет ресурсы до конца request. Поэтому callback используют только когда C API действительно требует его, минимизируют число/время жизни и не выбрасывают PHP-исключение через C-границу.

Вызвать короткий callback через C function pointerСамостоятельный пример
<?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 и права процесса настраиваются отдельно.

Минимальная схема preload/scope из четырёх файловФрагмент или команда
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 и cdefnm/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 conventionextern "C", header, compiler ABI, разрядность, field offsets.
Try/catch не сработалПроцесс упал в native-коде до PHP exceptionCLI fixture, guard process, минимальный вход, debugger/sanitizer библиотеки.

Обсуждения используются как карта реальных затруднений. Сигнатуры и нормативное поведение этой главы берутся из PHP Manual и php-src 8.5.11; чужие ответы не копируются как готовый контракт.

Полная карта классов: FFI, CData, CType и два уровня исключений

ТипЧто хранит / как получается
FFIПривязку C declarations/library; cdef, load или scope.
FFI\CDataNative 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_VOID0код, который интерпретируют только в соответствующем семействе
FFI\CType::TYPE_FLOAT1код, который интерпретируют только в соответствующем семействе
FFI\CType::TYPE_DOUBLE2код, который интерпретируют только в соответствующем семействе
FFI\CType::TYPE_UINT83код, который интерпретируют только в соответствующем семействе
FFI\CType::TYPE_SINT84код, который интерпретируют только в соответствующем семействе
FFI\CType::TYPE_UINT165код, который интерпретируют только в соответствующем семействе
FFI\CType::TYPE_SINT166код, который интерпретируют только в соответствующем семействе
FFI\CType::TYPE_UINT327код, который интерпретируют только в соответствующем семействе
FFI\CType::TYPE_SINT328код, который интерпретируют только в соответствующем семействе
FFI\CType::TYPE_UINT649код, который интерпретируют только в соответствующем семействе
FFI\CType::TYPE_SINT6410код, который интерпретируют только в соответствующем семействе
FFI\CType::TYPE_ENUM11enum
FFI\CType::TYPE_BOOL12код, который интерпретируют только в соответствующем семействе
FFI\CType::TYPE_CHAR13код, который интерпретируют только в соответствующем семействе
FFI\CType::TYPE_POINTER14указатель
FFI\CType::TYPE_FUNC15сигнатура функции
FFI\CType::TYPE_ARRAY16фиксированный массив
FFI\CType::TYPE_STRUCT17struct/union

ATTR_* — битовая маска свойств

КонстантаPHP 8.5.11Как читать
FFI\CType::ATTR_CONST1const-qualified type
FFI\CType::ATTR_INCOMPLETE_TAG2код, который интерпретируют только в соответствующем семействе
FFI\CType::ATTR_VARIADIC4variadic function
FFI\CType::ATTR_INCOMPLETE_ARRAY8код, который интерпретируют только в соответствующем семействе
FFI\CType::ATTR_VLA16код, который интерпретируют только в соответствующем семействе
FFI\CType::ATTR_UNION32union
FFI\CType::ATTR_PACKED64packed layout
FFI\CType::ATTR_MS_STRUCT128код, который интерпретируют только в соответствующем семействе
FFI\CType::ATTR_GCC_STRUCT256код, который интерпретируют только в соответствующем семействе

ABI_* — calling convention

КонстантаPHP 8.5.11Как читать
FFI\CType::ABI_DEFAULT0ABI по умолчанию текущей платформы
FFI\CType::ABI_CDECL1cdecl
FFI\CType::ABI_FASTCALL2fastcall
FFI\CType::ABI_THISCALL3код, который интерпретируют только в соответствующем семействе
FFI\CType::ABI_STDCALL4stdcall
FFI\CType::ABI_PASCAL5код, который интерпретируют только в соответствующем семействе
FFI\CType::ABI_REGISTER6код, который интерпретируют только в соответствующем семействе
FFI\CType::ABI_MS7код, который интерпретируют только в соответствующем семействе
FFI\CType::ABI_SYSV8код, который интерпретируют только в соответствующем семействе
FFI\CType::ABI_VECTORCALL9vectorcall

Полный справочник методов по категориям

Загрузка и 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

Маршрут обучения: от безопасной памяти к своей 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/lifetimeOut-параметр и char** с ownersМожете назвать владельца и момент освобождения каждого буфера.
5. cdef/loadВызвать один чистый символ тестовой библиотекиHeader, DLL/SO, архитектура и результат зафиксированы.
6. wrapper/testsОбычный PHP-интерфейс + fake adapterКонтроллер не знает FFI; ошибки преобразованы в domain result.
7. preload/isolationScope или отдельный native workerВеб-пользователь не управляет declarations/path, crash локализован.

Граница полноты этой ветки

ИнвентарьПокрытие
Официальные страницы book.ffi47/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, получив объект вызова библиотеки.

PHP 7.4+ · FFI

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.
Вызвать одну функцию системной C-библиотекиСамостоятельный пример
<?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.

PHP 7.4+ · FFI

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.
Загрузить небольшой доверенный headerСамостоятельный пример
<?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 именованную привязку без повторного парсинга заголовка.

PHP 7.4+ · FFI

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.
Отличить отсутствующий preload-scope от результата функцииСамостоятельный пример
<?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-память заданного типа и явно выбрать управляемое или ручное владение.

PHP 7.4+ · FFI

public function FFI::new(FFI\CType|string $type, bool $owned = true, bool $persistent = false): ?FFI\CData

Выделить C-память заданного типа и явно выбрать управляемое или ручное владение.

ПараметрЧто именно передать
$typeC-декларация либо уже созданный FFI\CType. Размеры и уровень указателя должны совпадать с реальной ABI.
$ownedtrue связывает время жизни памяти с 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.
Создать и заполнить C-массив целых чиселСамостоятельный пример
<?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-буфер и больше его не использовать.

PHP 7.4+ · FFI

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-тип без копирования и без передачи владения.

PHP 7.4+ · FFI

public function FFI::cast(FFI\CType|string $type, FFI\CData|int|float|bool|null &$ptr): ?FFI\CData

Посмотреть на ту же область памяти через другой совместимый C-тип без копирования и без передачи владения.

ПараметрЧто именно передать
$typeC-декларация либо уже созданный 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.
Прочитать ту же память через совместимый int-указательСамостоятельный пример
<?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 для повторного создания и анализа.

PHP 7.4+ · FFI

public function FFI::type(string $type): ?FFI\CType

Разобрать C-декларацию типа в объект FFI\CType для повторного создания и анализа.

ПараметрЧто именно передать
$typeC-декларация либо уже созданный 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.
Разобрать typedef структуры без выделения записиСамостоятельный пример
<?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.

PHP 7.4+ · FFI

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.
Узнать тип уже созданного C-массиваСамостоятельный пример
<?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 и массива размеров.

PHP 7.4+ · FFI

public static function FFI::arrayType(FFI\CType $type, array $dimensions): FFI\CType

Собрать многомерный C-массив из базового CType и массива размеров.

ПараметрЧто именно передать
$typeC-декларация либо уже созданный 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.
Собрать CType матрицы 2×3 и создать данныеСамостоятельный пример
<?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-функции.

PHP 7.4+ · FFI

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.
Изменить исходное C-значение через указательСамостоятельный пример
<?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-платформе.

PHP 7.4+ · FFI

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-платформе.

PHP 7.4+ · FFI

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-буфером.

PHP 7.4+ · FFI

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.
Скопировать текст вместе с завершающим NULСамостоятельный пример
<?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Лексикографически сравнить точное число сырых байтов двух областей памяти.

PHP 7.4+ · FFI

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-буфера одним байтовым значением.

PHP 7.4+ · FFI

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.
Заполнить четыре байта символом AСамостоятельный пример
<?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-строку по длине или до нулевого байта.

PHP 7.4+ · FFI

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.
Увидеть разницу между длиной и C-терминаторомСамостоятельный пример
<?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-указатель от указателя на реальную область памяти.

PHP 7.4+ · FFI

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.
Проверить null-указатель до разыменованияСамостоятельный пример
<?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-типа.

PHP 7.4+ · FFI

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.
Получить имя базового C-типаСамостоятельный пример
<?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.

PHP 8.1+ · FFI

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.
Различить массив и обычный scalarСамостоятельный пример
<?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.

PHP 8.1+ · FFI

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 в байтах.

PHP 8.1+ · FFI

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.
Сверить alignment CType и общего APIСамостоятельный пример
<?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 и других атрибутов типа.

PHP 8.1+ · FFI

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.
Обнаружить const через битовую маскуСамостоятельный пример
<?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.

PHP 8.1+ · FFI

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.
Узнать целочисленное представление enumСамостоятельный пример
<?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 массива к типу одного элемента.

PHP 8.1+ · FFI

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.
Перейти от double[4] к doubleСамостоятельный пример
<?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 массива.

PHP 8.1+ · FFI

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 указателя к типу, на который он указывает.

PHP 8.1+ · FFI

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.
Узнать, что int* указывает на intСамостоятельный пример
<?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 в порядке объявления.

PHP 8.1+ · FFI

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.

PHP 8.1+ · FFI

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.
Учесть padding между int и doubleСамостоятельный пример
<?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.

PHP 8.1+ · FFI

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.
Проверить тип поля totalСамостоятельный пример
<?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-функции.

PHP 8.1+ · FFI

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.
Узнать calling convention C-функцииСамостоятельный пример
<?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-функции.

PHP 8.1+ · FFI

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.
Прочитать возвращаемый C-тип callbackСамостоятельный пример
<?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-функции.

PHP 8.1+ · FFI

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.
Посчитать параметры C-функцииСамостоятельный пример
<?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-функции по нулевому индексу.

PHP 8.1+ · FFI

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; базовые понятия: переменная, массив, функция, исключение.

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

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

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

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

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