PHP FFI
В ПХП 7.4 предпринята очередная попытка обзавестись интерфейсом к языку Си. Кажется наконец за это расширение взялись по-серьёзному, и его поддержка не исчезнет со временем, как это уже случалось ранее с прошлыми реализациями.
Для интереса посмотрел что за АПИ получилось. В принципе, всё очень просто. Вот как выглядит функция-обёртка вокруг вызова mkdtemp с обработкой ошибок (проверял у себя на «Маке»):
/**
* @method object mkdtemp(string $template)
* @method object strerror(int $errnum)
* @property-read int $errno
*/
$ffi = FFI::cdef('
// Импортируем функцию создания временного директория
char *mkdtemp(char *template);
// Импортируем функцию перевода кодов ошибок в строку
char *strerror(int errnum);
// Импортируем переменную, хранящую коды ошибок
int errno;
');
/**
* Фунция для создания временных директориев по маске
* @param string $template Шаблон создания (см. man mkdtemp)
* @return string Путь до временного директория
*/
$mkdtemp = function (string $template) use ($ffi): string {
$result = $ffi->mkdtemp($template);
if ($result === null) {
$errno = $ffi->errno;
$errstr = $ffi->strerror($errno);
throw new RuntimeException(FFI::string($errstr), $errno);
}
return FFI::string($result);
};
Как можно понять из кода, создаётся объект, в который импортируются сущности, перечисленные в сишной нотации в первом параметре. В общем случае вторым параметром требуется указать библиотеку для импорта, но в данном случае работает и так.
Не знаю заработает ли этот код без изменений под Линуксом и Виндоузом, у кого есть под рукой, посмотрите, пожалуйста.
В этом примере параметры в импортированные функции передаются как обычные типы ПХП, а некоторые возвращаемые значения требуют конвертации. Так char * возвращается как специальный объект, который нужно преобразовывать в строку вызовом метода FFI::string.
Вот тривиальный текстовый пример использования созданной выше функции:
$template = implode(DIRECTORY_SEPARATOR, [sys_get_temp_dir(), 'ffiphp.XXXXXX']);
try {
$tmp = $mkdtemp($template);
rmdir($tmp);
echo $tmp, "\n";
} catch (RuntimeException $e) {
echo $e->getMessage(), "\n";
}
Суть происходящего проста: если директорий удалось создать, то он будет уничтожен, а его имя — выведено на экран, иначе появится текстовое сообщение об ошибке.
Под Линуксом работает.
Спасибо!