PHP FFI : Introduction – partie 1


Introduction

Depuis la version 7.4 de PHP nous avons enfin accès aux fonctions d’interopérabilité entre les différents languages et PHP: le FFI ou Foreign function interface.

FFI c’est quoi ? 
C’est tout simplement la possibilité d’utiliser une librairie externe (.dll ou .so) directement dans PHP, et ce, sans avoir à créer un module PHP. 
Oui oui, juste avec un script PHP ! 
C’est entre autre ce qui à fait la gloire de python et lui a permis d’avoir tant de fonctionnalités.

Ce qui est génial avec FFI c’est qu’un développeur PHP non-expert en C/Rust/Go/Kotlin (liste non exhaustive) peut enfin lier une librairie externe par lui même. Ainsi, si vous avez un projet avec un besoin hyper spécifique, une lib propriétaire ou que sais-je encore et que vous n’avez pas trop de charge vous pouvez directement vous coller au dev de l’utilisation de celle-ci. 
Ça arrive rarement, mais ici chez partITech, ça nous est quand même arrivé de devoir développer des module PHP. Du coup, le fait de développer directement la liaison avec la lib en PHP devrait rendre la procédure bien plus simple et rapide à déployer.

Bien entendu ce jeu de fonction a un coût car, même si la procédure permet d’aller plus vite en développement, elle reste moins rapide qu’un vrai module PHP écrit en c/c++. 
En effet, accéder aux structures avec FFI est pour le moment 2 fois moins rapide qu’avec un module natif. Il n’est donc pas recommandé d’utiliser FFI pour améliorer les performances de votre application. En revanche, il peut grandement vous aider à réduire la mémoire utilisée sur des process très gourmands. (source https://www.php.net/manual/fr/intro.ffi.php).

Bon, les intros et les blah-blah très peu pour nous. Ce qu’on veut voir c’est du code. 
Donc je vous propose de voir plusieurs problématiques rencontrées lors de nos tests. Bien entendu chaque projet est différent mais si cet article peut vous aider à mettre les mains dans le « bousin » on sera content.

Le hello world

Le test basique de référence restant le fameux « Hello world », nous allons débuter notre voyage dans le monde merveilleux des FFI avec une fonction C qui va nous retourner « Hello world ».

hello.c

#include <stdio.h>

 const char * hello() {
   return "Hello, World!";
}

hello.h

export const char * hello();

On peut à présent compiler.

gcc -c hello.c

On demande à gcc de nous créer notre librairie partagée, le fameux fichier .so

gcc -shared -o hello.so hello.o

Voilà ! A présent nous avons notre matière pour jouer avec PHP-ffi directement.

Voici le code PHP nous permettant d’appeler notre fonction hello()

hello.php

#!/usr/bin/php8.1
<?php
$ffi = FFI::cdef(
    "const char *hello();",
    __DIR__ ."/hello.so"
);

echo $ffi->hello();
chmod +x hello.php
./hello.php
Hello, World!

Explications :

La méthode cdef nous permet de créer un nouvel objet FFI. Le premier paramètre est une chaîne contenant la définition de notre librairie. On est pas obligé de mettre l’intégralité des informations de la librairie, seulement ce qui nous intéresse.

A noter que si vous utilisez des header files un peu complexe, il y a de fortes chances pour que ça plante directement. De ce que j’ai pu utiliser, j’ai systématiquement recréé et simplifié les fichiers de définitions. 
Nous verrons dans un autre exemple comment créer et utiliser directement un header file un peu trop gros pour être posé directement dans notre script. Ça peut rapidement devenir compliqué 🙂

Le second paramètre est notre librairie partagée. Pas vraiment besoin d’expliquer.

Finalement on va directement appeler la fonction et faire un echo du résultat.

Simple…Basique.

On passe à un exemple un petit peu plus poussé ? Rendez vous dans la seconde partie de notre dossier sur le monde merveilleux des Foreign Function Interfaces.

PHP FFI: Passage de paramètres et utilisation le zend engine – partie 2

Merci à Thomas Bourdin, Cédric Le Jallé, Stéphane Péchard pour leur aide, conseils et relecture.