Created
April 12, 2012 14:57
-
-
Save laruence/2367913 to your computer and use it in GitHub Desktop.
Allow use As in closure declaration
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); } | |
; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Nice mix of tab and space indent.