Как правильно добавить элементы в пустой массив, переданный в функцию расширения в 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);
}

0 ответов

Другие вопросы по тегам