summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLevi Morrison <levim@php.net>2014-05-12 21:53:08 -0600
committerStanislav Malyshev <stas@php.net>2014-06-08 18:59:44 -0700
commitf47976dd9ba5318eb1e358c816288ecd70975d95 (patch)
tree8f401a1d004968c531b62c1599d8f95fc748a126
parent38343856e19185042c54b2cbcc9185aafc741611 (diff)
downloadphp-git-f47976dd9ba5318eb1e358c816288ecd70975d95.tar.gz
Fix bug 666222
This also adds some smaller, isolated tests related to bug 66622.
-rw-r--r--Zend/tests/closure_049.phpt22
-rw-r--r--Zend/tests/closure_050.phpt22
-rw-r--r--Zend/tests/closure_051.phpt21
-rw-r--r--Zend/tests/closure_052.phpt21
-rw-r--r--Zend/tests/closure_053.phpt22
-rw-r--r--Zend/tests/closure_054.phpt22
-rw-r--r--Zend/tests/closure_055.phpt21
-rw-r--r--Zend/tests/closure_056.phpt21
-rw-r--r--Zend/tests/closure_bug66622.phpt37
-rw-r--r--Zend/zend_closures.c4
-rw-r--r--Zend/zend_vm_def.h9
-rw-r--r--Zend/zend_vm_execute.h9
12 files changed, 226 insertions, 5 deletions
diff --git a/Zend/tests/closure_049.phpt b/Zend/tests/closure_049.phpt
new file mode 100644
index 0000000000..684b33d564
--- /dev/null
+++ b/Zend/tests/closure_049.phpt
@@ -0,0 +1,22 @@
+--TEST--
+Closure 049: static::class in static closure in non-static method.
+
+--FILE--
+<?php
+
+class A {
+ function foo() {
+ $f = static function() {
+ return static::class;
+ };
+ return $f();
+ }
+}
+
+class B extends A {}
+
+$b = new B;
+
+var_dump($b->foo());
+--EXPECT--
+string(1) "B"
diff --git a/Zend/tests/closure_050.phpt b/Zend/tests/closure_050.phpt
new file mode 100644
index 0000000000..d43f325ef1
--- /dev/null
+++ b/Zend/tests/closure_050.phpt
@@ -0,0 +1,22 @@
+--TEST--
+Closure 050: static::class in non-static closure in non-static method.
+
+--FILE--
+<?php
+
+class A {
+ function foo() {
+ $f = function() {
+ return static::class;
+ };
+ return $f();
+ }
+}
+
+class B extends A {}
+
+$b = new B;
+var_dump($b->foo());
+
+--EXPECT--
+string(1) "B"
diff --git a/Zend/tests/closure_051.phpt b/Zend/tests/closure_051.phpt
new file mode 100644
index 0000000000..78b28d74a3
--- /dev/null
+++ b/Zend/tests/closure_051.phpt
@@ -0,0 +1,21 @@
+--TEST--
+Closure 051: static::class in static closure in static method.
+
+--FILE--
+<?php
+
+class A {
+ static function foo() {
+ $f = static function() {
+ return static::class;
+ };
+ return $f();
+ }
+}
+
+class B extends A {}
+
+var_dump(B::foo());
+
+--EXPECT--
+string(1) "B"
diff --git a/Zend/tests/closure_052.phpt b/Zend/tests/closure_052.phpt
new file mode 100644
index 0000000000..f878515a82
--- /dev/null
+++ b/Zend/tests/closure_052.phpt
@@ -0,0 +1,21 @@
+--TEST--
+Closure 052: static::class in non-static closure in static method.
+
+--FILE--
+<?php
+
+class A {
+ static function foo() {
+ $f = function() {
+ return static::class;
+ };
+ return $f();
+ }
+}
+
+class B extends A {}
+
+var_dump(B::foo());
+
+--EXPECT--
+string(1) "B"
diff --git a/Zend/tests/closure_053.phpt b/Zend/tests/closure_053.phpt
new file mode 100644
index 0000000000..b1d76a2561
--- /dev/null
+++ b/Zend/tests/closure_053.phpt
@@ -0,0 +1,22 @@
+--TEST--
+Closure 053: self::class in static closure in non-static method.
+
+--FILE--
+<?php
+
+class A {
+ function foo() {
+ $f = static function() {
+ return self::class;
+ };
+ return $f();
+ }
+}
+
+class B extends A {}
+
+$b = new B;
+var_dump($b->foo());
+
+--EXPECT--
+string(1) "A"
diff --git a/Zend/tests/closure_054.phpt b/Zend/tests/closure_054.phpt
new file mode 100644
index 0000000000..b2f87d1d61
--- /dev/null
+++ b/Zend/tests/closure_054.phpt
@@ -0,0 +1,22 @@
+--TEST--
+Closure 054: self::class in non-static closure in non-static method.
+
+--FILE--
+<?php
+
+class A {
+ function foo() {
+ $f = function() {
+ return self::class;
+ };
+ return $f();
+ }
+}
+
+class B extends A {}
+
+$b = new B;
+var_dump($b->foo());
+
+--EXPECT--
+string(1) "A"
diff --git a/Zend/tests/closure_055.phpt b/Zend/tests/closure_055.phpt
new file mode 100644
index 0000000000..047d72a89b
--- /dev/null
+++ b/Zend/tests/closure_055.phpt
@@ -0,0 +1,21 @@
+--TEST--
+Closure 055: self::class in static closure in static method.
+
+--FILE--
+<?php
+
+class A {
+ static function foo() {
+ $f = static function() {
+ return self::class;
+ };
+ return $f();
+ }
+}
+
+class B extends A {}
+
+var_dump(B::foo());
+
+--EXPECT--
+string(1) "A"
diff --git a/Zend/tests/closure_056.phpt b/Zend/tests/closure_056.phpt
new file mode 100644
index 0000000000..566de10d83
--- /dev/null
+++ b/Zend/tests/closure_056.phpt
@@ -0,0 +1,21 @@
+--TEST--
+Closure 056: self::class in non-static closure in static method.
+
+--FILE--
+<?php
+
+class A {
+ static function foo() {
+ $f = function() {
+ return self::class;
+ };
+ return $f();
+ }
+}
+
+class B extends A {}
+
+var_dump(B::foo());
+
+--EXPECT--
+string(1) "A"
diff --git a/Zend/tests/closure_bug66622.phpt b/Zend/tests/closure_bug66622.phpt
new file mode 100644
index 0000000000..1c9577d688
--- /dev/null
+++ b/Zend/tests/closure_bug66622.phpt
@@ -0,0 +1,37 @@
+--TEST--
+Bug 66622: Closures do not correctly capture the late bound class (static::) in some cases
+
+--FILE--
+<?php
+class A {
+ static function name() { return 'A'; }
+ function foo() {
+ $fn = function() { return static::name(); };
+ echo static::name() . ' vs ' . $fn() . "\n";
+ }
+ function bar() {
+ $fn = static function() { return static::name(); };
+ echo static::name() . ' vs ' . $fn() . "\n";
+ }
+ static function baz() {
+ $fn = function() { return static::name(); };
+ echo static::name() . ' vs ' . $fn() . "\n";
+ }
+}
+class B extends A {
+ static function name() { return 'B'; }
+}
+
+function test() {
+ (new B)->foo();
+ (new B)->bar();
+ (new B)->baz();
+ B::baz();
+}
+test();
+
+--EXPECT--
+B vs B
+B vs B
+B vs B
+B vs B
diff --git a/Zend/zend_closures.c b/Zend/zend_closures.c
index fcea56d811..0812724826 100644
--- a/Zend/zend_closures.c
+++ b/Zend/zend_closures.c
@@ -486,6 +486,7 @@ ZEND_API void zend_create_closure(zval *res, zend_function *func, zend_class_ent
}
}
+ closure->this_ptr = NULL;
/* Invariants:
* If the closure is unscoped, it has no bound object.
* The the closure is scoped, it's either static or it's bound */
@@ -497,10 +498,7 @@ ZEND_API void zend_create_closure(zval *res, zend_function *func, zend_class_ent
Z_ADDREF_P(this_ptr);
} else {
closure->func.common.fn_flags |= ZEND_ACC_STATIC;
- closure->this_ptr = NULL;
}
- } else {
- closure->this_ptr = NULL;
}
}
/* }}} */
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h
index 03cc9c45a0..f76e52961a 100644
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@ -5179,6 +5179,7 @@ ZEND_VM_HANDLER(153, ZEND_DECLARE_LAMBDA_FUNCTION, CONST, UNUSED)
{
USE_OPLINE
zend_function *op_array;
+ int closure_is_static, closure_is_being_defined_inside_static_context;
SAVE_OPLINE();
@@ -5187,7 +5188,13 @@ ZEND_VM_HANDLER(153, ZEND_DECLARE_LAMBDA_FUNCTION, CONST, UNUSED)
zend_error_noreturn(E_ERROR, "Base lambda function for closure not found");
}
- zend_create_closure(&EX_T(opline->result.var).tmp_var, (zend_function *) op_array, EG(scope), EG(This) TSRMLS_CC);
+ closure_is_static = op_array->common.fn_flags & ZEND_ACC_STATIC;
+ closure_is_being_defined_inside_static_context = EX(prev_execute_data) && EX(prev_execute_data)->function_state.function->common.fn_flags & ZEND_ACC_STATIC;
+ if (closure_is_static || closure_is_being_defined_inside_static_context) {
+ zend_create_closure(&EX_T(opline->result.var).tmp_var, (zend_function *) op_array, EG(called_scope), NULL TSRMLS_CC);
+ } else {
+ zend_create_closure(&EX_T(opline->result.var).tmp_var, (zend_function *) op_array, EG(scope), EG(This) TSRMLS_CC);
+ }
CHECK_EXCEPTION();
ZEND_VM_NEXT_OPCODE();
diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h
index 511a40b37e..94026a08ef 100644
--- a/Zend/zend_vm_execute.h
+++ b/Zend/zend_vm_execute.h
@@ -6487,6 +6487,7 @@ static int ZEND_FASTCALL ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_CONST_UNUSED_HANDLER
{
USE_OPLINE
zend_function *op_array;
+ int closure_is_static, closure_is_being_defined_inside_static_context;
SAVE_OPLINE();
@@ -6495,7 +6496,13 @@ static int ZEND_FASTCALL ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_CONST_UNUSED_HANDLER
zend_error_noreturn(E_ERROR, "Base lambda function for closure not found");
}
- zend_create_closure(&EX_T(opline->result.var).tmp_var, (zend_function *) op_array, EG(scope), EG(This) TSRMLS_CC);
+ closure_is_static = op_array->common.fn_flags & ZEND_ACC_STATIC;
+ closure_is_being_defined_inside_static_context = EX(prev_execute_data) && EX(prev_execute_data)->function_state.function->common.fn_flags & ZEND_ACC_STATIC;
+ if (closure_is_static || closure_is_being_defined_inside_static_context) {
+ zend_create_closure(&EX_T(opline->result.var).tmp_var, (zend_function *) op_array, EG(called_scope), NULL TSRMLS_CC);
+ } else {
+ zend_create_closure(&EX_T(opline->result.var).tmp_var, (zend_function *) op_array, EG(scope), EG(This) TSRMLS_CC);
+ }
CHECK_EXCEPTION();
ZEND_VM_NEXT_OPCODE();