This is an old revision of the document!
PHP RFC: FFI - Foreign Function Interface
- Version: 0.9
- Date: 2013-12-04
- Author: Dmitry Stogov, dmitry@zend.com
- Status: Under Discussion
- First Published at: https://wiki.php.net/rfc/ffi
Introduction
FFI is one of the features that made Python and LuaJIT very useful for fast prototyping. It allows calling C functions and use C data types from pure scripting language and therefore develop “system code” more productively. For PHP, FFI opens a way to write PHP extensions and bindings to C libraries in pure PHP.
Proposal
It is proposed to extend PHP with a simple FFI API designed after LuaJTI/FFI and Python/CFFI (actually, the second was based on the first). This API allows loading shared libraries (.DLL or .so), calling C functions and accessing C data structures, in pure PHP, without learning 3rd “intermediate” language.
The public API is implemented as a single class FFI with few static methods (some of them may be called non-statically), and overloaded object methods, that perform actual interaction with C data. Before diving into the details of FFI API, take a look into few examples, to see, how it's simple to use this API for regular tasks.
Calling a function from shared library
<?php // create FFI object, loading libc and exporting function printf() $ffi = new FFI( "int printf(const char *format, ...);", // this is regular C declaration "libc.so.6"); // call C printf() $ffi->printf("Hello %s!\n", "world");
Calling a function, returning structure through argument
<?php // create gettimeofday() binding $ffi = new FFI(" typedef unsigned int time_t; typedef unsigned int suseconds_t; struct timeval { time_t tv_sec; suseconds_t tv_usec; }; struct timezone { int tz_minuteswest; int tz_dsttime; }; int gettimeofday(struct timeval *tv, struct timezone *tz); ", "libc.so.6"); // create C data structures $tv = $ffi->new("struct timeval"); $tz = $ffi->new("struct timezone"); // calls C gettimeofday() var_dump($ffi->gettimeofday(FFI::addr($tv), FFI::addr($tz))); // access field of C data structure var_dump($tv->tv_sec); // print the whole C data structure var_dump($tz);
Accessing C variables
<?php // create FFI object, loading libc and exporting errno variable $ffi = new FFI("int errno;", // this is regular C declaration "libc.so.6"); // print C errno var_dump($ffi->errno);
Working with C arrays
<?php // create C data structure $a = FFI::new("unsigned char[1024*1024]"); // "FFI::new" is different from "new FFI" // work with it like with regular PHP array for ($i = 0; $i < 1024 * 1024; $i++) { $a[$i] = $i; } var_dump($a[25]); var_dump(count($a)); $sum = 0; foreach ($a as $n) { $sum += $n; } var_dump($sum); var_dump(FFI::sizeof($a));
PHP FFI API
FFI::__construct([string $cdef = "" [, string $lib = null]])
Creates a new FFI object. The first optional argument is a string, containing a sequence of declarations in regular C languages (types, structures, functions, variables, etc). Actually, this string may be copy-pasted from C header files. All the declared entities are going to be available to PHP through overloaded functions or other FFI API functions. Declared C variables may be accessed as FFI object properties, C functions - called as FFI object methods. C type names may be used to create new C data structures... The second optional argument is a shared library file name, to be loaded and linked with definitions.
We don't support C preprocessor, yet. #include, #define and CPP macros don't work.
FFI::new
FFI::free
FFI::cast
FFI::type
FFI::array
FFI::addr
FFI::sizeof
FFI::alignof
FFI::memcpy
FFI::memcmp
FFI::memset
FFI::string
FFI::load
FFI::scope
Backward Incompatible Changes
None, except of introduced FFI class and namespace.
Proposed PHP Version(s)
PHP 7.4
RFC Impact
To Opcache
FFI is designed in conjunction with preloading (curently implemented as part of opcache). FFI C headers may be loaded during preloading by FFI::load() and become available to all the following HTTP requests without reloading overhead.
php.ini Defaults
ffi.enable=false|preload|true
allows enabling or disabling FFI API usage, or restricting it only to preloaded files. The default value is preload
Open Issues
Make sure there are no open issues when the vote starts!
Future Scope
Currently, the performance of C data structures access is worst, then access of native PHP data structures (arrays and objects). This is a common problem of LuaJIT (in interpretator mode) and Python as well. However, LuaJIT may also compile these access code in very efficient way (almost as C compiler), and produce highly efficient machine code. It's planned to try similar things, implementing JIT for PHP.
Proposed Voting Choices
Include FFI extension into PHP-7.4 This project requires 50%+1 majority
Patches and Tests
Implementation
After the project is implemented, this section should contain
- the version(s) it was merged into
- a link to the git commit(s)
- a link to the PHP manual entry for the feature
- a link to the language specification section (if any)
References
Rejected Features
Keep this updated with features that were discussed on the mail lists.