rfc:ffi
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revisionNext revisionBoth sides next revision | ||
rfc:ffi [2018/12/04 20:34] – dmitry | rfc:ffi [2019/01/14 08:54] – dmitry | ||
---|---|---|---|
Line 1: | Line 1: | ||
====== PHP RFC: FFI - Foreign Function Interface | ====== PHP RFC: FFI - Foreign Function Interface | ||
* Version: 0.9 | * Version: 0.9 | ||
- | * Date: 2013-12-04 | + | * Date: 2018-12-04 |
* Author: Dmitry Stogov, dmitry@zend.com | * Author: Dmitry Stogov, dmitry@zend.com | ||
- | * Status: | + | * Status: |
* First Published at: https:// | * First Published at: https:// | ||
===== Introduction ===== | ===== 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 " | + | FFI is one of the features that made Python and LuaJIT very useful for fast prototyping. It allows calling C functions and using C data types from pure scripting language and therefore develop " |
===== Proposal ===== | ===== Proposal ===== | ||
- | It is proposed to extend PHP with a simple FFI API designed after LuaJTI/FFI and Python/CFFI (actually, | + | It is proposed to extend PHP with a simple FFI API designed after LuaJTI/FFI and Python/CFFI (the latter |
- | The public API is implemented as a single class **FFI** with few static methods (some of them may be called non-statically), | + | The public API is implemented as a single class **FFI** with a few static methods (some of them may be called non-statically), |
==== Calling a function from shared library ==== | ==== Calling a function from shared library ==== | ||
Line 18: | Line 18: | ||
<?php | <?php | ||
// create FFI object, loading libc and exporting function printf() | // create FFI object, loading libc and exporting function printf() | ||
- | $ffi = new FFI( | + | $ffi = FFI::cdef( |
"int printf(const char *format, ...);", | "int printf(const char *format, ...);", | ||
" | " | ||
Line 29: | Line 29: | ||
<?php | <?php | ||
// create gettimeofday() binding | // create gettimeofday() binding | ||
- | $ffi = new FFI(" | + | $ffi = FFI::cdef(" |
typedef unsigned int time_t; | typedef unsigned int time_t; | ||
typedef unsigned int suseconds_t; | typedef unsigned int suseconds_t; | ||
Line 60: | Line 60: | ||
<?php | <?php | ||
// create FFI object, loading libc and exporting errno variable | // create FFI object, loading libc and exporting errno variable | ||
- | $ffi = new FFI(" | + | $ffi = FFI::cdef("int errno;", |
" | " | ||
// print C errno | // print C errno | ||
Line 70: | Line 70: | ||
<?php | <?php | ||
// create C data structure | // create C data structure | ||
- | $a = FFI:: | + | $a = FFI:: |
// work with it like with regular PHP array | // work with it like with regular PHP array | ||
for ($i = 0; $i < count($a); $i++) { | for ($i = 0; $i < count($a); $i++) { | ||
Line 86: | Line 86: | ||
===== PHP FFI API ===== | ===== PHP FFI API ===== | ||
- | ==== FFI::__construct([string $cdef = "" | + | ==== FFI::cdef([string $cdef = "" |
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. The second optional argument is a shared library file name, to be loaded and linked with definitions. All the declared entities are going to be available to PHP through overloaded functions or other FFI API functions: | 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. The second optional argument is a shared library file name, to be loaded and linked with definitions. All the declared entities are going to be available to PHP through overloaded functions or other FFI API functions: | ||
* C variables may be accessed as FFI object properties | * C variables may be accessed as FFI object properties | ||
- | * C functions may called as FFI object methods | + | * C functions may be called as FFI object methods |
* C type names may be used to create new C data structures using **FFI:: | * C type names may be used to create new C data structures using **FFI:: | ||
- | Note: We don't support C preprocessor, yet. #include, #define and CPP macros | + | Note: At this time we don't support C preprocessor |
==== FFI:: | ==== FFI:: | ||
- | Creates native data structure of given C type. $type may be any valid C string declaration or an instance of **FFI\CType** created before. Using the second argument, it's possible to create **owned** data (default), or unmanaged. In first case, data structure is going to leave together with returned FFI\CData object, and die when last reference is released by regular PHP reference counting or GC. However, in some cases, programmer may decide to keep C data even after, releasing of **FFI\CData** object and manually free it through **FFI:: | + | Creates native data structure of given C type. $type may be any valid C string declaration or an instance of **FFI\CType** created before. Using the second argument, it's possible to create **owned** data (default), or unmanaged. In the first case, data structure is going to live together with returned FFI\CData object, and die when last reference is released by regular PHP reference counting or GC. However, in some cases, programmer may decide to keep C data even after, releasing of **FFI\CData** object and manually free it through **FFI:: |
- | This function may be called statically | + | This function may be called statically |
- | The returned **FF\CData** object may be used in a number of ways as a regular PHP data | + | The returned **FFI\CData** object may be used in a number of ways as a regular PHP data |
* C data of scalar types may be read and assigned as regular PHP data. **'' | * C data of scalar types may be read and assigned as regular PHP data. **'' | ||
- | * C struct/ | + | * C struct/ |
* C array elements may be accessed as regular PHP array elements. **'' | * C array elements may be accessed as regular PHP array elements. **'' | ||
* C array may be iterated using **foreach** statement. | * C array may be iterated using **foreach** statement. | ||
- | * C array may be used as arguments to **count()** function. | + | * C array may be used as an argument of **count()** function. |
* C pointers may be dereferenced as arrays. **'' | * C pointers may be dereferenced as arrays. **'' | ||
* C pointers may be compared using regualar comparison operators (<, <=, ==, !==, >=, >). | * C pointers may be compared using regualar comparison operators (<, <=, ==, !==, >=, >). | ||
Line 122: | Line 122: | ||
==== FFI:: | ==== FFI:: | ||
- | Manually releases previously created " | + | Manually releases |
==== FFI:: | ==== FFI:: | ||
- | Performs C type cast. It creates a new **FFI\CData** object, that references the same C data structure, but using different type. The resulting object doesn' | + | Performs C type cast. It creates a new **FFI\CData** object, that references the same C data structure, but associated with different type. The resulting object doesn' |
- | This function may be called statically | + | This function may be called statically |
==== FFI:: | ==== FFI:: | ||
Line 136: | Line 136: | ||
==== FFI:: | ==== FFI:: | ||
- | This function creates and returns a FFI\CType object, representng type of the given C type declaration | + | This function creates and returns a FFI\CType object |
- | This function may be called statically | + | This function may be called statically |
- | ==== FFI::array_type(FFI\CType $type, array $dims): FFI\CType ==== | + | ==== FFI::arrayType(FFI\CType $type, array $dims): FFI\CType ==== |
Dynamically constructs a new C array type with elements of type defined by the first argument and dimensions specified by the second. In the following example $t1 and $t2 are equivalent array types. | Dynamically constructs a new C array type with elements of type defined by the first argument and dimensions specified by the second. In the following example $t1 and $t2 are equivalent array types. | ||
Line 146: | Line 146: | ||
<code php> | <code php> | ||
$t1 = FFI:: | $t1 = FFI:: | ||
- | $t2 = FFI::array_type(FFI:: | + | $t2 = FFI::arrayType(FFI:: |
</ | </ | ||
Line 159: | Line 159: | ||
==== FFI:: | ==== FFI:: | ||
- | Returns | + | Returns |
==== FFI:: | ==== FFI:: | ||
Line 171: | Line 171: | ||
==== FFI:: | ==== FFI:: | ||
- | Fills the $size bytes of the memory area pointed to by $dst with the constant | + | Fills the $size bytes of the memory area pointed to by $dst with the given byte $c |
==== FFI:: | ==== FFI:: | ||
- | Creates a PHP string from $size bytes of memory area pointed by $src. If size is omitted, $src must be zero terminated array of C chars. | + | Creates a PHP string from $size bytes of the memory area pointed by $src. If size is omitted, $src must be a zero terminated array of C chars. |
==== FFI:: | ==== FFI:: | ||
- | In addition to ability of embedding C declaration code into C constructor, it's also possible to load C declarations from separate C header file. | + | In addition to ability of embedding C declaration code into **FFI:: |
- | Note: We don't support | + | Note: C preprocessor |
It's possible to specify shared libraries, that should be loaded, using special **FFI_LIB** define in the loaded C header file. | It's possible to specify shared libraries, that should be loaded, using special **FFI_LIB** define in the loaded C header file. | ||
- | FFI definition parsing and shared library loading may take significant time. It's not useful to do it on each HTTP request in WEB environment. However, it's possible to pre-load | + | FFI definition parsing and shared library loading may take significant time. It's not useful to do it on each HTTP request in a Web environment. However, it's possible to preload |
- | It's possible to preload | + | It's possible to preload |
==== FFI:: | ==== FFI:: | ||
Line 198: | Line 198: | ||
<code php> | <code php> | ||
- | $zend = new FFI(" | + | $zend = FFI::cdef(" |
typedef int (*zend_write_func_t)(const char *str, size_t str_length); | typedef int (*zend_write_func_t)(const char *str, size_t str_length); | ||
extern zend_write_func_t zend_write; | extern zend_write_func_t zend_write; | ||
Line 226: | Line 226: | ||
</ | </ | ||
- | This work, but this functionality is not supported on all libffi platforms, it is not efficient and leaks resources by the end of request. It's recommended to minimize the usage of PHP callbacks. | + | This works, but this functionality is not supported on all libffi platforms, it is not efficient and leaks resources by the end of request. It's recommended to minimize the usage of PHP callbacks. |
- | + | ||
- | ===== Owned and Not-Owned CData ===== | + | |
- | + | ||
- | ... | + | |
===== PHP FFI API Restriction ===== | ===== PHP FFI API Restriction ===== | ||
- | FFI API opens all the C power, and therefore | + | FFI API opens all the C power, and consequently, |
* **ffi.enable=false** completely disables PHP FFI API | * **ffi.enable=false** completely disables PHP FFI API | ||
Line 292: | Line 288: | ||
Accessing FFI data structures is significantly (about 2 times) slower, than accessing native PHP arrays and objects. It makes no sense to use them for speed, but may make sense to reduce memory consumption. This is true for all similar FFI implementations in interpretative mode. However, LuaJIT achieves improvement providing special support for FFI in its JIT. | Accessing FFI data structures is significantly (about 2 times) slower, than accessing native PHP arrays and objects. It makes no sense to use them for speed, but may make sense to reduce memory consumption. This is true for all similar FFI implementations in interpretative mode. However, LuaJIT achieves improvement providing special support for FFI in its JIT. | ||
- | The following table shows time of execution of **ary3** benchmark from bench.php. | + | The following table shows time of execution of **ary3** benchmark from bench.php |
<code php> | <code php> | ||
Line 336: | Line 332: | ||
ffi.enable=false|preload|true | ffi.enable=false|preload|true | ||
- | allows enabling or disabling FFI API usage, or restricting it only to preloaded files. The default value is **preload** | + | allows enabling or disabling FFI API usage, or restricting it only to preloaded files. The default value is **preload**. This is INI_SYSTEM directive and it's value can't be changed at run-time. |
===== Open Issues ===== | ===== Open Issues ===== | ||
Line 348: | Line 344: | ||
* Michael Wallner created [[https:// | * Michael Wallner created [[https:// | ||
* Sara Golemon thought, PHP needs something similar to [[https:// | * Sara Golemon thought, PHP needs something similar to [[https:// | ||
+ | |||
+ | The usability of this FFI extension was proved by [[https:// | ||
===== Future Scope ===== | ===== 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 | + | Currently, the performance of C data structures access is worse than access of native PHP data structures (arrays and objects). This is a common problem, and both LuaJIT (in interpretator mode) and Python |
===== Proposed Voting Choices ===== | ===== Proposed Voting Choices ===== | ||
- | Include FFI extension into PHP-7.4 | + | Include FFI extension into PHP-7.4 |
This project requires 50%+1 majority | This project requires 50%+1 majority | ||
+ | The voting started 2018-12-20 and will close on 2019-01-09 | ||
+ | |||
+ | <doodle title=" | ||
+ | * Yes | ||
+ | * No | ||
+ | </ | ||
===== Patches and Tests ===== | ===== Patches and Tests ===== | ||
Line 361: | Line 365: | ||
===== Implementation ===== | ===== Implementation ===== | ||
After the project is implemented, | After the project is implemented, | ||
- | - the version(s) | + | - it was merged into master (7.4) |
- | - a link to the git commit(s) | + | - a link to the git [[https:// |
- a link to the PHP manual entry for the feature | - a link to the PHP manual entry for the feature | ||
- | - a link to the language specification section (if any) | ||
===== References ===== | ===== References ===== | ||
Line 372: | Line 375: | ||
- [[https:// | - [[https:// | ||
- [[https:// | - [[https:// | ||
+ | - [[https:// | ||
===== Rejected Features ===== | ===== Rejected Features ===== | ||
Keep this updated with features that were discussed on the mail lists. | Keep this updated with features that were discussed on the mail lists. |
rfc/ffi.txt · Last modified: 2020/08/01 23:54 by carusogabriel