Skip to content

Commit

Permalink
Add auto-increment keys
Browse files Browse the repository at this point in the history
When no key is explicitely yielded PHP will used auto-incrementing keys
as a fallback. They behave the same as with arrays, i.e. the key is the
successor of the largest previously used integer key.
  • Loading branch information
nikic committed May 30, 2012
1 parent bc08c2c commit 8790160
Show file tree
Hide file tree
Showing 5 changed files with 313 additions and 78 deletions.
22 changes: 22 additions & 0 deletions Zend/tests/generators/auto_incrementing_keys.phpt
@@ -0,0 +1,22 @@
--TEST--
Generator keys are auto-incrementing by default
--FILE--
<?php

function *gen() {
yield 'foo';
yield 'bar';
yield 5 => 'rab';
yield 'oof';
}

foreach (gen() as $k => $v) {
echo $k, ' => ', $v, "\n";
}

?>
--EXPECT--
0 => foo
1 => bar
5 => rab
6 => oof
3 changes: 3 additions & 0 deletions Zend/zend_generators.c
Expand Up @@ -116,6 +116,9 @@ static zend_object_value zend_generator_create(zend_class_entry *class_type TSRM
generator = emalloc(sizeof(zend_generator));
memset(generator, 0, sizeof(zend_generator));

/* The key will be incremented on first use, so it'll start at 0 */
generator->largest_used_integer_key = -1;

zend_object_std_init(&generator->std, class_type TSRMLS_CC);

object.handle = zend_objects_store_put(generator, NULL,
Expand Down
2 changes: 2 additions & 0 deletions Zend/zend_generators.h
Expand Up @@ -34,6 +34,8 @@ typedef struct _zend_generator {
zval *key;
/* Variable to put sent value into */
temp_variable *send_target;
/* Largest used integer key for auto-incrementing keys */
long largest_used_integer_key;
} zend_generator;

extern ZEND_API zend_class_entry *zend_ce_generator;
Expand Down
14 changes: 11 additions & 3 deletions Zend/zend_vm_def.h
Expand Up @@ -5332,11 +5332,19 @@ ZEND_VM_HANDLER(160, ZEND_YIELD, CONST|TMP|VAR|CV|UNUSED, CONST|TMP|VAR|CV|UNUSE
generator->key = key;
}

if (Z_TYPE_P(generator->key) == IS_LONG
&& Z_LVAL_P(generator->key) > generator->largest_used_integer_key
) {
generator->largest_used_integer_key = Z_LVAL_P(generator->key);
}

FREE_OP2_IF_VAR();
} else {
/* Setting the key to NULL signals that the auto-increment key
* generation should be used */
generator->key = NULL;
/* If no key was specified we use auto-increment keys */
generator->largest_used_integer_key++;

ALLOC_INIT_ZVAL(generator->key);
ZVAL_LONG(generator->key, generator->largest_used_integer_key);
}

/* If a value is sent it should go into the result var */
Expand Down

0 comments on commit 8790160

Please sign in to comment.