В расширении PHP рекомендуется использовать способ возврата значения из и std :: string

Ad N спросил: 28 апреля 2018 в 08:31 в: php

У нас есть простая функция 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, вы попросите движок использовать привязку к запросу с помощью диспетчера памяти Zend. Такое распределение будет ликвидировано в конце текущего запроса. Если вы не делаете ityourself, в сборке отладки, двигатель будет кричать на вас об утечке утечки, которую вы только что создали. Если вы пройдете 1, вы спросите, что вызвало "постоянное" распределение, то есть движок будет использовать atraditional вызов C malloc () и не будет отслеживать выделение памяти любым способом.

Кажется, мы хотим значение 0, но затем RETURN_STR() освободите выделенную память? (текст немного неоднозначен, но кажется, что уничтожение должно быть явным). Есть ли более идиоматический способ вернуть такое значение std::string из функции расширения PHP?

1 ответ

Есть решение
Roger Gee ответил: 17 мая 2018 в 07:50

Чтобы ответить на ваш вопрос, я расскажу немного о распределении памяти PHP, а затем о вашем конкретном вопросе.

О распределении памяти PHP

При написании PHP-расширений вы можете выполнять два вида распределений памяти:

  • выделения отслеживаемой памяти
  • распределения постоянной памяти

Отслеживаемое распределение памяти - это оптимизация, которая позволяет механизму PHP иметь некоторый контроль над распределением необработанной памяти. Диспетчер памяти Zend (ZendMM) действует как обертка над стандартными библиотеками распределения памяти. Этот диспетчер памяти позволяет PHP избегать утечек памяти, очищая любую отслеживаемую память, которая не была явно освобождена в конце запроса. Кроме того, это позволяет двигателю определять пределы памяти (например, php.ini) memory_limit). По этой причине отслеживаемая память также называется памятью per-request .

Постоянное распределение памяти - это стандартное распределение памяти, управляемое библиотекой C (например, malloc и друзей). Стоит также отметить, что в C ++ new и delete обычно ссылаются на malloc и free соответственно. В PHP постоянное распределение памяти выживает при обработке запроса и может существовать для обслуживания более одного запроса. По этой причине можно вызвать утечку памяти с такими видами распределений.

В PHP API есть несколько макросов, которые определены для выполнения отслеживаемых или постоянных распределений памяти. Например, emalloc и efree являются аналогами malloc и free для отслеживания (т.е. для каждого запроса) управления памятью. Макросы pemalloc и pefree предназначены для отслеживаемых или постоянных распределений, имеющих параметр для переключения. Например, pemalloc(32,1) выделяет блок из 32 постоянных байт, тогда как pemalloc(32,0) эквивалентен emalloc(32), который выделяет блок из 32 отслеживаемых байтов.

В дополнение к функциям выделения необработанных памяти API PHP также обеспечивает контроль над распределением памяти, инициированным функциями более высокого уровня. Например, создание структуры PHP7 zend_string с помощью 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 существует исключение, так как структура zend_string может помнить, какой тип распределения использовался. Несмотря на это, рекомендуется всегда использовать отслеживаемые распределения по умолчанию, если у вас нет веских оснований для этого. Поэтому ваш текущий код выглядит хорошо, поскольку он передает 0 в качестве третьего параметра в zend_string_init.

Разрушение zend_string не должно быть явный в вашем коде, так как zval будет обрабатывать это через некоторое время. Кроме того, этот процесс зависит от того, как пользовательское пространство работает с возвращенным zval. Это не то, о чем вам нужно беспокоиться.