Skip to content

Instantly share code, notes, and snippets.

@laruence
Created April 12, 2012 14:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save laruence/2367913 to your computer and use it in GitHub Desktop.
Save laruence/2367913 to your computer and use it in GitHub Desktop.
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
Copy link

Nice mix of tab and space indent.

@alganet
Copy link

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