Who is using FFI?

Viewing 8 posts - 1 through 8 (of 8 total)
  • Author
    Posts
  • #1828
    brendt_gd
    Participant

    I’ve seen some cool examples around the internet of how FFI can be used (eg https://github.com/gabrielrcouto/awesome-php-ffi) but I’m wondering who is using it for real. What do you use it for? How was it like to write FFI code?

    #1829
    kiler129
    Guest

    I do πŸ˜‰

    https://github.com/kiler129/snmp-mib-parser

    It’s an amazing way to use C libraries in the native PHP to do things which were hardly (if even) possible without it.

    #1831
    ojrask
    Guest

    A little. I have a data parser that interacts with PHP over FFI. The lib itself is in Rust and I compile a C-ABI dynamic lib from it, which sits right in via FFI.

    #1832
    Crell
    Guest

    I’ve only used it for writing documentation and examples of it. πŸ™‚

    https://platform.sh/blog/2020/php-fun-with-ffi-just-enough-c/

    https://platform.sh/blog/2020/php-fun-with-ffi-c-php-run/

    https://platform.sh/blog/2020/php-fun-with-ffi-getting-rust-ic/

    https://github.com/platformsh-examples/php-ffi

    Overall, the API was frankly super finicky. It’s not well designed, and the custom C header parser is hella buggy. (I covered all of that in detail in the articles above.) All that said, it *does* work, and if you have CPU-intensive tasks to do or existing libraries to leverage it’s worth the effort, especially compared to “write a custom extension” (which… no.) The clunky API and security implications mean we’re unlikely to see major distributed FFI modules gain widespread use, but for, say, offline machine learning libraries (where if you’re doing that, you have enough server control to set it up safely and performantly) it should be a game changer.

    #1837
    dhope0000
    Guest

    Oh FFI – how I wish you were simple

    Im no C/CPP dev – but with Dunning Kruger in full effect I tried to import [https://github.com/LibreDWG/libredwg](https://github.com/LibreDWG/libredwg) at work for … reasons

    Then I started having to reproduce every struct because PHP wont “just find them” which made things “head hurty” (I appreciate writing a `.h` parser is probably not easy, but come on **every** struct has to be redefined in PHP’s version of the `.h` file? In large complex projects that’s a bit of a meme, also I think PHP moaned about some types(?) I cant quite remember that may have been me)

    In the end I could run the external function but I hit mysterious segfaults (that you didn’t hit with the “raw” program with the same input) – like I said im no C/CPP guy so `strace` and all the other good tools are just a mystery to me (this make me lazy not PHP)

    *(Please feel free to take that as invitation to prove me an idiot & make it open source)*

    #1838
    tored950
    Guest

    I’m using it to write desktop applications using IUP ([http://webserver2.tecgraf.puc-rio.br/iup/](http://webserver2.tecgraf.puc-rio.br/iup/)). I also call into the Win32 API when need, e.g. setting DPI awareness for high resolution screens and similar things like that.

    I started with writing FFI code against the Win32 GUI API, however it just a mess & way to much bureaucracy, lots of C type definitions, especially structs. IUP on the other hand is a very well written C library that it easy to call into. I looked into many GUI libraries and unfortunately many of them are hard to use over FFI (lots of C macros and structs). I guess most of them are designed to be used from C or C++, IUP on the other hand was designed from the beginning to be used with Lua.

    It takes a bit time to adapt to writing desktop application with PHP instead of web application. It has to do how you want to layout your code in an understandable architecture that makes sense in a long running application.

    One thing I do is to treat my FFI wrapper similar to the PHP standard library, i.e. I don’t do dependency injection with my FFI wrapper, I call static methods on my FFI wrapper similar how you would call the PHP standard library.

    This makes sense when you want to create building blocks of widgets. For your Button PHP class it makes more sense to write

    `$button = new Button();`

    than

    `$button = new Button($ffi_wrapper);`

    That last one just becomes tedious. You probably wont have multiple FFI instances of the same C library anyway and if you need to mock it I guess it is better to adapt it so it works as a Laravel facade.

    On my FFI wrapper class i use `__callStatic` magic method to call into the FFI instance. I use PHPDoc `@method static` to describe what functions I’m exposing on my FFI wrapper. And if needed I could make separate static function, perhaps if I would run into some type juggling problems. My first tries I used separate PHP functions to call into FFI on my wrapper class, but it didn’t really give any benefit, PHPDoc is good enough. FFI layer will scream on type mismatch anyways.

    The C header I store as a `private const` inside the FFI wrapper and I initiate the FFI instance my using `FFI::cdef`. This is much easier to handle than loading a separate header file. This means I just copy the C function definition by hand into my PHP code and I then add the PHPDoc manually.

    What can give you problems if you need to do type juggling between PHP types and C types manually. If you are calling a C function that takes `const char*` as parameter you can send in a PHP string & that will work.

    However if you need to create a C struct that has a `const char*` member you can’t assign your PHP string to that member directly, you have to manually create that `char*` type and start copying memory into it which is of course much more cumbersome. Generally avoid C libraries that overuse structs in its API or if you are writing a C library yourself.

    IUP is great in that sense because it returns opaque C pointers for you objects and you use that pointer as a function argument on other C functions to get or set data. No need to know what that pointer describes.

    ​

    I also had a problem with to read a value from C void pointer, a Win32 API function returned a `HANDLE` that could be -1 if failed, the C void pointer was stored inside a `FFICData` instance. Solution was to use `FFI::cast(‘void*’, -1) == $handle`. Those things are not always obvious to figure out and requires testing & extensive googling into other programming languages FFI libraries.

    I haven’t open sourced any of my FFI code, the application I’m writing at the moment will be closed source but I’m thinking of releasing the IUP wrapper & the widget classes.

    #1839
    sj-i
    Guest

    I’m working on a phpspy-like profiler written in PHP. It uses FFI to call OS APIs like ptrace and proces_vm_readv.
    https://github.com/sj-i/php-profiler

    If you have a bit of C experience and much more of PHP, then by using FFI, PHP would suddenly become a language to write interesting tools interacting with OS specific functionalities.

    I think the API of FFI is not mature though. For example, handling types of CData values tends to be code that lie to static analyzers. I wish if there was a safer and easier way of mapping C types to PHP types.

    #1841
    PonchoVire
    Guest

    I do not use it as of now, but I’m seriously thinking about it when I have performance problems related to computational algorithm, which means as of today, never happened. But I keep it in mind in case it happens one day. This day, I’ll either go for wasmer and webassembly, or PHP FFI if I want to avoid external dependencies, in both case, I’ll use rust. But, I had not the chance to stumble on a such worse performance problem that would allow my company to accept I do that in production project yet.

Viewing 8 posts - 1 through 8 (of 8 total)
  • You must be logged in to reply to this topic.