Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP extension iterate through array

I'm starting to write a PHP extension and wish to just get my head around how to loop through an array that is passed (with the intention of changing the data value by value). Preferred method would be a for loop so that I can match array1 with array2 data e.g. array1[0] is linked to array2[0], [1] with [1] etc...

Anyone able to help?

modarray.c

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"

extern zend_module_entry modarray_module_entry;
#define phpext_modarray_ptr &modarray_module_entry

PHP_FUNCTION(modarray);

static function_entry modarray_functions[] = {
    PHP_FE(modarray, NULL)
    PHP_FE_END
};

zend_module_entry modarray_module_entry = {
  STANDARD_MODULE_HEADER,
  "modarray",
  modarray_functions,
  NULL,
  NULL,
  NULL,
  NULL,
  NULL,
  "0.1",
  STANDARD_MODULE_PROPERTIES
};

ZEND_GET_MODULE(modarray)

PHP_FUNCTION(modarray)
{
  zval *val, *val2;

  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|z", &val, &val2) == FAILURE){
    return;
  }

  SEPARATE_ZVAL(&val);
  SEPARATE_ZVAL(&val2);

  array_init(return_value);

  zval_add_ref(&val);
  zval_add_ref(&val2);
  add_next_index_zval(return_value, val);
  add_next_index_zval(return_value, val2);
}

PHP Code

<?php
$array1 = array(1,2,3,4);
$array2 = array(5,6,7,8);
echo '<pre>';
print_r(modarray($array1,$array2));
echo '</pre>';
?>

PHP Output

Array
(
    [0] => Array
        (
            [0] => 1
            [1] => 2
            [2] => 3
            [3] => 4
        )

    [1] => Array
        (
            [0] => 5
            [1] => 6
            [2] => 7
            [3] => 8
        )

)
like image 520
TSUK Avatar asked Jul 03 '14 14:07

TSUK


1 Answers

There are two ways to do that, one fully "manual" by using the iteration API:

HashPosition pos;
zval *collection, **arg;
uint hash_key_type;
uint string_key_len;
ulong int_key;
char *string_key = NULL;

... get the collection from somewhere, e.g. argument parsing ...

while (!EG(exception) && zend_hash_get_current_data_ex(Z_ARRVAL_P(collection), (void **)&arg, &pos) == SUCCESS) {
    zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(collection), &pos);
    MAKE_STD_ZVAL(key);
    hash_key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(collection), &string_key, &string_key_len, &int_key, 0, &pos);

    // Invoke e.g. zend_hash_update

    zend_hash_move_forward_ex(Z_ARRVAL_P(collection), &pos);
}

The preferred alternative is to use on of three zend_hash_apply*() functions with a callback which is considered more elegant:

static int replace_value(zval **arg, zval ****params TSRMLS_DC)
{
    add_next_index_zval(params, val);

    return ZEND_HASH_APPLY_REMOVE;
}

zval *in, ***out;
... fill in from somewhere from somewhere, e.g. argument parsing ...
array_init(**out);
zend_hash_apply_with_argument(Z_ARRVAL_P(collection, (apply_func_arg_t) replace_value, params TSRMLS_CC);

Note: I didn’t test either of the snippets locally but copied it from different places.

like image 121
Lars Strojny Avatar answered Sep 18 '22 03:09

Lars Strojny