Skip to content

Commit a935292

Browse files
committed
PFA rebinding validation
1 parent 4646d0e commit a935292

File tree

3 files changed

+112
-1
lines changed

3 files changed

+112
-1
lines changed
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
--TEST--
2+
Partial application can only be rebound to an instanceof $this
3+
--FILE--
4+
<?php
5+
6+
class C {
7+
function f($a) { var_dump($this); }
8+
static function g($a) { var_dump(static::class); }
9+
}
10+
11+
class SubClass extends C {}
12+
13+
class Unrelated {}
14+
15+
$c = new C;
16+
$f = $c->f(?);
17+
$g = $c->g(?);
18+
19+
echo "# Can be rebound to \$this of the same class:\n";
20+
$f->bindTo(new C)(1);
21+
22+
echo "# Can be rebound to \$this of a sub-class:\n";
23+
$f->bindTo(new SubClass)(1);
24+
25+
echo "# Cannot be rebound to an unrelated class:\n";
26+
try {
27+
$f->bindTo(new Unrelated)(1);
28+
} catch (Error $e) {
29+
echo $e->getMessage(), "\n";
30+
}
31+
32+
echo "# Cannot unbind \$this on instance method:\n";
33+
try {
34+
$f->bindTo(null)(1);
35+
} catch (Error $e) {
36+
echo $e->getMessage(), "\n";
37+
}
38+
39+
echo "# Can unbind \$this on static method:\n";
40+
try {
41+
$g->bindTo(null)(1);
42+
} catch (Error $e) {
43+
echo $e->getMessage(), "\n";
44+
}
45+
46+
?>
47+
--EXPECTF--
48+
# Can be rebound to $this of the same class:
49+
object(C)#%d (0) {
50+
}
51+
# Can be rebound to $this of a sub-class:
52+
object(SubClass)#%d (0) {
53+
}
54+
# Cannot be rebound to an unrelated class:
55+
56+
Warning: Cannot bind method C::f() to object of class Unrelated in %s on line %d
57+
Value of type null is not callable
58+
# Cannot unbind $this on instance method:
59+
60+
Warning: Cannot unbind $this of method in %s on line %d
61+
Value of type null is not callable
62+
# Can unbind $this on static method:
63+
64+
Warning: Cannot unbind $this of method in %s on line %d
65+
Value of type null is not callable
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
--TEST--
2+
Partial application scope cannot be rebound
3+
--FILE--
4+
<?php
5+
6+
class C {
7+
function f($a) { var_dump(static::class); }
8+
}
9+
10+
class SubClass extends C {}
11+
12+
function g($a) { var_dump(__FUNCTION__); }
13+
14+
$c = new C;
15+
$f = $c->f(?);
16+
$g = g(?);
17+
18+
echo "# Can be rebound to the same scope:\n";
19+
$f->bindTo($c, C::class)(1);
20+
21+
echo "# Method cannot be rebound to a different scope:\n";
22+
try {
23+
$f->bindTo($c, SubClass::class)(1);
24+
} catch (Error $e) {
25+
echo $e->getMessage(), "\n";
26+
}
27+
28+
echo "# Function cannot be refound to a different scope:\n";
29+
try {
30+
$g->bindTo($c, SubClass::class)(1);
31+
} catch (Error $e) {
32+
echo $e->getMessage(), "\n";
33+
}
34+
?>
35+
--EXPECTF--
36+
# Can be rebound to the same scope:
37+
string(1) "C"
38+
# Method cannot be rebound to a different scope:
39+
40+
Warning: Cannot rebind scope of closure created from method in %s on line %d
41+
Value of type null is not callable
42+
# Function cannot be refound to a different scope:
43+
44+
Warning: Cannot rebind scope of closure created from function in %s on line %d
45+
Value of type null is not callable

Zend/zend_closures.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,8 @@ static bool zend_valid_closure_binding(
8484
zend_closure *closure, zval *newthis, zend_class_entry *scope) /* {{{ */
8585
{
8686
zend_function *func = &closure->func;
87-
bool is_fake_closure = (func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE) != 0;
87+
bool is_fake_closure = (func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE) != 0
88+
|| (closure->closure_flags & ZEND_CLOSURE_PARTIAL);
8889

8990
if (newthis) {
9091
if (func->common.fn_flags & ZEND_ACC_STATIC) {

0 commit comments

Comments
 (0)