symplely / zend-ffi
提供创建扩展或使用FFI修改Zend/PHP内部核心的基API。
Requires
- php: >7.4
- ext-ffi: *
This package is auto-updated.
Last update: 2024-08-23 04:20:06 UTC
README
提供创建扩展或修改使用FFI的Zend/PHP
内部核心的基API。
- 适用于PHP 7.4, 8.0, 8.1, 8.2, Windows, Mac, Linux
允许加载共享库(.dll
或.so
),调用C函数和访问纯PHP
中的C类型数据结构。
此包将Zend扩展API
分解为获取对所有PHP内部操作的直接访问的PHP类。您实际上可以更改PHP默认行为。您将能够获得componere扩展的行为,而无需安装它。
这里许多例程是对Z-Engine库包的重写,使用了不同的术语和设置结构。此包遵循/保留PHP C
源代码风格,并具有骨架FFi安装过程。
在Pecl上有很多尚未更新的扩展。
安装
对于正常独立使用。
composer require symplely/zend-ffi
设置FFI集成的骨架。
composer create-project symplely/zend-ffi .
最低php.ini
设置
extension=ffi extension=openssl extension=sockets zend_extension=opcache [opcache] ; Determines if Zend OPCache is enabled opcache.enable=1 ; Determines if Zend OPCache is enabled for the CLI version of PHP opcache.enable_cli=1 [ffi] ; FFI API restriction. Possible values: ; "preload" - enabled in CLI scripts and preloaded files (default) ; "false" - always disabled ; "true" - always enabled ffi.enable="true" ; List of headers files to preload, wildcard patterns allowed. `ffi.preload` has no effect on Windows. ; See headers directory for `your-php-version`, this feature is untested, since not enabled for Windows. ;ffi.preload=path/to/vendor/symplely/zend-ffi/headers/ze(your-php-version).h ;This feature is untested. ;opcache.preload==path/to/vendor/symplely/zend-ffi/preload.php
对于简单的FFI集成过程创建/编辑
ffi_extension.json
每个包/库应列出要预加载的文件,将由ffi_preloader.php
脚本处理。.ignore_autoload.php
将在composer create-project your_package .cdef/foldername
事件中调用/执行。- 此事件仅在您的包由
composer create-project
命令安装时调用。
- 此事件仅在您的包由
.preload.php
用于通用常用FFI函数,更改tag_changeMe
骨架名称。.github\workflows\*.yml
这些GitHub Actions旨在用于交叉编译并将二进制
返回到您的repo
,更改some_lib
和some_repo
骨架名称。- 这个想法是将安装完全自包含,必要的第三方库二进制文件已打包在内。
- CI构建动作仅用于手动运行。
// Skeleton for `ffi_extension.json` file { // The same name to be used in `composer create-project package .cdef/foldername` "name": "foldername", // Either "preload": { "files": [ "path/to/file.php", "...", "..." ], // Or "directory": [ "path/to/directory" ] } }
文档
应使用或扩展preload.php和Functions.php中的函数。
有关示例,请参阅测试文件夹。将代码复制/粘贴到--FILE--
和--EXPECT--
块之间在.phpt
文件中。
有关一般FFI C数据
处理,请参阅CStruct
类。
函数c_int_type()
、c_struct_type()
、c_array_type()
和c_typedef()
是任何C数据typedef的包装器,将其转换为PHP CStruct类实例,具有所有FFI函数作为方法以及附加功能。
有关AST处理
zend_parse_string()
将 PHP 源代码转换为保存在 ZendAst 类中的本地 C 数据zend_ast
节点,使用print_ast()
来显示结果。- 使用
zend_ast_process(function(\ZE\AstProcess $hook){})
来在编译过程后拦截和修改 AST。
获取像 nikic/php-ast 和 sgolemon/astkit 这样的 PHP 扩展的行为,这些扩展提供了对底层 AST 结构的低级绑定,无需任何额外库。
只需扩展 StandardModule 抽象类 就可以实现整个 PHP 生命周期过程。
declare(strict_types=1); require 'vendor/autoload.php'; final class SimpleCountersModule extends \StandardModule { protected string $module_version = '0.4'; //Represents ZEND_DECLARE_MODULE_GLOBALS macro. protected string $global_type = 'unsigned int[10]'; // Do module startup? protected bool $m_startup = true; protected bool $r_startup = true; // Represents PHP_MINIT_FUNCTION() macro. public function module_startup(int $type, int $module_number): int { echo 'module_startup' . \PHP_EOL; return \ZE::SUCCESS; } // Represents PHP_RINIT_FUNCTION() macro. public function request_startup(...$args): int { echo 'request_startup' . \PHP_EOL; $data = $this->get_globals(); $data[5] = 25; return \ZE::SUCCESS; } // Represents PHP_GINIT_FUNCTION() macro. public function global_startup(\FFI\CData $memory): void { if (\PHP_ZTS) { \tsrmls_activate(); } echo 'global_startup' . \PHP_EOL; \FFI::memset($this->get_globals(), 0, $this->globals_size()); } } $module = new SimpleCountersModule(); if (!$module->is_registered()) { $module->register(); $module->startup(); } // Represents ZEND_MODULE_GLOBALS_ACCESSOR() macro. $data = $module->get_globals(); $module->get_globals('4', 20); $data[0] = 5; $data[9] = 15; var_dump($data); ob_start(); phpinfo(8); $value = ob_get_clean(); preg_match('/simple_counters support => enabled/', $value, $matches); var_dump($matches[0]);
类似于 headers_sent()
错误的修复技巧:PHP 警告:无法修改头信息 - 已由 (输出开始于 xxxxxxxx 发送
require 'vendor/autoload.php'; function headers_sent_reset() { zend_sg('headers_sent', 0); } echo 'any non-buffered output'; var_dump(headers_sent()); // true headers_sent_reset(); var_dump(headers_sent()); // false // This would have otherwise produced warning/errors! header('Location: http://www.example.com/');
从任何 C
ABI 库的 *.h
文件创建适当的 FFI C 库头文件
Linux: cpp -P -D"__attribute__(ARGS)=" path/to/original/header.h -o ffi_header.h
Windows: 首先下载 mcpp mcpp -P -D"__attribute__(ARGS)=" path/to/original/header.h -o ffi_header.h
可能需要 -I <directory>
选项来搜索/查找额外的包含源文件,输出文件仍需编辑,主要是 96% 正确的头文件,FFI
会抱怨,只需编辑/检查指示行之后的 2 行。
参考/致谢
-
开始使用 PHP-FFI YouTube
可能的安全风险
开始
贡献
鼓励并欢迎贡献;我总是很高兴在 Github 上收到反馈或拉取请求 :) 为错误和新功能创建 Github 问题 并对您感兴趣的问题进行评论。
许可
MIT 许可证 (MIT)。请参阅 许可文件 获取更多信息。