From: Peter Kokot Date: Wed, 8 May 2019 22:29:43 +0000 (+0200) Subject: Remove ffi README in favour of docs X-Git-Tag: php-7.4.0alpha1~309 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=4bfb86cdcab4451cef184d3770420bb9cf7ca121;p=php Remove ffi README in favour of docs - https://www.php.net/manual/en/book.ffi.php - The FFI C parser is mentioned in the CONTRIBUTING.md file --- diff --git a/ext/ffi/README.md b/ext/ffi/README.md deleted file mode 100644 index 8d18c2450d..0000000000 --- a/ext/ffi/README.md +++ /dev/null @@ -1,382 +0,0 @@ -# FFI PHP extension (Foreign Function Interface) - -FFI PHP extension provides a simple way to call native functions, access native -variables and create/access data structures defined in C language. The API of -the extension is very simple and demonstrated by the following example and its -output. - -```php -printf("Hello World from %s!\n", "PHP"); -var_dump($libc->getenv("PATH")); -var_dump($libc->time(null)); - -$tv = $libc->new("struct timeval"); -$tz = $libc->new("struct timezone"); -$libc->gettimeofday(FFI::addr($tv), FFI::addr($tz)); -var_dump($tv->tv_sec, $tv->tv_usec, $tz); -?> -``` - -```txt -Hello World from PHP! -string(135) "/usr/lib64/qt-3.3/bin:/usr/lib64/ccache:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/home/dmitry/.local/bin:/home/dmitry/bin" -int(1523617815) -int(1523617815) -int(977765) -object(FFI\CData:)#3 (2) { - ["tz_minuteswest"]=> - int(-180) - ["tz_dsttime"]=> - int(0) -} -``` - -`FFI::cdef()` takes two arguments (both are optional). The first one is a -collection of C declarations and the second is DSO library. All variables and -functions defined by first arguments are bound to corresponding native symbols -in DSO library and then may be accessed as FFI object methods and properties. C -types of argument, return value and variables are automatically converted -to/from PHP types (if possible). Otherwise, they are wrapped in a special CData -proxy object and may be accessed by elements. - -In some cases (e.g. passing C structure by pointer) we may need to create a real -C data structures. This is possible using `FFF::new()` method. It takes a C type -definition and may reuse C types and tags defined by `FFI::cdef()`. - -It's also possible to use `FFI::new()` as a static method to create arbitrary C -data structures. - -```php -x = 5; -$p[1]->y = 10; -var_dump($p); -``` - -```txt -object(FFI\CData:[2])#1 (2) { - [0]=> - object(FFI\CData:)#2 (2) { - ["x"]=> - int(5) - ["y"]=> - int(0) - } - [1]=> - object(FFI\CData:)#3 (2) { - ["x"]=> - int(0) - ["y"]=> - int(10) - } -} -``` - -## API reference - -### function FFI::cdef([string $cdef = "" [, string $lib = null]]): FFI - -#### Call native functions - -All functions defined in `FFI::cdef()` may be called as methods of the created -FFI object. - -```php -$libc = FFI::cdef("const char * getenv(const char *);", "libc.so.6"); -var_dump($libc->getenv("PATH")); -``` - -#### Read/write values of native variables - -All functions defined in `FFI::cdef()` may be accessed as properties of the -created FFI object. - -```php -$libc = FFI::cdef("extern int errno;", "libc.so.6"); -var_dump($libc->errno); -``` - -### function FFI::type(string $type): FFI\CType - -This function creates and returns a `FFI\CType` object, representng type of -the given C type declaration string. - -`FFI::type()` may be called statically and use only predefined types, or as a -method of previously created FFI object. In last case the first argument may -reuse all type and tag names defined in `FFI::cdef()`. - -### function FFI::typeof(FFI\CData $type): FFI\CType - -This function returns a `FFI\CType` object, representing the type of the given -`FFI\CData` object. - -### static function FFI::arrayType(FFI\CType $type, array $dims): FFI\CType - -Constructs a new C array type with elements of $type and dimensions specified by -$dims. - -### function FFI::new(mixed $type [, bool $own = true [, bool $persistent = false]]): FFI\CData - -This function may be used to create a native data structure. The first argument -is a C type definition. It may be a `string` or `FFI\CType` object. The -following example creates two dimensional array of integers. - -```php -$p = FFI::new("int[2][2]"); -var_dump($p, FFI::sizeof($p)); -``` - -`FFI::new()` may be called statically and use only predefined types, or as a -method of previously created FFI object. In last case the first argument may -reuse all type and tag names defined in `FFI::cdef()`. - -By default `FFI::new()` creates "owned" native data structures, that live -together with corresponding PHP object, reusing PHP reference-counting and GC. -However, in some cases it may be necessary to manually control the life time of -the data structure. In this case, the PHP ownership on the corresponding data, -may be manually changed, using `false` as the second optianal argument. Later, -not-owned CData should be manually deallocated using `FFI::free()`. - -Using the optional $persistent argument it's possible to allocate C objects in -persistent memory, through `malloc()`, otherwise memory is allocated in PHP -request heap, through `emalloc()`. - -### static function FFI::free(FFI\CData $cdata): void - -Manually removes previously created "not-owned" data structure. - -#### Read/write elements of native arrays - -Elements of native array may be accessed in the same way as elements of PHP -arrays. Of course, native arrays support only integer indexes. It's not possible -to check element existence using `isset()` or `empty()` and remove element using -`unset()`. Native arrays work fine with "foreach" statement. - -```php -$p = FFI::new("int[2]"); -$p[0] = 1; -$p[1] = 2; -foreach ($p as $key => $val) { - echo "$key => $val\n"; -} -``` - -#### Read/write fields of native "struct" or "union" - -Fields of native struct/union may be accessed in the same way as properties of -PHP objects. It's not possible to check filed existence using `isset()` or -`empty()`, remove them using `unset()`, and iterate using "foreach" statement. - -```php -$pp = FFI::new("struct {int x,y;}[2]"); -foreach($pp as $n => &$p) { - $p->x = $p->y = $n; -} -var_dump($pp); -``` - -#### Pointer arithmetic - -CData pointer values may be incremented/decremented by a number. The result is a -pointer of the same type moved on given offset. - -Two pointers to the same type may be subtracted and return difference (similar -to C). - -### static function FFI::sizeof(mixed $cdata_or_ctype): int - -Returns size of C data type of the given `FFI\CData` or `FFI\CType`. - -### static function FFI::alignof(mixed $cdata_or_ctype): int - -Returns size of C data type of the given `FFI\CData` or `FFI\CType`. - -### static function FFI::memcpy(FFI\CData $dst, mixed $src, int $size): void - -Copies $size bytes from memory area $src to memory area $dst. $src may be any -native data structure (`FFI\CData`) or PHP `string`. - -### static function FFI::memcmp(mixed $src1, mixed $src2, int $size): int - -Compares $size bytes from memory area `$src1` and `$dst2`. `$src1` and `$src2` -may be any native data structures (`FFI\CData`) or PHP `string`s. - -### static function FFI::memset(FFI\CData $dst, int $c, int $size): void - -Fills the $size bytes of the memory area pointed to by `$dst` with the constant -byte `$c`. - -### static function FFI::string(FFI\CData $src [, int $size]): string - -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. - -### function FFI::cast(mixed $type, FFI\CData $cdata): FFI\CData - -Casts given $cdata to another C type, specified by C declaration `string` or -`FFI\CType` object. - -This function may be called statically and use only predefined types, or as a -method of previously created FFI object. In last case the first argument may -reuse all type and tag names defined in `FFI::cdef()`. - -### static function addr(FFI\CData $cdata): FFI\CData - -Returns C pointer to the given C data structure. The pointer is not "owned" and -won't be free. Anyway, this is a potentially unsafe operation, because the -life-time of the returned pointer may be longer than life-time of the source -object, and this may cause dangling pointer dereference (like in regular C). - -### static function load(string $filename): FFI - -Instead of embedding of a long C definition into PHP string, and creating FFI -through `FFI::cdef()`, it's possible to separate it into a C header file. Note, -that C preprocessor directives (e.g. `#define` or `#ifdef`) are not supported. -And only a couple of special macros may be used especially for FFI. - -```c -#define FFI_LIB "libc.so.6" - -int printf(const char *format, ...); -``` - -Here, FFI_LIB specifies, that the given library should be loaded. - -```php -$ffi = FFI::load(__DIR__ . "/printf.h"); -$ffi->printf("Hello world!\n"); -``` - -### static function scope(string $name): FFI - -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 definitions and libraries at php startup, and -instantiate FFI objects when necessary. Header files may be extended with -`FFI_SCOPE` define (default pre-loading scope is "C"). This name is going to -be used as `FFI::scope()` argument. It's possible to pre-load few files into a -single scope. - -```c -#define FFI_LIB "libc.so.6" -#define FFI_SCOPE "libc" - -int printf(const char *format, ...); -``` - -These files are loaded through the same `FFI::load()` load function, executed -from file loaded by `opcache.preload` php.ini directive. - -```ini -ffi.preload=/etc/php/ffi/printf.h -``` - -Finally, `FFI::scope()` instantiates an `FFI` object, that implements all C -definitions from the given scope. - -```php -$ffi = FFI::scope("libc"); -$ffi->printf("Hello world!\n"); -``` - -## Owned and not-owned CData - -FFI extension uses two kind of native C data structures. "Owned" pointers are -created using `FFI::new([, true])`, `clone`d. Owned data is deallocated -together with last PHP variable, that reference it. This mechanism reuses PHP -reference-counting and garbage-collector. - -Elements of C arrays and structures, as well as most data structures returned by -C functions are "not-owned". They work just as regular C pointers. They may leak -memory, if not freed manually using `FFI::free()`, or may become dangling -pointers and lead to PHP crashes. - -The following example demonstrates the problem. - -```php -$p1 = FFI::new("int[2][2]"); // $p1 is owned pointer -$p2 = $p1[0]; // $p2 is not-owned part of $p1 -unset($p1); // $p1 is deallocated ($p2 became dangling pointer) -var_dump($p2); // crash because dereferencing of dangling pointer -``` - -It's possible to change ownership, to avoid this crash, but this would require -manual memory management and may lead to memory leaks. - -```php -$p1 = FFI::new("int[2][2]", false); // $p1 is not-owned pointer -$p2 = $p1[0]; -unset($p1); // $p1 CData is keep alive (memory leak) -var_dump($p2); // works fine, except of memory leak -``` - -## PHP callbacks - -It's possible to assign PHP function to native function variable (or pass it as -a function argument). This seems to work, but this functionality is not -supported on all libffi platforms, it is not efficient and leaks resources by -the end of request. - -## FFI API restriction - -With FFI users may do almost anything, like in C, and therefor may crash PHP in -thousand ways. It's possible to completely disable or enable all FFI functions -using `ffi.enable=0/1` configuration directives, or limit FFI usage to preloaded -scripts using `ffi.enable=preload` (this is the default setting). In case FFI is -not completely disabled, it's also enabled for CLI scripts. Finally, the -restriction affects only FFI functions their selves, but not the overloaded -method of created FFI or CData objects. - -## Status - -In current state, access to FFI data structures is significantly (about 2 times) -slower, than access to PHP arrays and objects. It makes no sense to use them for -speed, but may make sense to reduce memory consumption. - -FFI functionality may be included into PHP-8 core, to provide better -interpretation performance and integrate with JIT, providing almost C -performance (similar to LuaJIT). - -## Requirement - -* [libffi-3.*](https://sourceware.org/libffi/) - -## Installation - -```bash -./configure ... --with-ffi -make -sudo make install -``` - -## Real usage - -FFI extension was used to implement -[PHP TensorFlow binding](https://github.com/dstogov/php-tensorflow). - -## FFI parser - -FFI C parser is generated using [LLK](https://github.com/dstogov/llk).