Speeding PHP with FFI

Speeding PHP with FFI

FFI is an experimental extension that allows us to use an external library (.so or .dll), without creating an extension. This library could be preloaded or loaded per each request. It is recommended to runs it preloaded but it's easy to load per request.

What we could do with FFI?

For example, we could use C, C++, Rust, or practically any language that allows us to create a library (C style). It could increase the performance of our tenfold times. In my initial test, a simple loop with doubles executes 800% fastest than in native PHP.

1) Creating the library

For this example, I will use CLion (ide),mingw64 as the toolchain but we could use any ide or toolchain. I also use Windows.

We will create a shared library for C (shared means a .so or .dll file)

Alt Text

Don't forget to set the toolchain.

Alt Text

Code

library.c

#include "library.h"

const char* ping(const char *pong) {
    return pong;
}

This code is simple, it has a simple function with a string argument and it returns the same string, i.e. it is a pong-pong function.

library.h

#define FFI_SCOPE "MYLIB"
#define FFI_LIB "C:\CLionProjects\untitled\cmake-build-debug\libuntitled.dll"

const char* ping(const char *pong);

What is the value of FFI_LIB? Is the path where the library (DLL or so) is compiled. We are not compiled but we need to edit it. So, right now you can write any value.

FFI_SCOPE is also the "scope" (i.e. some sort of namespace) of our library.

Compilation

It is our compilation

====================[ Build | all | Debug ]=====================================
"D:\Program Files\JetBrains\CLion 2020.2\bin\cmake\win\bin\cmake.exe" --build C:\CLionProjects\untitled\cmake-build-debug --target all -- -j 9
Scanning dependencies of target untitled
[ 50%] Building C object CMakeFiles/untitled.dir/library.c.obj
[100%] Linking C shared library libuntitled.dll
[100%] Built target untitled

Build finished

And we found where our library is compiled correctly in some path. So now, we could edit our .h file and put the correct path. We need to do it if we want to use the .h directly in PHP.

2) MinGW64

(Optional) I'm using the MinGW toolchain. It includes GCC libraries and other stuff. If we want to use their libraries, then we could add to the path or we could include the libraries inside ours.

CMakeLists.txt

cmake_minimum_required(VERSION 3.17)
project(untitled7)

set(CMAKE_CXX_STANDARD 14)
set(CMAKE_EXE_LINKER_FLAGS "-static")

set(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++ -static")
set(CMAKE_SHARED_LINKER_FLAGS "-static-libgcc -static-libstdc++ -static")


add_library(untitled7 SHARED library.cpp library.h)

We need to add the lines -static-libgcc for C or -static-libstdc++ for C++ (or both).

3) Configuring PHP

First, we need to install and enable the FFI extension. it requires PHP 7.4 or higher.

If you are using Linux, then you will need to recompile with the FFI extension.

php.ini

extension=ffi
[ffi]
ffi.enable=true

Note: We shouldn't forget to restart our web server.

We could preload FFI but for our example, we will load it per request.

PHPInfo should show the next information

Alt Text

4) Our PHP code (First alternative)

There are two ways to call our code, with FFI::cdef and FFI:load. FFI::cdef requires the library and the definition of it.

<?php

$file='C:\CLionProjects\untitled\cmake-build-debug\libuntitled.dll'; // the path of our dll
$ffi=FFI::cdef('const char* ping(const char *pong);',$file);

var_dump($ffi->ping("hello world")); // string(11) "hello world"

5) Our PHP Code (Second alternative)

The second alternative is to use the .h file defined in our code. This code requires that our .h file has the next lines

#define FFI_SCOPE "MYLIB"
#define FFI_LIB "C:\CLionProjects\untitled\cmake-build-debug\libuntitled.dll"

And we could call our code as follow

<?php

$hfile='C:\CLionProjects\untitled\library.h'; // the path of our .h file.
$r2=FFI::load($hfile);
var_dump($r2->ping("hello world")); // string(11) "hello world"

About Jorge Castro

Currently: Entrepreneur and Private Consultant
Civil Engineer in Informatics - USACH Chile.
Master in Business Administration (MBA) CEPADE Spain
Microsoft Certified Professional
Oracle Certified Associate
ScrumMaster Certified
Former developer
Former Project Manager

Related Posts