Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/241.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何从PHP扩展返回数组,而不在内存中复制它?_Php_C_Php Extension_Php Internals - Fatal编程技术网

如何从PHP扩展返回数组,而不在内存中复制它?

如何从PHP扩展返回数组,而不在内存中复制它?,php,c,php-extension,php-internals,Php,C,Php Extension,Php Internals,我正在开发一个PHP扩展,其中一个对象方法需要返回一个数组zval 该方法如下所示: ZEND_METHOD(myObject, myMethod) { zval **myArrayProperty; if (zend_hash_find(Z_OBJPROP_P(getThis()), "myArrayProperty", sizeof("myArrayProperty"), (void **) &myArrayProperty) == FAILURE) {

我正在开发一个PHP扩展,其中一个对象方法需要返回一个数组
zval

该方法如下所示:

ZEND_METHOD(myObject, myMethod)
{
    zval **myArrayProperty;
    if (zend_hash_find(Z_OBJPROP_P(getThis()), "myArrayProperty", sizeof("myArrayProperty"), (void **) &myArrayProperty) == FAILURE) {
        RETURN_FALSE;
    }
    RETURN_ZVAL(*myArrayProperty, 1, 0);
}
代码工作正常,并执行预期的操作-它返回对象的
myArrayProperty
。然而,我想优化这个过程

myArrayProperty
存储一个数组,该数组可能相当大。而
RETURN_ZVAL()
宏复制该数组以返回值。复制过程需要很长的时间来获取内存和复制所有数组值。同时,返回的数组通常用于只读操作。因此,一个很好的优化方法是使用PHP的引用计数机制,并且不复制
myArrayProperty
内容。相反,我会增加
myArrayProperty
refcount
,并返回指向它的指针。这与在PHP扩展中处理变量时通常使用的策略相同

然而,似乎没有办法做到这一点——您必须复制值才能从PHP扩展函数返回它。将函数签名更改为通过引用返回值不是一个选项,因为它链接属性和返回值-即稍后更改返回值,也会更改属性。这是不可接受的行为

无法进行引用计数看起来很奇怪,因为PHP中的代码相同:

function myMethod() {
{
    return $this->myArrayProperty;
}
通过参考计数机制进行优化。这就是为什么我在StackOverflow问这个问题,以防我遗漏了什么


那么,有没有一种方法可以从PHP扩展中的函数返回数组,而不必在内存中复制数组?

已经有一段时间了,因为我编写了这样的代码

所以,我在下面的代码中所做的是:1)。显式增加引用计数器2)。返回zval而不复制它

ZEND_METHOD(myObject, myMethod)
{
    zval **myArrayProperty;

    if (zend_hash_find(Z_OBJPROP_P(getThis()), "myArrayProperty", sizeof("myArrayProperty"), (void **) &myArrayProperty) == FAILURE) {
        RETURN_FALSE;
    }

    Z_ADDREF_PP(myArrayProperty);
    RETURN_ZVAL(*myArrayProperty, 0, 0);
}

如果您的函数按值返回,则只有在PHP 5.6(当前主程序)中使用
RETURN\u ZVAL\u FAST
宏时才可能:

RETURN_ZVAL_FAST(*myArrayProperty);

如果函数通过引用返回(
return\u reference=1
,在arginfo中),则可以使用以下代码返回:

zval_ptr_dtor(&return_value);
SEPARATE_ZVAL_TO_MAKE_IS_REF(myArrayProperty);
Z_ADDREF_PP(myArrayProperty);
*return_value_ptr = *myArrayProperty;

如果您的函数按值返回,并且您使用的是PHP 5.5或更高版本,则仍然可以优化
refcount=1
案例:

if (Z_REFCOUNT_PP(myArrayProperty) == 1) {
    RETVAL_ZVAL(*myArrayProperty, 0, 1);
    Z_ADDREF_P(return_value);
    *myArrayProperty = return_value;
} else {
    RETVAL_ZVAL(*myArrayProperty, 1, 0);
}

我没有访问PHP<5.6的权限,但我认为问题在于该值仅被复制。为了绝对确定,您应该在代码中搜索有问题的定义

这意味着您可以尝试:

 zval *arr;
 MAKE_STD_ZVAL(arr);
 array_init(arr);
 // Do things to the array.
 RETVAL_ZVAL(arr, 0, 0);
 efree(arr);
如果使用不当,这是危险的。如果与您自己的临时容器一起使用,我不知道有任何问题

您也可以直接处理返回值,这可能是一种更好的方法。您可能会初始化它,并在开始时将其作为指针传递


你可以这样包装你的返回结果。您也可以尝试引用。

但这不会导致内存泄漏或segfault(以先发生的为准)?当清除对属性的所有引用时,将发生内存泄漏,但无法释放由其zval容器占用的内存,因为refcount仍将保持为1。当返回值被释放时,会发生Segfault,因此其zval容器与数组(共享哈希表,从该容器和属性zval容器中引用)一起被清除,因此以后使用属性将导致不可预测但肯定是错误的效果。属性引用zval-这是refcount=1。当zval被返回时,此代码会增加refcount,并将被对象和调用方引用。如果对象不需要属性,它将减少refcount,因此它将仅由调用方拥有。所以,这个代码在我看来是正常的。但是,再次强调,所有这些都是严格理论上的——我现在甚至没有打开PHP的源代码——不幸的是,正如预测的那样,代码不起作用——在实践中得到了证实:。问题如上所述:对象和调用方引用不同的内存位置。正如描述中所述,函数不通过引用返回值。不幸的是,这不是一个解决方案。对不起,我错过了。在这种情况下,您想要的是不可能的。尽管我看不出为什么即使没有ACC_return_引用,我们也无法传递return_value_ptr的直接原因(除了这允许您从非ref函数返回is_ref=1 zval)。您可能想向internal@询问这一点。它不起作用,因为只有在为函数/方法声明了return by reference时,return\u value\u ptr才由引擎初始化。@AndreyTserkus我知道:)只是说这是我们可能想要更改的东西。我不清楚为什么我们不能总是设置return\u value\u ptr。