Skip to content

Commit 4e4cc9b

Browse files
committed
Merge branch 'PHP-7.4'
2 parents 51ea7fc + d1157cb commit 4e4cc9b

File tree

4 files changed

+66
-1
lines changed

4 files changed

+66
-1
lines changed

Zend/tests/closure_062.phpt

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
--TEST--
2+
Closure $this unbinding deprecation
3+
--FILE--
4+
<?php
5+
6+
class Test {
7+
public function method() {
8+
echo "instance scoped, non-static, \$this used\n";
9+
$fn = function() {
10+
var_dump($this);
11+
};
12+
$fn->bindTo(null);
13+
echo "instance scoped, static, \$this used\n";
14+
$fn = static function() {
15+
var_dump($this);
16+
};
17+
$fn->bindTo(null);
18+
echo "instance scoped, non-static, \$this not used\n";
19+
$fn = function() {
20+
var_dump($notThis);
21+
};
22+
$fn->bindTo(null);
23+
}
24+
25+
public static function staticMethod() {
26+
echo "static scoped, non-static, \$this used\n";
27+
$fn = function() {
28+
var_dump($this);
29+
};
30+
$fn->bindTo(null);
31+
echo "static scoped, static, \$this used\n";
32+
$fn = static function() {
33+
var_dump($this);
34+
};
35+
$fn->bindTo(null);
36+
echo "static scoped, static, \$this not used\n";
37+
$fn = function() {
38+
var_dump($notThis);
39+
};
40+
$fn->bindTo(null);
41+
}
42+
}
43+
44+
(new Test)->method();
45+
Test::staticMethod();
46+
47+
?>
48+
--EXPECTF--
49+
instance scoped, non-static, $this used
50+
51+
Deprecated: Unbinding $this of closure is deprecated in %s on line %d
52+
instance scoped, static, $this used
53+
instance scoped, non-static, $this not used
54+
static scoped, non-static, $this used
55+
static scoped, static, $this used
56+
static scoped, static, $this not used

Zend/zend_closures.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,8 @@ static zend_bool zend_valid_closure_binding(
8686
&& !(func->common.fn_flags & ZEND_ACC_STATIC)) {
8787
zend_error(E_WARNING, "Cannot unbind $this of method");
8888
return 0;
89-
} else if (!is_fake_closure && !Z_ISUNDEF(closure->this_ptr)) {
89+
} else if (!is_fake_closure && !Z_ISUNDEF(closure->this_ptr)
90+
&& (func->common.fn_flags & ZEND_ACC_USES_THIS)) {
9091
// TODO: Only deprecate if it had $this *originally*?
9192
zend_error(E_DEPRECATED, "Unbinding $this of closure is deprecated");
9293
}

Zend/zend_compile.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2357,6 +2357,7 @@ static zend_op *zend_compile_simple_var(znode *result, zend_ast *ast, uint32_t t
23572357
opline->result_type = IS_TMP_VAR;
23582358
result->op_type = IS_TMP_VAR;
23592359
}
2360+
CG(active_op_array)->fn_flags |= ZEND_ACC_USES_THIS;
23602361
return opline;
23612362
} else if (zend_try_compile_cv(result, ast) == FAILURE) {
23622363
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
24512452

24522453
if (is_this_fetch(obj_ast)) {
24532454
obj_node.op_type = IS_UNUSED;
2455+
CG(active_op_array)->fn_flags |= ZEND_ACC_USES_THIS;
24542456
} else {
24552457
opline = zend_delayed_compile_var(&obj_node, obj_ast, type, 0);
24562458
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) /* {{{ */
29872989
if (is_this_fetch(arg)) {
29882990
zend_emit_op(&arg_node, ZEND_FETCH_THIS, NULL, NULL);
29892991
opcode = ZEND_SEND_VAR_EX;
2992+
CG(active_op_array)->fn_flags |= ZEND_ACC_USES_THIS;
29902993
break;
29912994
} else if (zend_try_compile_cv(&arg_node, arg) == SUCCESS) {
29922995
opcode = ZEND_SEND_VAR_EX;
@@ -3846,6 +3849,7 @@ void zend_compile_method_call(znode *result, zend_ast *ast, uint32_t type) /* {{
38463849

38473850
if (is_this_fetch(obj_ast)) {
38483851
obj_node.op_type = IS_UNUSED;
3852+
CG(active_op_array)->fn_flags |= ZEND_ACC_USES_THIS;
38493853
} else {
38503854
zend_compile_expr(&obj_node, obj_ast);
38513855
}
@@ -7654,6 +7658,7 @@ void zend_compile_isset_or_empty(znode *result, zend_ast *ast) /* {{{ */
76547658
case ZEND_AST_VAR:
76557659
if (is_this_fetch(var_ast)) {
76567660
opline = zend_emit_op(result, ZEND_ISSET_ISEMPTY_THIS, NULL, NULL);
7661+
CG(active_op_array)->fn_flags |= ZEND_ACC_USES_THIS;
76577662
} else if (zend_try_compile_cv(&var_node, var_ast) == SUCCESS) {
76587663
opline = zend_emit_op(result, ZEND_ISSET_ISEMPTY_CV, &var_node, NULL);
76597664
} else {

Zend/zend_compile.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,9 @@ typedef struct _zend_oparray_context {
333333
/* function is a destructor | | | */
334334
#define ZEND_ACC_DTOR (1 << 29) /* | X | | */
335335
/* | | | */
336+
/* closure uses $this | | | */
337+
#define ZEND_ACC_USES_THIS (1 << 30) /* | X | | */
338+
/* | | | */
336339
/* op_array uses strict mode types | | | */
337340
#define ZEND_ACC_STRICT_TYPES (1U << 31) /* | X | | */
338341

0 commit comments

Comments
 (0)