FFI — Foreign Function Interface (PHP 7.4)
debt(d7/e5/b5/t7)
Closest to 'only careful code review or runtime testing' (d7). The detection_hints state automated=no, with only a code_pattern hint (FFI::cdef|FFI::load). No linter or SAST tool is listed. Misuse — such as using FFI in web requests, pointer lifetime errors, or incorrect security configuration — won't be caught by tooling and requires manual code review or runtime observation (e.g. memory leaks, segfaults in production).
Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix involves configuration changes (ffi.enable=preload), architectural context decisions (CLI vs FPM), and potentially replacing FFI-based code paths with PHP-native solutions after performance testing. This is not a one-line swap; it may span php.ini, application bootstrap, and multiple call sites, especially if FFI was used across several modules.
Closest to 'persistent productivity tax' (b5). FFI usage imposes an ongoing tax: developers must understand C memory management (pointer lifetimes, no GC), security restrictions (ffi.enable scope), and performance profiling discipline. applies_to is restricted to CLI contexts, which limits reach somewhat, but every maintainer touching FFI code must carry C interop mental overhead — a significant ongoing burden across affected work streams.
Closest to 'serious trap (contradicts how a similar concept works elsewhere)' (t7). The canonical misconception is that FFI is faster than PHP for all operations — a belief contradicted by FFI's calling overhead. Developers familiar with C extensions or other language FFI implementations may reasonably assume any C call is a speedup, but this is wrong without profiling. Additionally, pointer lifetime management (no GC) contradicts PHP's memory model, and the security risk of ffi.enable=true in FPM is non-obvious.
TL;DR
Explanation
FFI::cdef(cDefinitions, libraryPath) creates an FFI object that wraps a shared library. You can then call C functions directly: $ffi->function_name($args). Data types: int, float, struct, pointer via FFI::new(). Use cases: accessing native libraries not wrapped as PHP extensions, performance-critical operations, system calls. Security: FFI requires ffi.enable=true in php.ini (disabled by default). Can also use FFI::load() with header files. Not suitable for most web applications — mainly for CLI tools and specialised integrations. Performance: overhead from PHP→C marshalling.
Common Misconception
Why It Matters
Common Mistakes
- Using FFI in web requests — security risk (ffi.enable should be restricted in FPM).
- Not handling pointer lifetimes — C memory is not garbage collected.
- Performance testing without accounting for FFI overhead.
Code Examples
// Extension-less library access — used to require a C extension
<?php
$ffi = FFI::cdef(
'int abs(int j);',
'libc.so.6'
);
$result = $ffi->abs(-42); // 42
// Working with structs:
$ffi = FFI::cdef('
typedef struct { int x; int y; } Point;
', null);
$p = $ffi->new('Point');
$p->x = 10;