Create a gist now

Instantly share code, notes, and snippets.

Allow use As in closure declaration
index 6f2ded3..67eeefd 100644
--- a/Zend/zend_closures.c
+++ b/Zend/zend_closures.c
@@ -291,6 +291,66 @@ static zend_object_value zend_closure_clone(zval *zobject TSRMLS_DC) /* {{{ */
}
/* }}} */
+static int zend_closure_copy_lexical_var(zval **p TSRMLS_DC, int num_args, va_list args, zend_hash_key *key) /* {{{ */
+{
+ zval *tmp;
+ zend_bool is_ref;
+ HashTable *target = va_arg(args, HashTable*);
+ zval *this_ptr = va_arg(args, zval *);
+ long h = key->h;
+ char *skey = (char *)key->arKey;
+ uint len = key->nKeyLength;
+
+ if (Z_TYPE_PP(p) & (IS_LEXICAL_VAR|IS_LEXICAL_REF)) {
+
+ is_ref = Z_TYPE_PP(p) & IS_LEXICAL_REF;
+ if ((Z_TYPE_PP(p) & IS_CONSTANT_TYPE_MASK) == IS_STRING) {
+ if (Z_STRLEN_PP(p) == sizeof("this") - 1 && this_ptr && memcmp(Z_STRVAL_PP(p), "this", sizeof("this") - 1) == 0) {
+ if (zend_hash_quick_add(target, key->arKey, key->nKeyLength, key->h, &this_ptr, sizeof(zval*), NULL) == SUCCESS) {
+ Z_ADDREF_P(this_ptr);
+ }
+ return ZEND_HASH_APPLY_KEEP;
+ }
+ skey = Z_STRVAL_PP(p);
+ len = Z_STRLEN_PP(p) + 1;
+ h = zend_inline_hash_func(skey, len);
+ }
+
+ if (!EG(active_symbol_table)) {
+ zend_rebuild_symbol_table(TSRMLS_C);
+ }
+ if (zend_hash_quick_find(EG(active_symbol_table), skey, len, h, (void **) &p) == FAILURE) {
+ if (is_ref) {
+ ALLOC_INIT_ZVAL(tmp);
+ Z_SET_ISREF_P(tmp);
+ zend_hash_quick_add(EG(active_symbol_table), skey, len, h, &tmp, sizeof(zval*), (void**)&p);
+ } else {
+ tmp = EG(uninitialized_zval_ptr);
+ zend_error(E_NOTICE,"Undefined variable: %s", key->arKey);
+ }
+ } else {
+ if (is_ref) {
+ SEPARATE_ZVAL_TO_MAKE_IS_REF(p);
+ tmp = *p;
+ } else if (Z_ISREF_PP(p)) {
+ ALLOC_INIT_ZVAL(tmp);
+ ZVAL_COPY_VALUE(tmp, *p);
+ zval_copy_ctor(tmp);
+ Z_SET_REFCOUNT_P(tmp, 0);
+ Z_UNSET_ISREF_P(tmp);
+ } else {
+ tmp = *p;
+ }
+ }
+ } else {
+ tmp = *p;
+ }
+ if (zend_hash_quick_add(target, key->arKey, key->nKeyLength, key->h, &tmp, sizeof(zval*), NULL) == SUCCESS) {
+ Z_ADDREF_P(tmp);
+ }
+ return ZEND_HASH_APPLY_KEEP;
+}
+/* }}} */
int zend_closure_get_closure(zval *obj, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zval **zobj_ptr TSRMLS_DC) /* {{{ */
{
@@ -463,7 +523,7 @@ ZEND_API void zend_create_closure(zval *res, zend_function *func, zend_class_ent
ALLOC_HASHTABLE(closure->func.op_array.static_variables);
zend_hash_init(closure->func.op_array.static_variables, zend_hash_num_elements(static_variables), NULL, ZVAL_PTR_DTOR
, 0);
- zend_hash_apply_with_arguments(static_variables TSRMLS_CC, (apply_func_args_t)zval_copy_static_var, 1, closure->func.
op_array.static_variables);
+ zend_hash_apply_with_arguments(static_variables TSRMLS_CC, (apply_func_args_t)zend_closure_copy_lexical_var, 2, closu
re->func.op_array.static_variables, this_ptr);
}
closure->func.op_array.run_time_cache = NULL;
(*closure->func.op_array.refcount)++;
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
index c3c35eb..a6f5616 100644
--- a/Zend/zend_compile.c
+++ b/Zend/zend_compile.c
@@ -5964,6 +5964,25 @@ void zend_do_fetch_lexical_variable(znode *varname, zend_bool is_ref TSRMLS_DC)
}
/* }}} */
+void zend_do_fetch_lexical_variable_with_alias(znode *alias, znode *varname, zend_bool is_ref TSRMLS_DC) /* {{{ */
+{
+ znode value;
+ if (Z_STRLEN(alias->u.constant) == sizeof("this") - 1 &&
+ memcmp(Z_STRVAL(alias->u.constant), "this", sizeof("this") - 1) == 0) {
+ zend_error(E_COMPILE_ERROR, "Cannot use $this as lexical variable");
+ return;
+ }
+
+ value.op_type = IS_CONST;
+ ZVAL_STRINGL(&value.u.constant, Z_STRVAL(varname->u.constant), Z_STRLEN(varname->u.constant), 0);
+ Z_TYPE(value.u.constant) |= is_ref ? IS_LEXICAL_REF : IS_LEXICAL_VAR;
+ Z_SET_REFCOUNT_P(&value.u.constant, 1);
+ Z_UNSET_ISREF_P(&value.u.constant);
+
+ zend_do_fetch_static_variable(alias, &value, is_ref ? ZEND_FETCH_STATIC : ZEND_FETCH_LEXICAL TSRMLS_CC);
+}
+/* }}} */
+
void zend_do_fetch_global_variable(znode *varname, const znode *static_assignment, int fetch_type TSRMLS_DC) /* {{{ */
{
zend_op *opline;
diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h
index 8a81a95..9341c05 100644
--- a/Zend/zend_compile.h
+++ b/Zend/zend_compile.h
@@ -437,6 +437,7 @@ void fetch_simple_variable_ex(znode *result, znode *varname, int bp, zend_uchar
void zend_do_indirect_references(znode *result, const znode *num_references, znode *variable TSRMLS_DC);
void zend_do_fetch_static_variable(znode *varname, const znode *static_assignment, int fetch_type TSRMLS_DC);
void zend_do_fetch_global_variable(znode *varname, const znode *static_assignment, int fetch_type TSRMLS_DC);
+void zend_do_fetch_lexical_variable_with_alias(znode *alias, znode *varname, zend_bool is_ref TSRMLS_DC);
void fetch_array_begin(znode *result, znode *varname, znode *first_dim TSRMLS_DC);
void fetch_array_dim(znode *result, const znode *parent, const znode *dim TSRMLS_DC);
diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y
index d0730b7..efa2d8c 100644
--- a/Zend/zend_language_parser.y
+++ b/Zend/zend_language_parser.y
@@ -809,8 +809,9 @@ lexical_vars:
;
lexical_var_list:
- lexical_var_list ',' T_VARIABLE { zend_do_fetch_lexical_variable(&$3, 0 TSRMLS_CC); }
- | lexical_var_list ',' '&' T_VARIABLE { zend_do_fetch_lexical_variable(&$4, 1 TSRMLS_CC); }
+ lexical_var_list ',' lexical_var_list
+ | T_VARIABLE T_AS T_VARIABLE { zend_do_fetch_lexical_variable_with_alias(&$3, &$1, 0 TSRMLS_CC); }
+ | '&' T_VARIABLE T_AS T_VARIABLE { zend_do_fetch_lexical_variable_with_alias(&$4, &$2, 1 TSRMLS_CC); }
| T_VARIABLE { zend_do_fetch_lexical_variable(&$1, 0 TSRMLS_CC); }
| '&' T_VARIABLE { zend_do_fetch_lexical_variable(&$2, 1 TSRMLS_CC); }
;
@ThiefMaster

Nice mix of tab and space indent.

@alganet
alganet commented Feb 22, 2013

Great patch! Hope it gets in.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment