我们有一个简单的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_initRETURN_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++中,newdelete通常分别调用mallocfree。在PHP中,持久性内存分配在处理一个请求后仍然存在,并且可能存在以服务多个请求。因此,使用这种分配可能导致内存泄漏。

    在PHP API中,定义了一些宏以执行跟踪的或持久的内存分配。例如,emallocefreemallocfree的类似物,用于跟踪(即每个请求)的内存管理。宏pemallocpefree用于跟踪分配或持久分配,具有可切换的参数。例如,pemalloc(32,1)分配32个持久性字节的块,而pemalloc(32,0)等效于emalloc(32)分配32个跟踪字节的块。

    除了原始内存分配功能外,PHP API还提供了对由更高级别功能启动的内存分配的控制。例如,使用zend_string创建一个PHP7 zend_string_init结构可让您通过第三个参数选择所需的内存分配类型。这遵循整个API的通用习惯用法,0指示跟踪的分配,1指示持久性的分配。

    关于zend_stringzend_string_initRETURN_STR

    我对PHP7的了解不如对PHP5的熟悉,但是许多概念已经延续了下来,我认为我已经阅读了足够的源代码来回答这个问题。当您使用zend_stringzval分配给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/

    10-12 03:06