Einleitung
PHP FFI (Foreign Function Interface) ist eine PHP-Erweiterung, mit der Sie Shared Libraries laden, C-Funktionen aufrufen und auf C-Datenstrukturen zugreifen. Sie können vorhandene C-APIs direkt aus PHP nutzen, ohne selbst eine PHP-Extension zu schreiben. Die offizielle PHP-Dokumentation beschreibt FFI als eine Low-Level- und potenziell gefährliche Funktion. Sie sollte nur von Entwicklern eingesetzt werden, die C und die API der Zielbibliothek verstehen. FFI ist auch keine „Performance-Funktion”. Selbst die offizielle Doku weist darauf hin, dass der Datenstruktur-Zugriff via FFI langsamer ist als native PHP-Arrays oder -Objekte. Der Grund für FFI ist nicht Geschwindigkeit, sondern die Nutzung bestehender C-Bibliotheken aus PHP heraus.Verfügbare Umgebungen und Einschränkungen
Die offizielle PHP-Dokumentation nennt folgende Wege, um die FFI-Erweiterung zu aktivieren:- PHP mit
--with-ffibauen - Unter Windows in
php.iniphp_ffi.dllaktivieren - Über
ffi.enableinphp.inidie Verfügbarkeit steuern
ffi.enable kennt drei Werte:
In Webserver-Umgebungen wird häufig
ffi.enable=false oder ffi.enable=preload gesetzt. Auch bei Hosting-Plattformen einschließlich Laravel Cloud lässt sich FFI in einer klassischen Webanwendung nicht garantiert nutzen.Grundlagen der Nutzung
Die vier zentralen Bausteine von PHP FFI sindFFI::cdef(), FFI::new(), FFI::addr() und FFI::string().
FFI::cdef()erzeugt aus einer C-Deklaration und einem Bibliotheksnamen ein FFI-Objekt.$ffi->new('struct timeval')allokiert die C-Datenstruktur.FFI::addr($tv)erzeugt ein Pointer-Argument wiestruct timeval *.- Auf Struktur-Felder greifen Sie über
$tv->tv_seczu.
FFI::string().
Header-Dateien einlesen
FFI::load() liest Deklarationen aus einer C-Header-Datei. Diese kann FFI_SCOPE und FFI_LIB enthalten.
FFI::cdef() noch FFI::load() gewöhnliche C-Präprozessor-Direktiven verarbeiten. #include, #define und Bedingungskompilate lassen sich nicht direkt übergeben.
In der Praxis wählt man daher meist einen dieser zwei Wege:
1
Bei einfachen APIs direkt in `FFI::cdef()` schreiben
Sind wenige Typen und Funktionen betroffen, betten Sie die benötigten Deklarationen direkt im PHP-Code ein.
2
Bei komplexen APIs eine vorverarbeitete Header-Datei pflegen
Verwalten Sie einen speziell für FFI aufbereiteten Header — ohne Makros und Bedingungen — als separate Datei.
Praxisbeispiel: VOICEVOX Core for PHP
VOICEVOX Core for PHP ist ein reales Beispiel, das die dynamische C-Bibliothek von VOICEVOX CORE aus reinem PHP ansteuert. Die dortigen FFI-Muster sind kompakt zusammengefasst und daher leichter nachzuvollziehen als abstrakte Erklärungen.1. Ein FFI-eigenes Header-File pflegen
Der Original-Header von VOICEVOX Core wird nicht direkt verwendet. Stattdessen werden inheaders/voicevox_core_ffi.h FFI-spezifische Deklarationen ausgelagert, unter anderem für opake Pointer, Structs und free-Funktionen.
2. FFI::cdef() an einer Stelle konzentrieren
src/VoicevoxFFI.php bündelt das Header-Laden und die Bibliothekspfad-Auflösung an einem Ort.
FFI::cdef() nicht direkt aufrufen. Auch Unterschiede beim Bibliothekspfad lassen sich über eine Umgebungsvariable und Betriebssystem-Erkennung abfangen.
3. Out-Parameter kapseln und in Objekte überführen
Der Konstruktor insrc/Synthesizer.php allokiert einen struct VoicevoxSynthesizer* und übergibt dessen Adresse an voicevox_synthesizer_new().
Type **out_value in PHP annehmen:
new('struct VoicevoxSynthesizer*')legt die Pointer-Variable an.FFI::addr($ptr)liefert dasType **-Argument.- Das erhaltene Handle halten Sie als Property des PHP-Objekts.
4. Von C zurückgegebenen Speicher in einen PHP-String kopieren und sofort freigeben
VOICEVOX Core for PHP kopiert JSON-Strings und WAV-Binärdaten zunächst mitFFI::string() in einen PHP-String und ruft anschließend die C-seitige Free-Funktion auf.
Hinweise und Best Practices
FFI eignet sich für Fälle, in denen eine bereits stabile C-API existiert und der Aufwand, eine PHP-Extension zu schreiben, zu groß wäre. Für Features, die im normalen Web-Hosting laufen sollen, oder für rein in PHP realisierbare Verarbeitung ist FFI nicht der richtige Weg.
Fazit
Mit PHP FFI rufen Sie vorhandene C-Bibliotheken aus reinem PHP heraus auf. FFI ist jedoch ein Low-Level- und riskanter Mechanismus, der sich nicht immer in Webservern nutzen lässt. Die Implementierung von VOICEVOX Core for PHP zeigt, was in der Praxis zählt:- Einen eigenen FFI-Header pflegen.
FFI::cdef()und die Bibliothekspfad-Auflösung an einer Stelle bündeln.- Opake Pointer in eigenen Klassen kapseln.
- Von C zurückgegebenen Speicher in PHP kopieren und mit der dedizierten Free-Funktion freigeben.