PHP FFI: Introducción – Parte 1


Introducción

Desde la versión 7.4 de PHP, finalmente tenemos acceso a funciones de interoperabilidad entre diferentes lenguajes y PHP: FFI o Interfaz de Función Externa.

¿Qué es FFI?
Es simplemente la capacidad de utilizar una biblioteca externa (.dll o .so) directamente en PHP, sin tener que crear una extensión de PHP.
¡Sí, con solo un script de PHP!
Es, entre otras cosas, lo que ha hecho que Python sea tan famoso y le haya permitido tener tantas características.

Lo grandioso de FFI es que un desarrollador de PHP que no es experto en C/Rust/Go/Kotlin (lista no exhaustiva) finalmente puede vincular una biblioteca externa por sí mismos. Entonces, si tienes un proyecto con una necesidad muy específica, una biblioteca propietaria o lo que sea, y no tienes demasiada carga, puedes abordar directamente el desarrollo de su uso.
Rara vez sucede, pero aquí en partITech, hemos tenido que desarrollar módulos de PHP. Como resultado, desarrollar la conexión con la biblioteca en PHP debería hacer el procedimiento mucho más simple y rápido de implementar.

Por supuesto, esta funcionalidad tiene un costo, ya que, aunque el procedimiento permite un desarrollo más rápido, es menos ágil que un verdadero módulo de PHP escrito en C/C++.
De hecho, acceder a estructuras con FFI es actualmente dos veces más lento que con un módulo nativo. Por lo tanto, no se recomienda usar FFI para mejorar el rendimiento de tu aplicación. Sin embargo, puede ayudarte enormemente a reducir el uso de memoria en procesos muy exigentes. (fuente https://www.php.net/manual/en/intro.ffi.php).

Bien, basta con las introducciones y charlas. Lo que queremos ver es código.
Así que, propongo que miremos varios problemas encontrados durante nuestras pruebas. Por supuesto, cada proyecto es diferente, pero si este artículo puede ayudarte a ensuciarte las manos con las "entrañas", estaremos contentos.

El Hola Mundo

La prueba de referencia básica sigue siendo el famoso "Hola Mundo", así que comencemos nuestro viaje hacia el maravilloso mundo de FFI con una función C que nos devolverá "Hola Mundo".

hello.c

#include <stdio.h>

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

hello.h

export const char * hello();

Ahora podemos compilar.

gcc -c hello.c

Le pedimos a gcc que cree nuestra biblioteca compartida, el famoso archivo .so.

gcc -shared -o hello.so hello.o

¡Ahí lo tienes! Ahora tenemos nuestro material para jugar directamente en PHP-ffi.

A continuación se muestra el código PHP que nos permite llamar a nuestra función 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!

Explicaciones:

El método cdef nos permite crear un nuevo objeto FFI. El primer parámetro es una cadena que contiene la definición de nuestra biblioteca. No estamos obligados a poner toda la información de la biblioteca, solo lo que nos interesa.

Ten en cuenta que si usas archivos de cabecera algo complejos, hay muchas posibilidades de que se caiga directamente. De lo que he podido usar, he recreado y simplificado sistemáticamente los archivos de definición.
Veremos en otro ejemplo cómo crear y usar directamente un archivo de cabecera demasiado grande para colocarse directamente en nuestro script. Puede volverse complicado rápidamente 😊

El segundo parámetro es nuestra biblioteca compartida. No hay necesidad real de explicar.

Finalmente, llamaremos directamente a la función y mostraremos el resultado.

Simple... Básico.

¿Pasamos a un ejemplo un poco más avanzado? Nos vemos en la segunda parte de nuestro dossier sobre el maravilloso mundo de la Interfaz de Funciones Externas.

PHP FFI: Pasar parámetros y usar el motor zend - parte 2

Gracias a Thomas Bourdin, Cédric Le Jallé, y Stéphane Pechard por su ayuda, consejos y corrección de pruebas.