6

PHP FFI and what it can do for you

 2 years ago
source link: https://devm.io/php/php-ffi-and-what-it-can-do-for-you
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

FFI in PHP

PHP FFI and what it can do for you


PHP 7.4 brings a lot of exciting new features. One of them is the Foreign Function Interface extension built directly into the core. But what problems exactly this extension is trying to solve? Does this mean that we no longer need to write a PHP extension if we want to use an existing library? In this article, we will discover how to call almost any C library directly from PHP easily, how to overcome common pitfalls, when to use this approach, and most importantly, when not.

When we read the PHP 7.4 release announcement, we can see that it brings many exciting new features, such as typed properties, preloading, and FFI – foreign function interface. Some of these features have been long-awaited. For instance, typed properties, a few of them were quite surprising. Regardless of this, one thing is clear, from all mentioned features, “FFI – foreign function interface” is the least self-explanatory.

So, what is FFI? According to Wikipedia, it is: “a mechanism by which a program written in one programming language can call routines or make use of services written in another.”. But this is merely a book definition, which does not tell us what real-world problems can be solved. This left us with a more proper question: What problems does FFI solve?

FFI in PHP

FFI can help you if you want to reuse a code that is already written in an entirely different programming language. For example, you have a connector to a database that has not yet been ported to PHP. Another possible usage is to speed up some parts of your code. In this case, you can write an algorithm in the programming language that can provide a better performance for your use; for instance, when you want to do some complicated scientific calculations. Finally, you can do something that is not supported in your language. To illustrate this, you can communicate with hardware.

You may ask yourself, wait, can we not already do all of this with PHP extensions? The answer is yes. We can do all of the mentioned tasks with the help of PHP extensions. But FFI still has its merits as it promises more straightforward usage, easier maintenance or deployment, and better portability across PHP versions. The main reason for this is that you can do everything in plain PHP, so there is no need to set a compilation toolkit or change deployment procedures.

Regarding portability, the PHP extension API can vary across versions, which usually leads to a need to recompile the whole extension. Another possible benefit is that there is no need to learn any new programming language. We are still in PHP, right? Well, this is more complicated, as we will see later.

There are a few limitations of FFI in comparison with extensions. You cannot easily modify how PHP works internally, so there is no easy way to create debug tools such as Xdebug. Also, PHP extensions are usually faster as they are made in compiled languages. The last limitation is that FFI supports only one target language; often, this language is C.

FFI is implemented in PHP 7.4 through a brand new extension that is part of the core and always available. It is also more mature than previous attempts on FFI in the PHP ecosystem and multiplatform, at least to some degree. The main caveat is that the extension allows the programmer to call only C libraries or with libraries providing so called “C ABI”.

First steps

We will illustrate basic usage of FFI by rewriting abs() function, which returns an absolute value of provided number:

Listing 1: abs.php

<?php
$ffi = FFI::cdef(
    'int abs(int j);', // function declaration in C language
    'libc.so.6'        // library from which the function will be called
);
 
var_dump($ffi->abs(-42)); // int(42)

The first thing we have to do is to create a proxy object between the library and PHP. One of the biggest challenges in FFI, regardless of programming language, is how to map functions from one programming language in another one. Authors of FFI in PHP decided that the best way to handle this is by parsing a C function definition. So it is no surprise that the first argument contains a function declaration in C language. The second parameter must be the name of the library from which the function will be called. In this case, we are trying to use functions from the standard C library.

Code samples

All provided code samples require minimum version of PHP 7.4 and operating system Linux or Windows with WSL. They cannot be run in standard Windows or Mac OS. The complete source code is available at https://github.com/kambo-1st/php-ffi-article together with prepared Docker image.

The function signatures are quite similar in PHP and in C. After all, PHP is a C-style language. Nevertheless, there are a few differences:

  • Variable types must always be defined.
  • The return type is declared before the function name.

The function is then called through a method of the same name on the proxy object. Simple data types such as integer, float, and boolean are automatically converted during the function call. Automatic conversion can sometimes be a double-edged sword, especially for the PHP developers, as we will illustrate on the following snippet:

Listing 2: abs-data-type.php

<?php
$ffi = FFI::cdef(
   'int abs(int j);
    long int labs(long int j);',
   'libc.so.6'
);
 
var_dump($ffi->abs(-2147483649));  // int(2147483647)
var_dump($ffi->labs(-2147483649)); // int(2147483649)

In this snippet, we first try to call the abs() function with a value outside of the C integer range. Thanks to that, the result value will overflow, and the function returns the wrong result. PHP counterpart of the abs() function will handle float and integer value without issue. If we want to get a proper number, we have to call labs() that will work with values outside of C integer type. Data types in C are much richer than in PHP, and this must be considered during the function call.

Complex data types

Unfortunately, complex data types such as arrays cannot be handled straightforwardly. We will demonstrate this on the example of a Quicksort algorithm from the standard C library:

Listing 3: pass-php-array.php

<?php
$ffi = FFI::cdef(
            "void qsort (void *array, size_t count, ...

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK