Merge branch 'PHP-7.4'

This commit is contained in:
Nikita Popov 2019-08-23 17:23:31 +02:00
commit 4e4cc9b480
4 changed files with 66 additions and 1 deletions

View File

@ -0,0 +1,56 @@
--TEST--
Closure $this unbinding deprecation
--FILE--
<?php
class Test {
public function method() {
echo "instance scoped, non-static, \$this used\n";
$fn = function() {
var_dump($this);
};
$fn->bindTo(null);
echo "instance scoped, static, \$this used\n";
$fn = static function() {
var_dump($this);
};
$fn->bindTo(null);
echo "instance scoped, non-static, \$this not used\n";
$fn = function() {
var_dump($notThis);
};
$fn->bindTo(null);
}
public static function staticMethod() {
echo "static scoped, non-static, \$this used\n";
$fn = function() {
var_dump($this);
};
$fn->bindTo(null);
echo "static scoped, static, \$this used\n";
$fn = static function() {
var_dump($this);
};
$fn->bindTo(null);
echo "static scoped, static, \$this not used\n";
$fn = function() {
var_dump($notThis);
};
$fn->bindTo(null);
}
}
(new Test)->method();
Test::staticMethod();
?>
--EXPECTF--
instance scoped, non-static, $this used
Deprecated: Unbinding $this of closure is deprecated in %s on line %d
instance scoped, static, $this used
instance scoped, non-static, $this not used
static scoped, non-static, $this used
static scoped, static, $this used
static scoped, static, $this not used

View File

@ -86,7 +86,8 @@ static zend_bool zend_valid_closure_binding(
&& !(func->common.fn_flags & ZEND_ACC_STATIC)) {
zend_error(E_WARNING, "Cannot unbind $this of method");
return 0;
} else if (!is_fake_closure && !Z_ISUNDEF(closure->this_ptr)) {
} else if (!is_fake_closure && !Z_ISUNDEF(closure->this_ptr)
&& (func->common.fn_flags & ZEND_ACC_USES_THIS)) {
// TODO: Only deprecate if it had $this *originally*?
zend_error(E_DEPRECATED, "Unbinding $this of closure is deprecated");
}

View File

@ -2357,6 +2357,7 @@ static zend_op *zend_compile_simple_var(znode *result, zend_ast *ast, uint32_t t
opline->result_type = IS_TMP_VAR;
result->op_type = IS_TMP_VAR;
}
CG(active_op_array)->fn_flags |= ZEND_ACC_USES_THIS;
return opline;
} else if (zend_try_compile_cv(result, ast) == FAILURE) {
return zend_compile_simple_var_no_cv(result, ast, type, delayed);
@ -2451,6 +2452,7 @@ static zend_op *zend_delayed_compile_prop(znode *result, zend_ast *ast, uint32_t
if (is_this_fetch(obj_ast)) {
obj_node.op_type = IS_UNUSED;
CG(active_op_array)->fn_flags |= ZEND_ACC_USES_THIS;
} else {
opline = zend_delayed_compile_var(&obj_node, obj_ast, type, 0);
if (opline && type == BP_VAR_W && (opline->opcode == ZEND_FETCH_STATIC_PROP_W || opline->opcode == ZEND_FETCH_OBJ_W)) {
@ -2987,6 +2989,7 @@ uint32_t zend_compile_args(zend_ast *ast, zend_function *fbc) /* {{{ */
if (is_this_fetch(arg)) {
zend_emit_op(&arg_node, ZEND_FETCH_THIS, NULL, NULL);
opcode = ZEND_SEND_VAR_EX;
CG(active_op_array)->fn_flags |= ZEND_ACC_USES_THIS;
break;
} else if (zend_try_compile_cv(&arg_node, arg) == SUCCESS) {
opcode = ZEND_SEND_VAR_EX;
@ -3846,6 +3849,7 @@ void zend_compile_method_call(znode *result, zend_ast *ast, uint32_t type) /* {{
if (is_this_fetch(obj_ast)) {
obj_node.op_type = IS_UNUSED;
CG(active_op_array)->fn_flags |= ZEND_ACC_USES_THIS;
} else {
zend_compile_expr(&obj_node, obj_ast);
}
@ -7654,6 +7658,7 @@ void zend_compile_isset_or_empty(znode *result, zend_ast *ast) /* {{{ */
case ZEND_AST_VAR:
if (is_this_fetch(var_ast)) {
opline = zend_emit_op(result, ZEND_ISSET_ISEMPTY_THIS, NULL, NULL);
CG(active_op_array)->fn_flags |= ZEND_ACC_USES_THIS;
} else if (zend_try_compile_cv(&var_node, var_ast) == SUCCESS) {
opline = zend_emit_op(result, ZEND_ISSET_ISEMPTY_CV, &var_node, NULL);
} else {

View File

@ -333,6 +333,9 @@ typedef struct _zend_oparray_context {
/* function is a destructor | | | */
#define ZEND_ACC_DTOR (1 << 29) /* | X | | */
/* | | | */
/* closure uses $this | | | */
#define ZEND_ACC_USES_THIS (1 << 30) /* | X | | */
/* | | | */
/* op_array uses strict mode types | | | */
#define ZEND_ACC_STRICT_TYPES (1U << 31) /* | X | | */