Как правильно добавить элементы в пустой массив, переданный в функцию расширения в PHP 7.3? - PullRequest
0 голосов
/ 24 октября 2018

Я пытаюсь перенести мое старое расширение PHP, работающее для PHP 5.4, на PHP 7.3 (точнее, 7.3.0 RC3).

Я строю расширение с помощью Visual Studio 2017 для Windows 10Pro 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-скрипт, который я использую, чтобы попробовать его:

<code><?php
  $arr = [];
  $retVal = TestUpdateArray($arr);
  echo "<pre>";
  var_export($retVal);
  echo "\n";
  var_export($arr);
  echo "
";

Вывод:

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, как указано выше:

Access violation

Что такоеменя интересует то, что я получаю совершенно другое поведение на 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 function ожидает, что это так (пожалуйста, не стесняйтесь меня поправлять).

Итак, я спрашиваю, как правильно проверить и (в конечном итоге) инициализировать пустой массив, переданный вZEND_FUNCTION для внесения изменений (в массив) в вызывающий скрипт?

Я также пытался использовать функцию init_array на zArr zval, но в этом случае вызывающий скрипт не получает добавленные строки (я думаю, что ссылка на $ arr теряется при вызове init_array).

РЕДАКТИРОВАТЬ после комментария NikiC:

, когда я добавил вопрос, это было объявление функции:

ZEND_FE(TestUpdateArray, NULL)

после комментария NikiC я добавил следующий аргумент:

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);
}
...