PHP FFI: How to pass PHP class object to C++

40 views Asked by At

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:

  1. pass serialize($this) to the C++ DLL, and call unserialize() at function callbackfunc(), but unserialize() will create a new object, miss property value;
  2. 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.
0

There are 0 answers