Как правильно добавить элементы в пустой массив, переданный в функцию расширения в PHP 7.3?
Я пытаюсь перенести мое старое расширение PHP, работающее на PHP 5.4, на PHP 7.3 (точнее, 7.3.0 RC3).
Я строю расширение, используя Visual Studio 2017 для Windows 10 Pro x64, для архитектур x64 и x86.
Расширение предоставляет простую функцию (среди прочих), которая принимает массив в качестве аргумента, возвращает логическое значение и помещает в массив несколько строк. Входной массив обычно пуст.
Вот код c, на котором я сосредоточился, который нацелен на PHP 5.x и PHP 7.x:
ZEND_FUNCTION(TestUpdateArray)
{
zval *zArr;
zend_bool retVal = FALSE;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zArr) != FAILURE)
{
if (Z_TYPE_P(zArr) == IS_ARRAY)
{
char str[256];
for (int i = 1; i < 11; i++)
{
sprintf_s(str, "This is a test %d", i);
#if PHP_VERSION_ID > 70000
add_next_index_string(zArr, str);
#else
add_next_index_string(zArr, str, true);
#endif
}
retVal = TRUE;
}
}
RETURN_BOOL(retVal);
}
И это простой скрипт php, который я использую, чтобы попробовать его:
<?php
$arr = [];
$retVal = TestUpdateArray($arr);
echo "<pre>";
var_export($retVal);
echo "\n";
var_export($arr);
echo "</pre>";
Выведение:
true
array (
0 => 'This is a test 1',
1 => 'This is a test 2',
2 => 'This is a test 3',
3 => 'This is a test 4',
4 => 'This is a test 5',
5 => 'This is a test 6',
6 => 'This is a test 7',
7 => 'This is a test 8',
8 => 'This is a test 9',
9 => 'This is a test 10',
)
В то время как функции прекрасно работают в PHP 5.4, когда
$arr = [];
httpd / php выдает исключение, а затем просто падает на PHP 7.3 с объявленным $arr, как указано выше:
Что меня интересует, так это то, что я получаю совершенно другое поведение на 7.3, если $arr объявлен так:
$arr = ['test'];
В этом случае как на 5.4, так и на 7.3 функция правильно добавляет 10 "Это тестовые x" строки в массив, конечный результат:
true
array (
0 => 'test',
1 => 'This is a test 1',
2 => 'This is a test 2',
3 => 'This is a test 3',
4 => 'This is a test 4',
5 => 'This is a test 5',
6 => 'This is a test 6',
7 => 'This is a test 7',
8 => 'This is a test 8',
9 => 'This is a test 9',
10 => 'This is a test 10',
)
В свете того, что я видел, я предполагаю, что с учетом различий и оптимизации, представленных в PHP 7, виртуальная машина PHP фактически не выделяет пространство для элементов массива (когда он объявлен пустым), но затем добавляет add_next_index_string. функция ожидает, что это будет иметь место (пожалуйста, не стесняйтесь поправить меня в этом).
Итак, я спрашиваю: как правильно проверить и (в конечном итоге) инициализировать пустой массив, переданный в ZEND_FUNCTION, чтобы сделать изменения (в массиве) доступными для вызывающего скрипта?
Я также пытался использовать функцию init_array на zArr zval, но в этом случае вызывающий скрипт не получает добавленные строки (я думаю, что ссылка на $arr теряется при вызове init_array).
РЕДАКТИРОВАТЬ после комментария NikiC:
когда я добавил вопрос, это было объявление функции:
ZEND_FE(TestUpdateArray, NULL)
после комментария NikiC я добавил следующее arginfo:
ZEND_BEGIN_ARG_INFO_EX(arginfo_test_update_array, 0, 0, 1)
ZEND_ARG_ARRAY_INFO(1, update_array, 0)
ZEND_END_ARG_INFO()
и обновил код функции:
ZEND_FUNCTION(TestUpdateArray)
{
zval *zArr;
zend_bool retVal = FALSE;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zArr) != FAILURE)
{
if (Z_ISREF_P(zArr))
{
ZVAL_DEREF(zArr);
SEPARATE_ARRAY(zArr);
}
if (Z_TYPE_P(zArr) == IS_ARRAY)
{
char str[256];
for (int i = 1; i < 11; i++)
{
sprintf_s(str, "This is a test %d", i);
#if PHP_VERSION_ID > 70000
add_next_index_string(zArr, str);
#else
add_next_index_string(&myArr, str, true);
#endif
}
retVal = TRUE;
}
}
RETURN_BOOL(retVal);
}