如何检查PHP用户区中是否使用return_value(来自php函数,位于本机扩展内)?

时间:2018-08-08 08:55:22

标签: php php-extension

因此,我正在编写一个扩展程序,以充当某些多线程网络库的包装。现在,使用的模式是一个简单的请求-答复。

我要做的就是为响应分配一个zend_string(带有zend_string_init),然后通过return_value返回它。事实是,由于PHP如何对待zval,我不想显式调用zend_string_release。

我的意思是:如果某个zval到达了php userland,它将在不再使用后被销毁并释放。如果无法到达目的地(例如,用户将在php中使用“ myfunc();”之类的东西,而不是“ $ result = myfunc();”),则必须销毁它。

我发现这是一个非常棘手的案例。我想知道execute_data参数中是否没有某些函数,宏或字段,可以告诉我函数的结果是否在php中使用。如果不使用它,则意味着我不需要为答复分配内存。如果是这样,我将分配内存并返回它,它将自动释放。

编辑:如果这样一种机制不存在,不可靠或不是最佳实践(如另一位用户指出的那样),应该如何管理内存?

例如类似

PHP_FUNCTION(myfunc)
{
  zend_string *dummy = zend_string_init("dummy", sizeof("dummy") - 1, 0);
  RETVAL_STR(dummy);
  return;
}

如果用户未在php中执行类似$ var = myfunc()之类的操作,则会导致内存泄漏,并且如果用户确实执行了操作,也会导致双重释放 $ var = myfunc(),然后在RSHUTDOWN()函数中执行zend_string_release(dummy)之类的操作(假设我有一个指向它的指针以某种方式保存在全局哈希表中)

1 个答案:

答案 0 :(得分:0)

通常,您不必担心处理函数返回值的生命周期。 PHP引擎会像处理userland中的任何其他值一样处理此值。换句话说,您对用户区返回值“正在使用”(或“未使用”)的概念不太正确。实际上,无论用户域代码是否将返回值分配给变量,引擎都会每个返回值使用。这意味着将应用PHP的自动内存管理,一切都将得到处理,并最终正确释放。

在引擎盖下,每个PHP_FUNCTION都传递了一个具有参数名称zval的{​​{1}}(当然,return_value宏隐藏了这一事实)。此PHP_FUNCTION始终在调用函数之前初始化为zval(例如NULL)。宏ZVAL_NULL(return_value)评估到调用RETVAL_STR(str)中,该调用将ZVAL_STR(return_value,str)分配给现有的zend_string* return_value。请记住,zval是一个引用计数结构,通过zend_string分配zval 继承初始引用集。然后,引擎将处理分配的zend_string_init的引用计数,并且一旦zend_string*的引用计数器达到零(即不再被任何{{1所使用),它将最终调用zend_string_release }} s。在通过变量分配,函数调用参数分配ETC将值潜在地分配给另一个zend_string之后,引擎会处理销毁zval return_value的问题。

注意:如果阅读此书的人对PHP5的了解比对PHP7的了解(像我本人一样),请注意这是相同的概念,只是zvalzval,在PHP5中是{{1 }}本身是引用计数的,而不是zend_string*

例如,考虑一下:

char*

在这种情况下,返回值由引擎处理,就像我们期望使用PHP的引用计数系统一样。 zval的引用计数在zend_string达到峰值,并在被销毁之前递减一次。换句话说,<?php myfunc(); 在清除之前完全生活在zend_string* 1内。现在考虑另一种情况:

zend_string

在这种情况下,尽管使用了更长的时间(即更多的refcount增量/减量),但仍使用引用计数系统以完全相同的方式对返回值进行处理。将返回值分配给return_value时,refcount至少会命中zval。当引擎销毁<?php $val = myfunc(); echo "Got message: $val\n"; 2时,由于$val仍在return_value中,因此引用计数将减少到zval

我希望这可以解决问题。请注意,我不久前也回答了very similar question。这对您也可能有用。