【发布时间】:2019-02-14 18:58:42
【问题描述】:
我正在编写带有类定义的简单扩展
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 Native)
.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*,但是……为什么!?
【问题讨论】:
-
您编译的 PHP 版本是什么?如果是master,那么看看对象的GC_FLAGS()(
GC_PROTECTED标志) -
是的,所以在该对象上设置了
IS_APPLY_COUNT标志,因此它立即以*RECURSION*失败。错误在别处;您发布的代码很好。您需要调试它,为什么 GC_FLAGS() 的 3 个最低有效位都是三个集合。 -
@bwoebi 抱歉,忘记从函数中删除
zval_dtor(绝望实验)。该标志的实际值为 0(零) -
那么,你的班级有_DebugInfo吗?否则我没有太多建议要寻找什么,除了从 php_var_dump() 向后调试它打印
*RECURSION*
标签: php php-internals