diff options
author | Levi Morrison <levim@php.net> | 2014-05-12 21:53:08 -0600 |
---|---|---|
committer | Stanislav Malyshev <stas@php.net> | 2014-06-08 18:59:44 -0700 |
commit | f47976dd9ba5318eb1e358c816288ecd70975d95 (patch) | |
tree | 8f401a1d004968c531b62c1599d8f95fc748a126 | |
parent | 38343856e19185042c54b2cbcc9185aafc741611 (diff) | |
download | php-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.phpt | 22 | ||||
-rw-r--r-- | Zend/tests/closure_050.phpt | 22 | ||||
-rw-r--r-- | Zend/tests/closure_051.phpt | 21 | ||||
-rw-r--r-- | Zend/tests/closure_052.phpt | 21 | ||||
-rw-r--r-- | Zend/tests/closure_053.phpt | 22 | ||||
-rw-r--r-- | Zend/tests/closure_054.phpt | 22 | ||||
-rw-r--r-- | Zend/tests/closure_055.phpt | 21 | ||||
-rw-r--r-- | Zend/tests/closure_056.phpt | 21 | ||||
-rw-r--r-- | Zend/tests/closure_bug66622.phpt | 37 | ||||
-rw-r--r-- | Zend/zend_closures.c | 4 | ||||
-rw-r--r-- | Zend/zend_vm_def.h | 9 | ||||
-rw-r--r-- | Zend/zend_vm_execute.h | 9 |
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(); |