我们有一个简单的PHP函数,其目的是调用一个C++自由函数std::string callLibrary(std::string)
并返回其std::string
返回值。
当前看起来像这样:
PHP_FUNCTION(call_library)
{
char *arg = NULL;
size_t arg_len, len;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &arg, &arg_len) == FAILURE)
{
return;
}
// Call underlying library
std::string callResult = callLibrary(arg);
zend_string * result = zend_string_init(callResult.c_str(), callResult.size(), 0);
RETURN_STR(result);
}
我们找不到描述
zend_string_init
或RETURN_STR()
行为的引用手册,这是我们最近的事情:http://www.phpinternalsbook.com/php7/internal_types/strings/zend_strings.html
特别是,它声明了
zend_string_init
的最后一个参数似乎我们需要
0
值,但是RETURN_STR()
是否可以释放分配的内存? (文本有点模棱两可,但似乎破坏应该是明确的)是否有更惯用的方法从PHP扩展函数返回此类
std::string
值? 最佳答案
为了回答您的问题,我将简单介绍一下PHP内存分配,然后再讨论您的特定问题。
关于PHP内存分配
编写PHP扩展时,可以执行两种内存分配:
跟踪的内存分配是一种优化,它允许PHP引擎对原始内存分配进行更多控制。 Zend内存管理器(ZendMM)充当标准内存分配库之上的包装器。该内存管理器允许PHP通过清除所有在请求结束时未明确释放的跟踪内存来避免内存泄漏。此外,这允许引擎制定内存限制(例如
php.ini
设置 memory_limit
)。由于这些原因,跟踪的内存也称为每个请求的内存。持久性内存分配是由C库管理的标准内存分配(例如
malloc
和friends)。还值得注意的是,在C++中,new
和delete
通常分别调用malloc
和free
。在PHP中,持久性内存分配在处理一个请求后仍然存在,并且可能存在以服务多个请求。因此,使用这种分配可能导致内存泄漏。在PHP API中,定义了一些宏以执行跟踪的或持久的内存分配。例如,
emalloc
和efree
是malloc
和free
的类似物,用于跟踪(即每个请求)的内存管理。宏pemalloc
和pefree
用于跟踪分配或持久分配,具有可切换的参数。例如,pemalloc(32,1)
分配32个持久性字节的块,而pemalloc(32,0)
等效于emalloc(32)
分配32个跟踪字节的块。除了原始内存分配功能外,PHP API还提供了对由更高级别功能启动的内存分配的控制。例如,使用
zend_string
创建一个PHP7 zend_string_init
结构可让您通过第三个参数选择所需的内存分配类型。这遵循整个API的通用习惯用法,0
指示跟踪的分配,1
指示持久性的分配。关于
zend_string
,zend_string_init
和RETURN_STR
我对PHP7的了解不如对PHP5的熟悉,但是许多概念已经延续了下来,我认为我已经阅读了足够的源代码来回答这个问题。当您使用
zend_string
将zval
分配给RETURN_STR
时,zval
负责释放zend_string
(在PHP5中,这只是char*
,但概念相同)。 Zend引擎期望使用跟踪的内存管理器分配大多数(如果不是全部)对象。在PHP5中,必须通过zval
分配分配给emalloc
的字符串,因为当efree
被销毁时,该代码总是在字符串缓冲区上调用zval
。在PHP7中似乎有an exception,因为zend_string
结构可以记住使用了哪种分配类型。无论如何,除非有充分的理由,否则始终将跟踪的分配用作默认值是一个好习惯。因此,您当前的代码看起来不错,因为它将0
作为第三个参数传递给zend_string_init
。zend_string
的销毁不应在您的代码中明确显示,因为zval
将在以后的某个时间进行处理。另外,该过程取决于用户空间如何对返回的zval
进行操作。这不是您不必担心的事情。关于php - 在PHP扩展中,推荐的方法从and std::string返回值,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/50465101/