我正在用类定义编写简单的扩展
extension.h
zend_class_entry * ExampleClass_class;
zend_class_entry * get_ExampleClass_class();
extension.c
#include "php.h"
#include "extension.h"
...
zend_class_entry * get_ExampleClass_class(){
return ExampleClass_class;
}
....
PHP_METHOD(ExampleClass, getInstance){
ZEND_PARSE_PARAMETERS_START(0, 0)
Z_PARAM_OPTIONAL
ZEND_PARSE_PARAMETERS_END();
RETURN_OBJ(
// ----------- fun objectToZval(obj: PhpObject) = obj.zval //CPointer<zval>
example_symbols()->kotlin.root.php.extension.proxy.objectToZval(
example_symbols()->kotlin.root.exampleclass.getInstance(
// ------- Unused parameter
example_symbols()
->kotlin.root.php.extension.proxy.phpObj(
ExampleClass_class, getThis()
)
// ------- Unused parameter end
)
)
)
}
我还用逻辑实现(Kotlin本机)编写和编译静态库
.def
static inline zval* zend_helper_new_ExampleClass() {
zval *obj = malloc(sizeof(zval));
object_init_ex(obj, get_ExampleClass_class());
return obj;
}
.kt
fun newExampleClass() = zend_helper_new_ExampleClass()!!
//PhpObject is wrapper for two fields CPointer<zend_class_entry> and CPointer<zval>
class PhpObject(val context: CPointer<zend_class_entry>, val zval: PhpMixed) {
companion object {
fun fromMixed(zval: PhpMixed) = PhpObject(zval.pointed!!.value.obj!!.pointed!!.ce!!, zval)
}
....
}
val PhpMixed.phpObject get() = PhpObject.fromMixed(this)
fun getInstance(obj: PhpObject) = newExampleClass().phpObject
最后我运行PHP代码
var_dump(ExampleClass::getInstance());
并收到这个
# /opt/rh/rh-php71/root/usr/bin/php -dextension=`ls ./phpmodule/modules/*.so` -r "var_dump(ExampleClass::getInstance());"
*RECURSION*
#
我在哪里弄错了?
UPD
static inline zval* zend_helper_new_{className}() {
zval *obj = malloc(sizeof(zval));
object_init_ex(obj, get_{className}_class());
php_printf("Just created FLAGS %u\n", GC_FLAGS(obj->value.obj));
return obj;
}
刚刚创建的对象的GC_FLAGS
等于0
*RECURSIVE*
根据代码在功能php_var_dump
中的作用
case IS_OBJECT:
if (Z_IS_RECURSIVE_P(struc)) {
PUTS("*RECURSION*\n");
return;
}
宏->宏->宏->天哪!->宏->宏...
Z_IS_RECURSIVE_P(struc) = (GC_FLAGS((*(zval)).value.counted) & GC_PROTECTED)
好吧...
php_printf("%d\n", GC_FLAGS((*(obj)).value.counted));
返回0
一定不要触发*RECURSIVE*
,但是...为什么!?
答案 0 :(得分:0)
第一
对于编译,我使用了PHP 7.1.8,但基于最新资源进行了编码。
递归保护已更改2017年10月6日
7.1.8的实际var_dump
代码
case IS_OBJECT:
if (Z_OBJ_APPLY_COUNT_P(struc) > 0) {
PUTS("*RECURSION*\n");
return;
}
但这没关系
第二
RETURN_OBJ(
example_symbols()->kotlin.root.php.extension.proxy.objectToZval(
example_symbols()->kotlin.root.exampleclass.getInstance(/*unused*/)
)
)
让我们展开宏RETURN_OBJ (r)
RETURN_OBJ(r)
{ RETVAL_OBJ(r); return; }
{ ZVAL_OBJ(return_value, r); return; }
。
{ do {
zval *__z = (return_value);
Z_OBJ_P(__z) = (r);
Z_TYPE_INFO_P(__z) = IS_OBJECT_EX;
} while (0); return; }
。
{ do {
zval *__z = (return_value);
Z_OBJ(*(__z)) = (r);
Z_TYPE_INFO(*(__z)) = (IS_OBJECT | (IS_TYPE_REFCOUNTED << Z_TYPE_FLAGS_SHIFT));
} while (0); return; }
。
{ do {
zval *__z = (return_value);
(*(__z)).value.obj = (r);
(*(__z)).u1.type_info = (8 | ((1<<0) << 8));
} while (0); return; }
你看到了吗? :)
是的,此宏必须接收zend_object
而不是zval
只需将返回表达式更改为
example_symbols()->kotlin.root.php.extension.proxy.zendObject(
example_symbols()->kotlin.root.exampleclass.getInstance(/*unused*/)
)
其中
fun zendObject(obj: PhpObject) = obj.zval.pointed!!.value.obj!!
宾果!
PS特别感谢php开发人员社区提供了令人难以置信的文档化宏地狱