Start · Sprachen · PHP · Referenz · FFI

FFI

Interface

Ermöglicht den direkten Aufruf von C-Funktionen und den Zugriff auf C-Datenstrukturen aus PHP heraus, ohne eine PHP-Erweiterung schreiben zu müssen.

seit PHP 7.4.0 Kategorie: misc

Signatur

class FFI

Beschreibung

FFI (Foreign Function Interface) ist eine PHP-Kernklasse, die es ermöglicht, native C-Bibliotheken direkt aus PHP-Code heraus zu laden und zu nutzen. Mit FFI::cdef() oder FFI::load() werden C-Deklarationen (Funktionen, Strukturen, Typedefs, Konstanten) angegeben, und anschließend können die entsprechenden Funktionen wie PHP-Methoden aufgerufen werden.

Typische Anwendungsfälle sind: Zugriff auf Betriebssystem-APIs, die keine PHP-Extension besitzen, Hochleistungs-Berechnungen durch Auslagerung in nativ kompilierte Bibliotheken, oder schnelles Prototyping von Bindings zu C-Bibliotheken ohne Extension-Boilerplate. Die FFI-Erweiterung muss in der php.ini aktiviert sein (extension=ffi) und die INI-Einstellung ffi.enable muss auf true oder preload gesetzt sein.

FFI verwaltet C-Datentypinstanzen als FFI\CData-Objekte und C-Typen als FFI\CType-Objekte. Speicher kann manuell über FFI::new() allokiert und über FFI::free() freigegeben werden. Pointer-Arithmetik und direkte Speicherzugriffe sind möglich, was FFI zu einem mächtigen, aber auch gefährlichen Werkzeug macht.

Im CLI- und Preload-Kontext ist FFI uneingeschränkt nutzbar. Im Web-SAPI-Kontext empfiehlt es sich, die C-Definitionen per OPcache-Preload zu laden, um Performance-Einbußen durch wiederholtes Parsen zu vermeiden.

Beispiele

C-Standardbibliothek aufrufen: strlen via FFI

<?php
// FFI::cdef() parst die C-Deklarationen und lädt die Bibliothek
$ffi = FFI::cdef(
    'size_t strlen(const char *s);',
    'libc.so.6' // unter Linux; unter macOS: 'libc.dylib'
);

$len = $ffi->strlen('Hallo Welt');
echo "Länge: $len\n"; // Länge: 10
Länge: 10

C-Struktur definieren und verwenden

<?php
$ffi = FFI::cdef(<<<C
    typedef struct {
        int x;
        int y;
    } Point;
C);

// Neue C-Struktur allokieren
$point = $ffi->new('Point');
$point->x = 10;
$point->y = 20;

echo "Punkt: ({$point->x}, {$point->y})\n";

// Pointer auf die Struktur
$ptr = FFI::addr($point);
echo "Via Pointer: ({$ptr->x}, {$ptr->y})\n";
Punkt: (10, 20) Via Pointer: (10, 20)

FFI per Preload-Header-Datei laden (empfohlen für Web-Kontext)

<?php
// mylib.h (Kommentar-Direktive wird von FFI::load() ausgewertet):
// #define FFI_LIB "libmylib.so"
// int my_add(int a, int b);

// In einem OPcache-Preload-Skript:
// $ffi = FFI::load('/path/to/mylib.h');

// Im Anwendungscode:
// $result = $ffi->my_add(3, 4);
// echo $result; // 7

// Beispiel ohne externe Datei – direkt im Skript:
$ffi = FFI::cdef('int abs(int j);', 'libc.so.6');
echo $ffi->abs(-42) . "\n"; // 42
42

// Wichtig · Fallstricke

Sicherheit: FFI erlaubt direkten Zugriff auf Arbeitsspeicher und native Bibliotheken. Falscher Einsatz kann zu Speicherlecks, Segmentation Faults oder beliebiger Codeausführung führen. Niemals mit nicht vertrauenswürdigen Eingaben arbeiten, insbesondere nicht mit dynamisch zusammengestellten C-Deklarationen.

ffi.enable-Einstellung: Der Wert preload erlaubt FFI nur in Preload-Skripten (empfohlen für Produktivumgebungen). Im Web-SAPI-Modus sollte ffi.enable=preload bevorzugt werden, da ffi.enable=true jeden PHP-Code in die Lage versetzt, beliebige native Bibliotheken zu laden.

Speicherverwaltung: Mit FFI::new() ohne zweiten Parameter false allokierter Speicher wird automatisch freigegeben, wenn das FFI\CData-Objekt aus dem Scope fällt. Wird false übergeben (unmanaged), muss FFI::free() explizit aufgerufen werden, um Speicherlecks zu vermeiden.

Performance: Das Parsen von C-Deklarationen via FFI::cdef() ist teuer. Im Web-Kontext daher stets OPcache-Preload nutzen (FFI::load() in einem Preload-Skript), um die Kosten auf den Startvorgang zu beschränken.