I am using PHP FFI to call a C++ DLL. I do not know how to pass PHP class objects to C++ DLL and convert the ptr sent back from C++ DLL to PHP objects.
I wrote a demo to illustrate my problem.
The C++ code:
typedef int(__stdcall* CALLBACKFUNC) (void* lpObj, int mtdId);
class MyClass {
private:
void* m_PhpObj;
CALLBACKFUNC m_Callback;
public:
MyClass(CALLBACKFUNC callback, void* phpObj) {
m_PhpObj = phpObj;
m_Callback = callback;
}
int doSomething1() {
int ret = (*m_Callback)(m_PhpObj, 1);
return ret;
}
int doSomething2() {
int ret = (*m_Callback)(m_PhpObj, 2);
return ret;
}
};
extern "C" __declspec(dllexport) void* __stdcall MyClass_Create(CALLBACKFUNC callback, void* phpObj) {
MyClass* obj = new MyClass(callback, phpObj);
return obj;
}
extern "C" __declspec(dllexport) int __stdcall MyClass_Do(void* lpObj, int mtdId) {
if (!lpObj) return 0;
MyClass* lpT = (MyClass*)lpObj;
if (mtdId == 1) {
return lpT->doSomething1();
} else {
return lpT->doSomething2();
}
}
The PHP code:
<?php
$ffi = FFI::cdef("
typedef int(__stdcall* CALLBACKFUNC) (void* lpObj, int mthId);
void* MyClass_Create(CALLBACKFUNC lpSink, void* phpObj);
int MyClass_Do(void* lpObj, int mtdId)",
"dllpath");
function callbackfunc($lpObj, $mthId) {
// The second question: how to convert $lpObj to MyClass object and call member function by this object
$obj = VoidPtrToObj($lpObj);
switch ($mthId) {
case 1:
return $obj->doSomething1();
case 2:
return $obj->doSomething2();
default:
return -1;
}
}
class MyClass{
var $cppObj;
var $count1 = 0;
var $count2 = 0;
public function __construct() {
global $ffi;
//The first question: how pass $this to void*
$this->cppObj = $ffi->MyClass_Create("callbackfunc", ObjToVoidPtr($this));
}
public function callCppDo1() {
global $ffi;
$ffi->MyClass_Do($this->cppObj, 1);
}
public function callCppDo2() {
global $ffi;
$ffi->MyClass_Do($this->cppObj, 2);
}
public function doSomething1() {
$this->count1++;
return $this->count1;
}
public function doSomething2() {
$this->count2++;
return $this->count2;
}
}
$obj = new MyClass();
$obj->callCppDo1();
$obj->callCppDo1();
$obj->callCppDo2();
//expect $obj->count1 == 2, $obj->count2 == 1
I tried:
- pass serialize($this) to the C++ DLL, and call unserialize() at function callbackfunc(), but unserialize() will create a new object, miss property value;
- create a global array, store array[spl_object_id($this)] = $this and pass spl_object_id($this) to the C++ DLL, then get object from array by id. However, it maybe inefficient.