PHP FFI技术问题:如何传递PHP类对象给C++ DLL并反向转换
PHP FFI 与 C++ DLL 交互:对象指针传递与回调处理
核心解决方案
直接利用PHP FFI的类型转换能力,实现PHP对象与C++ void*的双向映射,同时避免垃圾回收风险,确保操作原对象的属性。
1. 将PHP对象$this转为void*传递给C++
PHP对象底层对应zend_object结构体,FFI可以直接将对象实例转换为void*,无需序列化或额外映射。
PHP代码片段
// 将$this转换为void*指针 $userData = FFI::cast('void*', $this); // 传递给C++的创建函数 $this->myClassInstance = $this->ffi->MyClass_Create($callback, $userData);
2. 回调函数中将void*转回PHP对象并调用方法
使用FFI的FFI::object()函数,将C++传回的void*(实际是zend_object*)还原为原PHP对象,直接操作其成员属性和方法。
PHP回调代码片段
$callback = function($userData) { // 将void*转回原PHP对象 $obj = FFI::object($userData); // 直接调用对象成员方法或修改属性 $obj->count1 += 1; $obj->count2 += 1; };
完整示例代码
C++ DLL 代码(编译为MyDll.dll)
#include <iostream> using namespace std; // 定义回调函数类型 typedef void (*CallbackFunc)(void*); // C++端存储回调与用户数据的结构体 struct MyClass { CallbackFunc callback; void* userData; }; // 创建实例并保存回调和用户指针 extern "C" __declspec(dllexport) MyClass* MyClass_Create(CallbackFunc callback, void* userData) { MyClass* obj = new MyClass(); obj->callback = callback; obj->userData = userData; return obj; } // 触发回调函数 extern "C" __declspec(dllexport) void MyClass_TriggerCallback(MyClass* obj) { if (obj && obj->callback) { obj->callback(obj->userData); } } // 释放C++实例 extern "C" __declspec(dllexport) void MyClass_Destroy(MyClass* obj) { if (obj) { delete obj; } }
PHP 测试代码
<?php class Test { public $count1 = 1; public $count2 = 0; private $ffi; private $myClassInstance; public function __construct() { // 加载C++ DLL并声明函数结构 $this->ffi = FFI::cdef(" typedef void (*CallbackFunc)(void*); struct MyClass; struct MyClass* MyClass_Create(CallbackFunc callback, void* userData); void MyClass_TriggerCallback(struct MyClass* obj); void MyClass_Destroy(struct MyClass* obj); ", "MyDll.dll"); // 定义回调函数 $callback = function($userData) { $obj = FFI::object($userData); $obj->count1 += 1; $obj->count2 += 1; }; // 传递$this指针给C++ $userData = FFI::cast('void*', $this); $this->myClassInstance = $this->ffi->MyClass_Create($callback, $userData); } // 触发C++端回调 public function trigger() { $this->ffi->MyClass_TriggerCallback($this->myClassInstance); } // 销毁C++实例 public function __destruct() { if ($this->myClassInstance) { $this->ffi->MyClass_Destroy($this->myClassInstance); } } } // 运行测试 $obj = new Test(); $obj->trigger(); echo "count1: {$obj->count1}, count2: {$obj->count2}\n"; // 输出结果:count1: 2, count2: 1 ?>
关键注意事项
- 垃圾回收防护:确保PHP对象在C持有指针期间不会被回收。示例中通过类成员变量持有
$this和C实例,保证对象生命周期与C++实例一致。如果需要长期持有多个对象,推荐使用SplObjectStorage(比普通数组更高效的对象存储容器)来维护引用。 - 类型安全:确保传递的
void*确实指向有效的PHP对象,避免野指针访问导致崩溃。 - 性能优势:此方案无需序列化/反序列化或额外映射表,直接操作底层指针,性能远优于之前尝试的两种方案。
内容的提问来源于stack exchange,提问作者jennie
相关产品推荐
相关产品推荐

