This is a PHP SAPI written in PHP via FFI, or in other words, PHP embedded in itself.
$ cat test.php
<?php
echo "Hello from inside PHP meta-SAPI\n";
$ ./php-meta-sapi.php
php_meta_sapi > return 42
int(42)
php_meta_sapi > return 'a'
string(1) "a"
php_meta_sapi > function f() { echo "43\n"; } f();
43
php_meta_sapi > test.php
Hello from inside PHP meta-SAPI
php_meta_sapi > ^C
$
- PHP 8.3.x compiled with
--with-readline
and--enable-embed
Technically, php-meta-sapi.php
loads libphp.so
from the embed
SAPI via FFI
to define and run a custom PHP-scriptable meta
SAPI. The loop
method could
be anything, but for this example, I implemented a simple REPL. Each line
entered in the REPL represents one request in the meta
SAPI. In effect this is
similar to invoking eval
but with more control over runtime behavior via SAPI
callbacks.
I've only tested php-meta-sapi.php
via the cli
SAPI, but if you subtract the
readline
stuff it should work in other SAPIs as well.
I wrote this mainly to satisfy a personal curiosity. It may not have immediate practical uses. One possible use is to invoke ZTS extensions through a non-ZTS build. (h/t @sj-i for that idea.)
Related TODOs:
-
Add support for variadic closures in FFI. This would allow us to properly implement the
sapi_error
callback. -
Experiment with loading FFI targets via
dlmopen
instead ofdlopen
here. I think that would enable driving multiple SAPIs in the same process.