Skip to content

@laruence /fr61682.patch
Created

Embed URL

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
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

Great patch! Hope it gets in.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.