mirror of
https://github.com/php/php-src.git
synced 2024-11-27 03:44:07 +08:00
Implemented RFC: Fix inconsistent behavior of $this variable
Squashed commit of the following: commitbdd3b6895c
Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Jun 16 00:19:42 2016 +0300 Fixed GOTO VM commit2f1d7c8b89
Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 21:01:57 2016 +0300 Removed unused variable commitcf749c42b0
Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 19:06:16 2016 +0300 Protection from $this reassign through mb_parse_str() commit59a9a6c83c
Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 18:14:50 2016 +0300 Added type inference rule for FETCH_THIS opcode commit73f8d14a85
Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 18:11:18 2016 +0300 Restored PHP-7 behavior of isset($this->foo). It throws exception if not in object context. Removed useless opcode handlers. commitfa0881381e
Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 31 12:25:47 2016 +0300 Changed "Notice: Undefined variable: this" into "Exception: Using $this when not in object context". commite32cc528c0
Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 24 02:02:43 2016 +0300 Throw exception on attempt to re-assign $this through extract() and parse_str(). commit41f1531b52
Author: Dmitry Stogov <dmitry@zend.com> Date: Mon May 23 22:18:36 2016 +0300 Fixed inconsistent $this behavior
This commit is contained in:
parent
fba6f90ae3
commit
a9512af810
@ -31,40 +31,4 @@ $test->bar();
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
object(Exception)#%d (7) {
|
||||
["message":protected]=>
|
||||
string(3) "foo"
|
||||
["string":"Exception":private]=>
|
||||
string(0) ""
|
||||
["code":protected]=>
|
||||
int(0)
|
||||
["file":protected]=>
|
||||
string(%d) "%s030.php"
|
||||
["line":protected]=>
|
||||
int(%d)
|
||||
["trace":"Exception":private]=>
|
||||
array(1) {
|
||||
[0]=>
|
||||
array(6) {
|
||||
["file"]=>
|
||||
string(%d) "%s030.php"
|
||||
["line"]=>
|
||||
int(%d)
|
||||
["function"]=>
|
||||
string(3) "bar"
|
||||
["class"]=>
|
||||
string(3) "foo"
|
||||
["type"]=>
|
||||
string(2) "->"
|
||||
["args"]=>
|
||||
array(0) {
|
||||
}
|
||||
}
|
||||
}
|
||||
["previous":"Exception":private]=>
|
||||
NULL
|
||||
}
|
||||
'test' => '0'
|
||||
'test_2' => '1'
|
||||
'test_3' => '2'
|
||||
ok
|
||||
Fatal error: Cannot re-assign $this in %s030.php on line 11
|
||||
|
@ -13,6 +13,4 @@ $x = $c->test();
|
||||
print_r($x);
|
||||
unset($c, $x);
|
||||
--EXPECTF--
|
||||
Array
|
||||
(
|
||||
)
|
||||
Fatal error: Cannot unset $this in %sbug68370.php on line 4
|
||||
|
@ -5,7 +5,7 @@ Calling method from array
|
||||
|
||||
class Hello {
|
||||
public function world($x) {
|
||||
echo "Hello, $x\n"; return $this;
|
||||
echo "Hello, $x\n";return $this;
|
||||
}
|
||||
}
|
||||
|
||||
@ -37,8 +37,16 @@ class Magic3 {
|
||||
}
|
||||
|
||||
$f = array('Hello','world');
|
||||
var_dump($f('you'));
|
||||
var_dump(call_user_func($f, 'you'));
|
||||
try {
|
||||
var_dump($f('you'));
|
||||
} catch (Throwable $e) {
|
||||
echo "Exception: " . $e->getMessage() . "\n";
|
||||
}
|
||||
try {
|
||||
var_dump(call_user_func($f, 'you'));
|
||||
} catch (Throwable $e) {
|
||||
echo "Exception: " . $e->getMessage() . "\n";
|
||||
}
|
||||
|
||||
printf("-----\n");
|
||||
|
||||
@ -101,35 +109,31 @@ var_dump(call_user_func($f, 'you'));
|
||||
--EXPECTF--
|
||||
Deprecated: Non-static method Hello::world() should not be called statically in %s on line %d
|
||||
Hello, you
|
||||
|
||||
Notice: Undefined variable: this in %s on line %d
|
||||
NULL
|
||||
Exception: Using $this when not in object context
|
||||
|
||||
Deprecated: %son-static method Hello::world() should not be called statically in %s on line %d
|
||||
Hello, you
|
||||
|
||||
Notice: Undefined variable: this in %s on line %d
|
||||
NULL
|
||||
Exception: Using $this when not in object context
|
||||
-----
|
||||
Hello, again
|
||||
object(Hello)#1 (0) {
|
||||
object(Hello)#%d (0) {
|
||||
}
|
||||
Hello, again
|
||||
object(Hello)#1 (0) {
|
||||
object(Hello)#%d (0) {
|
||||
}
|
||||
-----
|
||||
Hello, there
|
||||
object(Hello)#2 (0) {
|
||||
object(Hello)#%d (0) {
|
||||
}
|
||||
Hello, there
|
||||
object(Hello)#2 (0) {
|
||||
object(Hello)#%d (0) {
|
||||
}
|
||||
-----
|
||||
Hello, devs
|
||||
object(Hello)#4 (0) {
|
||||
object(Hello)#%d (0) {
|
||||
}
|
||||
Hello, devs
|
||||
object(Hello)#4 (0) {
|
||||
object(Hello)#%d (0) {
|
||||
}
|
||||
-----
|
||||
Magic::__call called (foo)!
|
||||
|
@ -10,11 +10,12 @@ class B {
|
||||
function bar() { A::foo(); }
|
||||
}
|
||||
$b = new B;
|
||||
$b->bar();
|
||||
|
||||
try {
|
||||
$b->bar();
|
||||
} catch (Throwable $e) {
|
||||
echo "Exception: " . $e->getMessage() . "\n";
|
||||
}
|
||||
?>
|
||||
--EXPECTF--
|
||||
Deprecated: Non-static method A::foo() should not be called statically in %s on line %d
|
||||
|
||||
Notice: Undefined variable: this in %s on line %d
|
||||
string(1) "A"
|
||||
Exception: Using $this when not in object context
|
||||
|
@ -17,8 +17,11 @@ class foo {
|
||||
}
|
||||
|
||||
$arr = array('foo', 'abc');
|
||||
$arr();
|
||||
|
||||
try {
|
||||
$arr();
|
||||
} catch (Throwable $e) {
|
||||
echo "Exception: " . $e->getMessage() . "\n";
|
||||
}
|
||||
$foo = new foo;
|
||||
$arr = array($foo, 'abc');
|
||||
$arr();
|
||||
@ -28,9 +31,7 @@ $arr();
|
||||
--EXPECTF--
|
||||
From foo::__callStatic:
|
||||
string(3) "abc"
|
||||
|
||||
Notice: Undefined variable: this in %s on line %d
|
||||
NULL
|
||||
Exception: Using $this when not in object context
|
||||
From foo::__call:
|
||||
string(3) "abc"
|
||||
object(foo)#%d (0) {
|
||||
|
12
Zend/tests/this_as_global.phpt
Normal file
12
Zend/tests/this_as_global.phpt
Normal file
@ -0,0 +1,12 @@
|
||||
--TEST--
|
||||
$this as global variable
|
||||
--FILE--
|
||||
<?php
|
||||
function foo() {
|
||||
global $this;
|
||||
var_dump($this);
|
||||
}
|
||||
foo();
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Cannot use $this as global variable in %sthis_as_global.php on line 3
|
11
Zend/tests/this_as_parameter.phpt
Normal file
11
Zend/tests/this_as_parameter.phpt
Normal file
@ -0,0 +1,11 @@
|
||||
--TEST--
|
||||
$this as parameter
|
||||
--FILE--
|
||||
<?php
|
||||
function foo($this) {
|
||||
var_dump($this);
|
||||
}
|
||||
foo(5);
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Cannot use $this as parameter in %sthis_as_parameter.php on line 2
|
12
Zend/tests/this_as_static.phpt
Normal file
12
Zend/tests/this_as_static.phpt
Normal file
@ -0,0 +1,12 @@
|
||||
--TEST--
|
||||
$this as static variable
|
||||
--FILE--
|
||||
<?php
|
||||
function foo() {
|
||||
static $this;
|
||||
var_dump($this);
|
||||
}
|
||||
foo();
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Cannot use $this as static variable in %sthis_as_static.php on line 3
|
18
Zend/tests/this_in_catch.phpt
Normal file
18
Zend/tests/this_in_catch.phpt
Normal file
@ -0,0 +1,18 @@
|
||||
--TEST--
|
||||
$this in catch
|
||||
--FILE--
|
||||
<?php
|
||||
class C {
|
||||
function foo() {
|
||||
try {
|
||||
throw new Exception();
|
||||
} catch (Exception $this) {
|
||||
}
|
||||
var_dump($this);
|
||||
}
|
||||
}
|
||||
$obj = new C;
|
||||
$obj->foo();
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Cannot re-assign $this in %sthis_in_catch.php on line 6
|
17
Zend/tests/this_in_extract.phpt
Normal file
17
Zend/tests/this_in_extract.phpt
Normal file
@ -0,0 +1,17 @@
|
||||
--TEST--
|
||||
$this re-assign in extract()
|
||||
--FILE--
|
||||
<?php
|
||||
function foo() {
|
||||
extract(["this"=>42]);
|
||||
var_dump($this);
|
||||
}
|
||||
foo();
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Uncaught Error: Cannot re-assign $this in %sthis_in_extract.php:3
|
||||
Stack trace:
|
||||
#0 %sthis_in_extract.php(3): extract(Array)
|
||||
#1 %sthis_in_extract.php(6): foo()
|
||||
#2 {main}
|
||||
thrown in %sthis_in_extract.php on line 3
|
11
Zend/tests/this_in_foreach_001.phpt
Normal file
11
Zend/tests/this_in_foreach_001.phpt
Normal file
@ -0,0 +1,11 @@
|
||||
--TEST--
|
||||
$this in foreach
|
||||
--FILE--
|
||||
<?php
|
||||
$a = [1];
|
||||
foreach ($a as $this) {
|
||||
var_dump($this);
|
||||
}
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Cannot re-assign $this in %sthis_in_foreach_001.php on line 3
|
11
Zend/tests/this_in_foreach_002.phpt
Normal file
11
Zend/tests/this_in_foreach_002.phpt
Normal file
@ -0,0 +1,11 @@
|
||||
--TEST--
|
||||
$this in foreach
|
||||
--FILE--
|
||||
<?php
|
||||
$a = [1];
|
||||
foreach ($a as $this => $dummy) {
|
||||
var_dump($this);
|
||||
}
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Cannot re-assign $this in %sthis_in_foreach_002.php on line 3
|
11
Zend/tests/this_in_foreach_003.phpt
Normal file
11
Zend/tests/this_in_foreach_003.phpt
Normal file
@ -0,0 +1,11 @@
|
||||
--TEST--
|
||||
$this in foreach
|
||||
--FILE--
|
||||
<?php
|
||||
$a = [1];
|
||||
foreach ($a as &$this) {
|
||||
var_dump($this);
|
||||
}
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Cannot re-assign $this in %sthis_in_foreach_003.php on line 3
|
11
Zend/tests/this_in_foreach_004.phpt
Normal file
11
Zend/tests/this_in_foreach_004.phpt
Normal file
@ -0,0 +1,11 @@
|
||||
--TEST--
|
||||
$this in foreach
|
||||
--FILE--
|
||||
<?php
|
||||
$a = [[1]];
|
||||
foreach ($a as list($this)) {
|
||||
var_dump($this);
|
||||
}
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Cannot re-assign $this in %sthis_in_foreach_004.php on line 3
|
41
Zend/tests/this_in_isset.phpt
Normal file
41
Zend/tests/this_in_isset.phpt
Normal file
@ -0,0 +1,41 @@
|
||||
--TEST--
|
||||
$this in isset
|
||||
--FILE--
|
||||
<?php
|
||||
var_dump(isset($this));
|
||||
try {
|
||||
var_dump(isset($this->foo));
|
||||
} catch (Throwable $e) {
|
||||
echo "exception\n";
|
||||
}
|
||||
try {
|
||||
var_dump(isset($this->foo->bar));
|
||||
} catch (Throwable $e) {
|
||||
echo "exception\n";
|
||||
}
|
||||
try {
|
||||
var_dump(isset($this[0]));
|
||||
} catch (Throwable $e) {
|
||||
echo "exception\n";
|
||||
}
|
||||
|
||||
class A extends ArrayObject {
|
||||
public $foo = 5;
|
||||
function foo() {
|
||||
$this[0] = 5;
|
||||
var_dump(isset($this));
|
||||
var_dump(isset($this->foo));
|
||||
var_dump(isset($this[0]));
|
||||
}
|
||||
}
|
||||
$a = new A();
|
||||
$a->foo();
|
||||
?>
|
||||
--EXPECT--
|
||||
bool(false)
|
||||
exception
|
||||
exception
|
||||
exception
|
||||
bool(true)
|
||||
bool(true)
|
||||
bool(true)
|
19
Zend/tests/this_in_mb_parse_str.phpt
Normal file
19
Zend/tests/this_in_mb_parse_str.phpt
Normal file
@ -0,0 +1,19 @@
|
||||
--TEST--
|
||||
$this re-assign in mb_parse_str()
|
||||
--SKIPIF--
|
||||
<?php extension_loaded('mbstring') or die('skip mbstring not available'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
function foo() {
|
||||
mb_parse_str("this=42");
|
||||
var_dump($this);
|
||||
}
|
||||
foo();
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Uncaught Error: Cannot re-assign $this in %sthis_in_mb_parse_str.php:3
|
||||
Stack trace:
|
||||
#0 %sthis_in_mb_parse_str.php(3): mb_parse_str('this=42')
|
||||
#1 %sthis_in_mb_parse_str.php(6): foo()
|
||||
#2 {main}
|
||||
thrown in %sthis_in_mb_parse_str.php on line 3
|
17
Zend/tests/this_in_parse_str.phpt
Normal file
17
Zend/tests/this_in_parse_str.phpt
Normal file
@ -0,0 +1,17 @@
|
||||
--TEST--
|
||||
$this re-assign in parse_str()
|
||||
--FILE--
|
||||
<?php
|
||||
function foo() {
|
||||
parse_str("this=42");
|
||||
var_dump($this);
|
||||
}
|
||||
foo();
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Uncaught Error: Cannot re-assign $this in %sthis_in_parse_str.php:3
|
||||
Stack trace:
|
||||
#0 %sthis_in_parse_str.php(3): parse_str('this=42')
|
||||
#1 %sthis_in_parse_str.php(6): foo()
|
||||
#2 {main}
|
||||
thrown in %sthis_in_parse_str.php on line 3
|
8
Zend/tests/this_in_unset.phpt
Normal file
8
Zend/tests/this_in_unset.phpt
Normal file
@ -0,0 +1,8 @@
|
||||
--TEST--
|
||||
$this in unset
|
||||
--FILE--
|
||||
<?php
|
||||
unset($this);
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Cannot unset $this in %sthis_in_unset.php on line 2
|
17
Zend/tests/this_reassign.phpt
Normal file
17
Zend/tests/this_reassign.phpt
Normal file
@ -0,0 +1,17 @@
|
||||
--TEST--
|
||||
$this re-assign
|
||||
--FILE--
|
||||
<?php
|
||||
function foo() {
|
||||
$a = "this";
|
||||
$$a = 0;
|
||||
var_dump($$a);
|
||||
}
|
||||
foo();
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Uncaught Error: Cannot re-assign $this in %sthis_reassign.php:4
|
||||
Stack trace:
|
||||
#0 %sthis_reassign.php(7): foo()
|
||||
#1 {main}
|
||||
thrown in %sthis_reassign.php on line 4
|
@ -756,6 +756,9 @@ void zend_do_free(znode *op1) /* {{{ */
|
||||
additional FREE opcode and simplify the FETCH handlers
|
||||
their selves */
|
||||
zend_emit_op(NULL, ZEND_FREE, op1, NULL);
|
||||
} else if (opline->opcode == ZEND_FETCH_THIS) {
|
||||
opline->opcode = ZEND_NOP;
|
||||
opline->result_type = IS_UNUSED;
|
||||
} else {
|
||||
opline->result_type = IS_UNUSED;
|
||||
}
|
||||
@ -1928,6 +1931,10 @@ static void zend_adjust_for_fetch_type(zend_op *opline, uint32_t type) /* {{{ */
|
||||
{
|
||||
zend_uchar factor = (opline->opcode == ZEND_FETCH_STATIC_PROP_R) ? 1 : 3;
|
||||
|
||||
if (opline->opcode == ZEND_FETCH_THIS) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (type & BP_VAR_MASK) {
|
||||
case BP_VAR_R:
|
||||
return;
|
||||
@ -2527,9 +2534,6 @@ static int zend_try_compile_cv(znode *result, zend_ast *ast) /* {{{ */
|
||||
/* lookup_cv may be using another zend_string instance */
|
||||
name = CG(active_op_array)->vars[EX_VAR_TO_NUM(result->u.op.var)];
|
||||
|
||||
if (zend_string_equals_literal(name, "this")) {
|
||||
CG(active_op_array)->this_var = result->u.op.var;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
@ -2560,22 +2564,31 @@ static zend_op *zend_compile_simple_var_no_cv(znode *result, zend_ast *ast, uint
|
||||
opline->extended_value = ZEND_FETCH_GLOBAL;
|
||||
} else {
|
||||
opline->extended_value = ZEND_FETCH_LOCAL;
|
||||
/* there is a chance someone is accessing $this */
|
||||
if (ast->kind != ZEND_AST_ZVAL
|
||||
&& CG(active_op_array)->scope && CG(active_op_array)->this_var == (uint32_t)-1
|
||||
) {
|
||||
zend_string *key = CG(known_strings)[ZEND_STR_THIS];
|
||||
CG(active_op_array)->this_var = lookup_cv(CG(active_op_array), key);
|
||||
}
|
||||
}
|
||||
|
||||
return opline;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static zend_bool is_this_fetch(zend_ast *ast) /* {{{ */
|
||||
{
|
||||
if (ast->kind == ZEND_AST_VAR && ast->child[0]->kind == ZEND_AST_ZVAL) {
|
||||
zval *name = zend_ast_get_zval(ast->child[0]);
|
||||
return Z_TYPE_P(name) == IS_STRING && zend_string_equals_literal(Z_STR_P(name), "this");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static void zend_compile_simple_var(znode *result, zend_ast *ast, uint32_t type, int delayed) /* {{{ */
|
||||
{
|
||||
if (zend_try_compile_cv(result, ast) == FAILURE) {
|
||||
zend_op *opline;
|
||||
|
||||
if (is_this_fetch(ast)) {
|
||||
opline = zend_emit_op(result, ZEND_FETCH_THIS, NULL, NULL);
|
||||
zend_adjust_for_fetch_type(opline, type);
|
||||
} else if (zend_try_compile_cv(result, ast) == FAILURE) {
|
||||
zend_op *opline = zend_compile_simple_var_no_cv(result, ast, type, delayed);
|
||||
zend_adjust_for_fetch_type(opline, type);
|
||||
}
|
||||
@ -2656,17 +2669,6 @@ void zend_compile_dim(znode *result, zend_ast *ast, uint32_t type) /* {{{ */
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static zend_bool is_this_fetch(zend_ast *ast) /* {{{ */
|
||||
{
|
||||
if (ast->kind == ZEND_AST_VAR && ast->child[0]->kind == ZEND_AST_ZVAL) {
|
||||
zval *name = zend_ast_get_zval(ast->child[0]);
|
||||
return Z_TYPE_P(name) == IS_STRING && zend_string_equals_literal(Z_STR_P(name), "this");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static zend_op *zend_delayed_compile_prop(znode *result, zend_ast *ast, uint32_t type) /* {{{ */
|
||||
{
|
||||
zend_ast *obj_ast = ast->child[0];
|
||||
@ -2965,7 +2967,8 @@ void zend_compile_assign(znode *result, zend_ast *ast) /* {{{ */
|
||||
offset = zend_delayed_compile_begin();
|
||||
zend_delayed_compile_dim(result, var_ast, BP_VAR_W);
|
||||
|
||||
if (zend_is_assign_to_self(var_ast, expr_ast)) {
|
||||
if (zend_is_assign_to_self(var_ast, expr_ast)
|
||||
&& !is_this_fetch(expr_ast)) {
|
||||
/* $a[0] = $a should evaluate the right $a first */
|
||||
zend_compile_simple_var_no_cv(&expr_node, expr_ast, BP_VAR_R, 0);
|
||||
} else {
|
||||
@ -3899,7 +3902,9 @@ void zend_compile_global_var(zend_ast *ast) /* {{{ */
|
||||
convert_to_string(&name_node.u.constant);
|
||||
}
|
||||
|
||||
if (zend_try_compile_cv(&result, var_ast) == SUCCESS) {
|
||||
if (is_this_fetch(var_ast)) {
|
||||
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use $this as global variable");
|
||||
} else if (zend_try_compile_cv(&result, var_ast) == SUCCESS) {
|
||||
zend_op *opline = zend_emit_op(NULL, ZEND_BIND_GLOBAL, &result, &name_node);
|
||||
zend_alloc_cache_slot(opline->op2.constant);
|
||||
} else {
|
||||
@ -3944,6 +3949,10 @@ static void zend_compile_static_var_common(zend_ast *var_ast, zval *value, zend_
|
||||
}
|
||||
zend_hash_update(CG(active_op_array)->static_variables, Z_STR(var_node.u.constant), value);
|
||||
|
||||
if (zend_string_equals_literal(Z_STR(var_node.u.constant), "this")) {
|
||||
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use $this as static variable");
|
||||
}
|
||||
|
||||
opline = zend_emit_op(NULL, ZEND_BIND_STATIC, NULL, &var_node);
|
||||
opline->op1_type = IS_CV;
|
||||
opline->op1.var = lookup_cv(CG(active_op_array), zend_string_copy(Z_STR(var_node.u.constant)));
|
||||
@ -3977,7 +3986,9 @@ void zend_compile_unset(zend_ast *ast) /* {{{ */
|
||||
|
||||
switch (var_ast->kind) {
|
||||
case ZEND_AST_VAR:
|
||||
if (zend_try_compile_cv(&var_node, var_ast) == SUCCESS) {
|
||||
if (is_this_fetch(var_ast)) {
|
||||
zend_error_noreturn(E_COMPILE_ERROR, "Cannot unset $this");
|
||||
} else if (zend_try_compile_cv(&var_node, var_ast) == SUCCESS) {
|
||||
opline = zend_emit_op(NULL, ZEND_UNSET_VAR, &var_node, NULL);
|
||||
opline->extended_value = ZEND_FETCH_LOCAL | ZEND_QUICK_SET;
|
||||
} else {
|
||||
@ -4412,7 +4423,9 @@ void zend_compile_foreach(zend_ast *ast) /* {{{ */
|
||||
opnum_fetch = get_next_op_number(CG(active_op_array));
|
||||
opline = zend_emit_op(NULL, by_ref ? ZEND_FE_FETCH_RW : ZEND_FE_FETCH_R, &reset_node, NULL);
|
||||
|
||||
if (value_ast->kind == ZEND_AST_VAR &&
|
||||
if (is_this_fetch(value_ast)) {
|
||||
zend_error_noreturn(E_COMPILE_ERROR, "Cannot re-assign $this");
|
||||
} else if (value_ast->kind == ZEND_AST_VAR &&
|
||||
zend_try_compile_cv(&value_node, value_ast) == SUCCESS) {
|
||||
SET_NODE(opline->op2, &value_node);
|
||||
} else {
|
||||
@ -4666,6 +4679,10 @@ void zend_compile_try(zend_ast *ast) /* {{{ */
|
||||
opline->op1.constant = zend_add_class_name_literal(CG(active_op_array),
|
||||
zend_resolve_class_name_ast(class_ast));
|
||||
|
||||
if (zend_string_equals_literal(Z_STR_P(var_name), "this")) {
|
||||
zend_error_noreturn(E_COMPILE_ERROR, "Cannot re-assign $this");
|
||||
}
|
||||
|
||||
opline->op2_type = IS_CV;
|
||||
opline->op2.var = lookup_cv(CG(active_op_array), zend_string_copy(Z_STR_P(var_name)));
|
||||
|
||||
@ -5009,11 +5026,7 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast) /* {{{ */
|
||||
zend_error_noreturn(E_COMPILE_ERROR, "Redefinition of parameter $%s",
|
||||
ZSTR_VAL(name));
|
||||
} else if (zend_string_equals_literal(name, "this")) {
|
||||
if ((op_array->scope || (op_array->fn_flags & ZEND_ACC_CLOSURE))
|
||||
&& (op_array->fn_flags & ZEND_ACC_STATIC) == 0) {
|
||||
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use $this as parameter");
|
||||
}
|
||||
op_array->this_var = var_node.u.op.var;
|
||||
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use $this as parameter");
|
||||
}
|
||||
|
||||
if (op_array->fn_flags & ZEND_ACC_VARIADIC) {
|
||||
@ -6996,7 +7009,9 @@ void zend_compile_isset_or_empty(znode *result, zend_ast *ast) /* {{{ */
|
||||
|
||||
switch (var_ast->kind) {
|
||||
case ZEND_AST_VAR:
|
||||
if (zend_try_compile_cv(&var_node, var_ast) == SUCCESS) {
|
||||
if (is_this_fetch(var_ast)) {
|
||||
opline = zend_emit_op(result, ZEND_ISSET_ISEMPTY_THIS, NULL, NULL);
|
||||
} else if (zend_try_compile_cv(&var_node, var_ast) == SUCCESS) {
|
||||
opline = zend_emit_op(result, ZEND_ISSET_ISEMPTY_VAR, &var_node, NULL);
|
||||
opline->extended_value = ZEND_FETCH_LOCAL | ZEND_QUICK_SET;
|
||||
} else {
|
||||
|
@ -364,8 +364,6 @@ struct _zend_op_array {
|
||||
|
||||
uint32_t *refcount;
|
||||
|
||||
uint32_t this_var;
|
||||
|
||||
uint32_t last;
|
||||
zend_op *opcodes;
|
||||
|
||||
|
@ -2133,7 +2133,7 @@ static zend_never_inline ZEND_COLD ZEND_NORETURN void ZEND_FASTCALL zend_interru
|
||||
* +----------------------------------------+
|
||||
*/
|
||||
|
||||
static zend_always_inline void i_init_func_execute_data(zend_execute_data *execute_data, zend_op_array *op_array, zval *return_value, int check_this) /* {{{ */
|
||||
static zend_always_inline void i_init_func_execute_data(zend_execute_data *execute_data, zend_op_array *op_array, zval *return_value) /* {{{ */
|
||||
{
|
||||
uint32_t first_extra_arg, num_args;
|
||||
ZEND_ASSERT(EX(func) == (zend_function*)op_array);
|
||||
@ -2191,11 +2191,6 @@ static zend_always_inline void i_init_func_execute_data(zend_execute_data *execu
|
||||
} while (var != end);
|
||||
}
|
||||
|
||||
if (check_this && op_array->this_var != (uint32_t)-1 && EXPECTED(Z_TYPE(EX(This)) == IS_OBJECT)) {
|
||||
ZVAL_OBJ(EX_VAR(op_array->this_var), Z_OBJ(EX(This)));
|
||||
GC_REFCOUNT(Z_OBJ(EX(This)))++;
|
||||
}
|
||||
|
||||
EX_LOAD_RUN_TIME_CACHE(op_array);
|
||||
EX_LOAD_LITERALS(op_array);
|
||||
|
||||
@ -2219,13 +2214,6 @@ static zend_always_inline void i_init_code_execute_data(zend_execute_data *execu
|
||||
EX(call) = NULL;
|
||||
EX(return_value) = return_value;
|
||||
|
||||
if (UNEXPECTED(op_array->this_var != (uint32_t)-1) && EXPECTED(Z_TYPE(EX(This)) == IS_OBJECT)) {
|
||||
GC_REFCOUNT(Z_OBJ(EX(This)))++;
|
||||
if (!zend_hash_add(EX(symbol_table), CG(known_strings)[ZEND_STR_THIS], &EX(This))) {
|
||||
GC_REFCOUNT(Z_OBJ(EX(This)))--;
|
||||
}
|
||||
}
|
||||
|
||||
zend_attach_symbol_table(execute_data);
|
||||
|
||||
if (!op_array->run_time_cache) {
|
||||
@ -2248,13 +2236,6 @@ static zend_always_inline void i_init_execute_data(zend_execute_data *execute_da
|
||||
EX(return_value) = return_value;
|
||||
|
||||
if (EX_CALL_INFO() & ZEND_CALL_HAS_SYMBOL_TABLE) {
|
||||
if (UNEXPECTED(op_array->this_var != (uint32_t)-1) && EXPECTED(Z_TYPE(EX(This)) == IS_OBJECT)) {
|
||||
GC_REFCOUNT(Z_OBJ(EX(This)))++;
|
||||
if (!zend_hash_add(EX(symbol_table), CG(known_strings)[ZEND_STR_THIS], &EX(This))) {
|
||||
GC_REFCOUNT(Z_OBJ(EX(This)))--;
|
||||
}
|
||||
}
|
||||
|
||||
zend_attach_symbol_table(execute_data);
|
||||
} else {
|
||||
uint32_t first_extra_arg, num_args;
|
||||
@ -2307,11 +2288,6 @@ static zend_always_inline void i_init_execute_data(zend_execute_data *execute_da
|
||||
var++;
|
||||
} while (var != end);
|
||||
}
|
||||
|
||||
if (op_array->this_var != (uint32_t)-1 && EXPECTED(Z_TYPE(EX(This)) == IS_OBJECT)) {
|
||||
ZVAL_OBJ(EX_VAR(op_array->this_var), Z_OBJ(EX(This)));
|
||||
GC_REFCOUNT(Z_OBJ(EX(This)))++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!op_array->run_time_cache) {
|
||||
|
@ -1141,7 +1141,6 @@ ZEND_API zend_function *zend_get_call_trampoline_func(zend_class_entry *ce, zend
|
||||
if (is_static) {
|
||||
func->fn_flags |= ZEND_ACC_STATIC;
|
||||
}
|
||||
func->this_var = -1;
|
||||
func->opcodes = &EG(call_trampoline_op);
|
||||
|
||||
func->prototype = fbc;
|
||||
|
@ -85,8 +85,6 @@ void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_siz
|
||||
op_array->static_variables = NULL;
|
||||
op_array->last_try_catch = 0;
|
||||
|
||||
op_array->this_var = -1;
|
||||
|
||||
op_array->fn_flags = 0;
|
||||
|
||||
op_array->early_binding = -1;
|
||||
|
@ -762,7 +762,7 @@ ZEND_VM_HELPER(zend_binary_assign_op_obj_helper, VAR|UNUSED|CV, CONST|TMPVAR|CV,
|
||||
ZEND_VM_NEXT_OPCODE_EX(1, 2);
|
||||
}
|
||||
|
||||
ZEND_VM_HELPER(zend_binary_assign_op_dim_helper, VAR|UNUSED|CV, CONST|TMPVAR|UNUSED|CV, binary_op_type binary_op)
|
||||
ZEND_VM_HELPER(zend_binary_assign_op_dim_helper, VAR|CV, CONST|TMPVAR|UNUSED|CV, binary_op_type binary_op)
|
||||
{
|
||||
USE_OPLINE
|
||||
zend_free_op free_op1, free_op2, free_op_data1;
|
||||
@ -771,14 +771,8 @@ ZEND_VM_HELPER(zend_binary_assign_op_dim_helper, VAR|UNUSED|CV, CONST|TMPVAR|UNU
|
||||
|
||||
SAVE_OPLINE();
|
||||
container = GET_OP1_OBJ_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW);
|
||||
if (OP1_TYPE == IS_UNUSED && UNEXPECTED(Z_TYPE_P(container) == IS_UNDEF)) {
|
||||
zend_throw_error(NULL, "Using $this when not in object context");
|
||||
FREE_UNFETCHED_OP((opline+1)->op1_type, (opline+1)->op1.var);
|
||||
FREE_UNFETCHED_OP2();
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
|
||||
if (OP1_TYPE != IS_UNUSED && EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
|
||||
if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
|
||||
ZEND_VM_C_LABEL(assign_dim_op_array):
|
||||
SEPARATE_ARRAY(container);
|
||||
ZEND_VM_C_LABEL(assign_dim_op_new_array):
|
||||
@ -811,27 +805,25 @@ ZEND_VM_C_LABEL(assign_dim_op_new_array):
|
||||
ZVAL_COPY(EX_VAR(opline->result.var), var_ptr);
|
||||
}
|
||||
} else {
|
||||
if (OP1_TYPE != IS_UNUSED) {
|
||||
if (EXPECTED(Z_ISREF_P(container))) {
|
||||
container = Z_REFVAL_P(container);
|
||||
if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
|
||||
ZEND_VM_C_GOTO(assign_dim_op_array);
|
||||
}
|
||||
} else if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(container) == IS_UNDEF)) {
|
||||
container = GET_OP1_UNDEF_CV(container, BP_VAR_RW);
|
||||
ZEND_VM_C_LABEL(assign_dim_op_convert_to_array):
|
||||
ZVAL_NEW_ARR(container);
|
||||
zend_hash_init(Z_ARRVAL_P(container), 8, NULL, ZVAL_PTR_DTOR, 0);
|
||||
ZEND_VM_C_GOTO(assign_dim_op_new_array);
|
||||
if (EXPECTED(Z_ISREF_P(container))) {
|
||||
container = Z_REFVAL_P(container);
|
||||
if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
|
||||
ZEND_VM_C_GOTO(assign_dim_op_array);
|
||||
}
|
||||
} else if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(container) == IS_UNDEF)) {
|
||||
container = GET_OP1_UNDEF_CV(container, BP_VAR_RW);
|
||||
ZEND_VM_C_LABEL(assign_dim_op_convert_to_array):
|
||||
ZVAL_NEW_ARR(container);
|
||||
zend_hash_init(Z_ARRVAL_P(container), 8, NULL, ZVAL_PTR_DTOR, 0);
|
||||
ZEND_VM_C_GOTO(assign_dim_op_new_array);
|
||||
}
|
||||
|
||||
dim = GET_OP2_ZVAL_PTR(BP_VAR_R);
|
||||
|
||||
if (OP1_TYPE == IS_UNUSED || EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) {
|
||||
if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) {
|
||||
value = get_zval_ptr_r((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1);
|
||||
zend_binary_assign_op_obj_dim(container, dim, value, UNEXPECTED(RETURN_VALUE_USED(opline)) ? EX_VAR(opline->result.var) : NULL, binary_op);
|
||||
} else if (OP1_TYPE != IS_UNUSED) {
|
||||
} else {
|
||||
if (UNEXPECTED(Z_TYPE_P(container) == IS_STRING)) {
|
||||
if (OP2_TYPE == IS_UNUSED) {
|
||||
zend_throw_error(NULL, "[] operator not supported for strings");
|
||||
@ -900,12 +892,11 @@ ZEND_VM_HANDLER(23, ZEND_ASSIGN_ADD, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEX
|
||||
if (EXPECTED(opline->extended_value == 0)) {
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_helper, binary_op, add_function);
|
||||
}
|
||||
# endif
|
||||
if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) {
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, add_function);
|
||||
} else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_OBJ)) */ {
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_obj_helper, binary_op, add_function);
|
||||
}
|
||||
# endif
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_obj_helper, binary_op, add_function);
|
||||
#else
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, add_function);
|
||||
#endif
|
||||
@ -920,12 +911,11 @@ ZEND_VM_HANDLER(24, ZEND_ASSIGN_SUB, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEX
|
||||
if (EXPECTED(opline->extended_value == 0)) {
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_helper, binary_op, sub_function);
|
||||
}
|
||||
# endif
|
||||
if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) {
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, sub_function);
|
||||
} else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_OBJ)) */ {
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_obj_helper, binary_op, sub_function);
|
||||
}
|
||||
# endif
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_obj_helper, binary_op, sub_function);
|
||||
#else
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, sub_function);
|
||||
#endif
|
||||
@ -940,12 +930,11 @@ ZEND_VM_HANDLER(25, ZEND_ASSIGN_MUL, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEX
|
||||
if (EXPECTED(opline->extended_value == 0)) {
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_helper, binary_op, mul_function);
|
||||
}
|
||||
# endif
|
||||
if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) {
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, mul_function);
|
||||
} else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_OBJ)) */ {
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_obj_helper, binary_op, mul_function);
|
||||
}
|
||||
# endif
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_obj_helper, binary_op, mul_function);
|
||||
#else
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, mul_function);
|
||||
#endif
|
||||
@ -960,12 +949,11 @@ ZEND_VM_HANDLER(26, ZEND_ASSIGN_DIV, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEX
|
||||
if (EXPECTED(opline->extended_value == 0)) {
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_helper, binary_op, div_function);
|
||||
}
|
||||
# endif
|
||||
if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) {
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, div_function);
|
||||
} else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_OBJ)) */ {
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_obj_helper, binary_op, div_function);
|
||||
}
|
||||
# endif
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_obj_helper, binary_op, div_function);
|
||||
#else
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, div_function);
|
||||
#endif
|
||||
@ -980,12 +968,11 @@ ZEND_VM_HANDLER(27, ZEND_ASSIGN_MOD, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEX
|
||||
if (EXPECTED(opline->extended_value == 0)) {
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_helper, binary_op, mod_function);
|
||||
}
|
||||
# endif
|
||||
if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) {
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, mod_function);
|
||||
} else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_OBJ)) */ {
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_obj_helper, binary_op, mod_function);
|
||||
}
|
||||
# endif
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_obj_helper, binary_op, mod_function);
|
||||
#else
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, mod_function);
|
||||
#endif
|
||||
@ -1000,12 +987,11 @@ ZEND_VM_HANDLER(28, ZEND_ASSIGN_SL, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEXT
|
||||
if (EXPECTED(opline->extended_value == 0)) {
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_helper, binary_op, shift_left_function);
|
||||
}
|
||||
# endif
|
||||
if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) {
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, shift_left_function);
|
||||
} else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_OBJ)) */ {
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_obj_helper, binary_op, shift_left_function);
|
||||
}
|
||||
# endif
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_obj_helper, binary_op, shift_left_function);
|
||||
#else
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, shift_left_function);
|
||||
#endif
|
||||
@ -1020,12 +1006,11 @@ ZEND_VM_HANDLER(29, ZEND_ASSIGN_SR, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NEXT
|
||||
if (EXPECTED(opline->extended_value == 0)) {
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_helper, binary_op, shift_right_function);
|
||||
}
|
||||
# endif
|
||||
if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) {
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, shift_right_function);
|
||||
} else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_OBJ)) */ {
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_obj_helper, binary_op, shift_right_function);
|
||||
}
|
||||
# endif
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_obj_helper, binary_op, shift_right_function);
|
||||
#else
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, shift_right_function);
|
||||
#endif
|
||||
@ -1040,12 +1025,11 @@ ZEND_VM_HANDLER(30, ZEND_ASSIGN_CONCAT, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|
|
||||
if (EXPECTED(opline->extended_value == 0)) {
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_helper, binary_op, concat_function);
|
||||
}
|
||||
# endif
|
||||
if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) {
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, concat_function);
|
||||
} else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_OBJ)) */ {
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_obj_helper, binary_op, concat_function);
|
||||
}
|
||||
# endif
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_obj_helper, binary_op, concat_function);
|
||||
#else
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, concat_function);
|
||||
#endif
|
||||
@ -1060,12 +1044,11 @@ ZEND_VM_HANDLER(31, ZEND_ASSIGN_BW_OR, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|N
|
||||
if (EXPECTED(opline->extended_value == 0)) {
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_helper, binary_op, bitwise_or_function);
|
||||
}
|
||||
# endif
|
||||
if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) {
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, bitwise_or_function);
|
||||
} else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_OBJ)) */ {
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_obj_helper, binary_op, bitwise_or_function);
|
||||
}
|
||||
# endif
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_obj_helper, binary_op, bitwise_or_function);
|
||||
#else
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, bitwise_or_function);
|
||||
#endif
|
||||
@ -1080,12 +1063,11 @@ ZEND_VM_HANDLER(32, ZEND_ASSIGN_BW_AND, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|
|
||||
if (EXPECTED(opline->extended_value == 0)) {
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_helper, binary_op, bitwise_and_function);
|
||||
}
|
||||
# endif
|
||||
if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) {
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, bitwise_and_function);
|
||||
} else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_OBJ)) */ {
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_obj_helper, binary_op, bitwise_and_function);
|
||||
}
|
||||
# endif
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_obj_helper, binary_op, bitwise_and_function);
|
||||
#else
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, bitwise_and_function);
|
||||
#endif
|
||||
@ -1100,12 +1082,11 @@ ZEND_VM_HANDLER(33, ZEND_ASSIGN_BW_XOR, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|
|
||||
if (EXPECTED(opline->extended_value == 0)) {
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_helper, binary_op, bitwise_xor_function);
|
||||
}
|
||||
# endif
|
||||
if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) {
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, bitwise_xor_function);
|
||||
} else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_OBJ)) */ {
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_obj_helper, binary_op, bitwise_xor_function);
|
||||
}
|
||||
# endif
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_obj_helper, binary_op, bitwise_xor_function);
|
||||
#else
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, bitwise_xor_function);
|
||||
#endif
|
||||
@ -1120,12 +1101,11 @@ ZEND_VM_HANDLER(167, ZEND_ASSIGN_POW, VAR|UNUSED|THIS|CV, CONST|TMPVAR|UNUSED|NE
|
||||
if (EXPECTED(opline->extended_value == 0)) {
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_helper, binary_op, pow_function);
|
||||
}
|
||||
# endif
|
||||
if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) {
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, pow_function);
|
||||
} else /* if (EXPECTED(opline->extended_value == ZEND_ASSIGN_OBJ)) */ {
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_obj_helper, binary_op, pow_function);
|
||||
}
|
||||
# endif
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_obj_helper, binary_op, pow_function);
|
||||
#else
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_binary_assign_op_dim_helper, binary_op, pow_function);
|
||||
#endif
|
||||
@ -1487,6 +1467,43 @@ ZEND_VM_HELPER(zend_fetch_var_address_helper, CONST|TMPVAR|CV, UNUSED, int type)
|
||||
target_symbol_table = zend_get_target_symbol_table(execute_data, opline->extended_value & ZEND_FETCH_TYPE_MASK);
|
||||
retval = zend_hash_find(target_symbol_table, name);
|
||||
if (retval == NULL) {
|
||||
if (UNEXPECTED(zend_string_equals(name, CG(known_strings)[ZEND_STR_THIS]))) {
|
||||
zval *result;
|
||||
|
||||
ZEND_VM_C_LABEL(fetch_this):
|
||||
result = EX_VAR(opline->result.var);
|
||||
switch (type) {
|
||||
case BP_VAR_R:
|
||||
if (EXPECTED(Z_TYPE(EX(This)) == IS_OBJECT)) {
|
||||
ZVAL_OBJ(result, Z_OBJ(EX(This)));
|
||||
Z_ADDREF_P(result);
|
||||
} else {
|
||||
ZVAL_NULL(result);
|
||||
zend_error(E_NOTICE,"Undefined variable: this");
|
||||
}
|
||||
break;
|
||||
case BP_VAR_IS:
|
||||
if (EXPECTED(Z_TYPE(EX(This)) == IS_OBJECT)) {
|
||||
ZVAL_OBJ(result, Z_OBJ(EX(This)));
|
||||
Z_ADDREF_P(result);
|
||||
} else {
|
||||
ZVAL_NULL(result);
|
||||
}
|
||||
break;
|
||||
case BP_VAR_RW:
|
||||
case BP_VAR_W:
|
||||
zend_throw_error(NULL, "Cannot re-assign $this");
|
||||
break;
|
||||
case BP_VAR_UNSET:
|
||||
zend_throw_error(NULL, "Cannot unset $this");
|
||||
break;
|
||||
EMPTY_SWITCH_DEFAULT_CASE()
|
||||
}
|
||||
if (OP1_TYPE != IS_CONST) {
|
||||
zend_string_release(name);
|
||||
}
|
||||
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
|
||||
}
|
||||
switch (type) {
|
||||
case BP_VAR_R:
|
||||
case BP_VAR_UNSET:
|
||||
@ -1508,6 +1525,9 @@ ZEND_VM_HELPER(zend_fetch_var_address_helper, CONST|TMPVAR|CV, UNUSED, int type)
|
||||
} else if (Z_TYPE_P(retval) == IS_INDIRECT) {
|
||||
retval = Z_INDIRECT_P(retval);
|
||||
if (Z_TYPE_P(retval) == IS_UNDEF) {
|
||||
if (UNEXPECTED(zend_string_equals(name, CG(known_strings)[ZEND_STR_THIS]))) {
|
||||
ZEND_VM_C_GOTO(fetch_this);
|
||||
}
|
||||
switch (type) {
|
||||
case BP_VAR_R:
|
||||
case BP_VAR_UNSET:
|
||||
@ -3596,7 +3616,7 @@ ZEND_VM_HANDLER(130, ZEND_DO_UCALL, ANY, ANY, SPEC(RETVAL))
|
||||
}
|
||||
|
||||
call->prev_execute_data = execute_data;
|
||||
i_init_func_execute_data(call, &fbc->op_array, ret, 0);
|
||||
i_init_func_execute_data(call, &fbc->op_array, ret);
|
||||
|
||||
ZEND_VM_ENTER();
|
||||
}
|
||||
@ -3619,7 +3639,7 @@ ZEND_VM_HANDLER(131, ZEND_DO_FCALL_BY_NAME, ANY, ANY, SPEC(RETVAL))
|
||||
}
|
||||
|
||||
call->prev_execute_data = execute_data;
|
||||
i_init_func_execute_data(call, &fbc->op_array, ret, 0);
|
||||
i_init_func_execute_data(call, &fbc->op_array, ret);
|
||||
|
||||
ZEND_VM_ENTER();
|
||||
} else {
|
||||
@ -3716,7 +3736,7 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY, SPEC(RETVAL))
|
||||
}
|
||||
|
||||
call->prev_execute_data = execute_data;
|
||||
i_init_func_execute_data(call, &fbc->op_array, ret, 1);
|
||||
i_init_func_execute_data(call, &fbc->op_array, ret);
|
||||
|
||||
if (EXPECTED(zend_execute_ex == execute_ex)) {
|
||||
ZEND_VM_ENTER();
|
||||
@ -5547,7 +5567,7 @@ ZEND_VM_HANDLER(179, ZEND_UNSET_STATIC_PROP, CONST|TMPVAR|CV, UNUSED|CLASS_FETCH
|
||||
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
|
||||
}
|
||||
|
||||
ZEND_VM_HANDLER(75, ZEND_UNSET_DIM, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV)
|
||||
ZEND_VM_HANDLER(75, ZEND_UNSET_DIM, VAR|CV, CONST|TMPVAR|CV)
|
||||
{
|
||||
USE_OPLINE
|
||||
zend_free_op free_op1, free_op2;
|
||||
@ -5558,15 +5578,10 @@ ZEND_VM_HANDLER(75, ZEND_UNSET_DIM, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV)
|
||||
|
||||
SAVE_OPLINE();
|
||||
container = GET_OP1_OBJ_ZVAL_PTR_PTR_UNDEF(BP_VAR_UNSET);
|
||||
if (OP1_TYPE == IS_UNUSED && UNEXPECTED(Z_TYPE_P(container) == IS_UNDEF)) {
|
||||
zend_throw_error(NULL, "Using $this when not in object context");
|
||||
FREE_UNFETCHED_OP2();
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
offset = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
|
||||
|
||||
do {
|
||||
if (OP1_TYPE != IS_UNUSED && EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
|
||||
if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
|
||||
HashTable *ht;
|
||||
|
||||
ZEND_VM_C_LABEL(unset_dim_array):
|
||||
@ -5616,7 +5631,7 @@ ZEND_VM_C_LABEL(num_index_dim):
|
||||
zend_error(E_WARNING, "Illegal offset type in unset");
|
||||
}
|
||||
break;
|
||||
} else if (OP1_TYPE != IS_UNUSED && Z_ISREF_P(container)) {
|
||||
} else if (Z_ISREF_P(container)) {
|
||||
container = Z_REFVAL_P(container);
|
||||
if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
|
||||
ZEND_VM_C_GOTO(unset_dim_array);
|
||||
@ -5628,7 +5643,7 @@ ZEND_VM_C_LABEL(num_index_dim):
|
||||
if (OP2_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(offset) == IS_UNDEF)) {
|
||||
offset = GET_OP2_UNDEF_CV(offset, BP_VAR_R);
|
||||
}
|
||||
if (OP1_TYPE == IS_UNUSED || EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) {
|
||||
if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) {
|
||||
if (UNEXPECTED(Z_OBJ_HT_P(container)->unset_dimension == NULL)) {
|
||||
zend_throw_error(NULL, "Cannot use object as array");
|
||||
} else {
|
||||
@ -6479,7 +6494,7 @@ ZEND_VM_C_LABEL(is_static_prop_return):
|
||||
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
|
||||
}
|
||||
|
||||
ZEND_VM_HANDLER(115, ZEND_ISSET_ISEMPTY_DIM_OBJ, CONST|TMPVAR|UNUSED|THIS|CV, CONST|TMPVAR|CV, ISSET)
|
||||
ZEND_VM_HANDLER(115, ZEND_ISSET_ISEMPTY_DIM_OBJ, CONST|TMPVAR|CV, CONST|TMPVAR|CV, ISSET)
|
||||
{
|
||||
USE_OPLINE
|
||||
zend_free_op free_op1, free_op2;
|
||||
@ -6490,16 +6505,9 @@ ZEND_VM_HANDLER(115, ZEND_ISSET_ISEMPTY_DIM_OBJ, CONST|TMPVAR|UNUSED|THIS|CV, CO
|
||||
|
||||
SAVE_OPLINE();
|
||||
container = GET_OP1_OBJ_ZVAL_PTR_UNDEF(BP_VAR_IS);
|
||||
|
||||
if (OP1_TYPE == IS_UNUSED && UNEXPECTED(Z_TYPE_P(container) == IS_UNDEF)) {
|
||||
zend_throw_error(NULL, "Using $this when not in object context");
|
||||
FREE_UNFETCHED_OP2();
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
|
||||
offset = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
|
||||
|
||||
if (OP1_TYPE != IS_UNUSED && EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
|
||||
if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
|
||||
HashTable *ht;
|
||||
zval *value;
|
||||
zend_string *str;
|
||||
@ -6566,8 +6574,7 @@ ZEND_VM_C_LABEL(num_index_prop):
|
||||
offset = GET_OP2_UNDEF_CV(offset, BP_VAR_R);
|
||||
}
|
||||
|
||||
if (OP1_TYPE == IS_UNUSED ||
|
||||
(OP1_TYPE != IS_CONST && EXPECTED(Z_TYPE_P(container) == IS_OBJECT))) {
|
||||
if ((OP1_TYPE != IS_CONST && EXPECTED(Z_TYPE_P(container) == IS_OBJECT))) {
|
||||
if (EXPECTED(Z_OBJ_HT_P(container)->has_dimension)) {
|
||||
result =
|
||||
((opline->extended_value & ZEND_ISSET) == 0) ^
|
||||
@ -7910,8 +7917,7 @@ ZEND_VM_HANDLER(158, ZEND_CALL_TRAMPOLINE, ANY, ANY)
|
||||
if (UNEXPECTED(!fbc->op_array.run_time_cache)) {
|
||||
init_func_run_time_cache(&fbc->op_array);
|
||||
}
|
||||
i_init_func_execute_data(call, &fbc->op_array,
|
||||
ret, (fbc->common.fn_flags & ZEND_ACC_STATIC) == 0);
|
||||
i_init_func_execute_data(call, &fbc->op_array, ret);
|
||||
if (EXPECTED(zend_execute_ex == execute_ex)) {
|
||||
ZEND_VM_ENTER();
|
||||
} else {
|
||||
@ -8071,6 +8077,34 @@ ZEND_VM_HANDLER(183, ZEND_BIND_STATIC, CV, CONST, REF)
|
||||
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
|
||||
}
|
||||
|
||||
ZEND_VM_HANDLER(184, ZEND_FETCH_THIS, UNUSED, UNUSED)
|
||||
{
|
||||
USE_OPLINE
|
||||
|
||||
if (EXPECTED(Z_TYPE(EX(This)) == IS_OBJECT)) {
|
||||
zval *result = EX_VAR(opline->result.var);
|
||||
|
||||
ZVAL_OBJ(result, Z_OBJ(EX(This)));
|
||||
Z_ADDREF_P(result);
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
} else {
|
||||
SAVE_OPLINE();
|
||||
zend_throw_error(NULL, "Using $this when not in object context");
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
}
|
||||
|
||||
ZEND_VM_HANDLER(186, ZEND_ISSET_ISEMPTY_THIS, UNUSED, UNUSED)
|
||||
{
|
||||
USE_OPLINE
|
||||
|
||||
ZVAL_BOOL(EX_VAR(opline->result.var),
|
||||
(opline->extended_value & ZEND_ISSET) ?
|
||||
(Z_TYPE(EX(This)) == IS_OBJECT) :
|
||||
(Z_TYPE(EX(This)) != IS_OBJECT));
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
}
|
||||
|
||||
ZEND_VM_TYPE_SPEC_HANDLER(ZEND_ADD, (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG), ZEND_ADD_LONG_NO_OVERFLOW, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(NO_CONST_CONST,COMMUTATIVE))
|
||||
{
|
||||
USE_OPLINE
|
||||
@ -8550,10 +8584,10 @@ ZEND_VM_TYPE_SPEC_HANDLER(ZEND_SEND_VAR_EX, (op1_info & (MAY_BE_UNDEF|MAY_BE_REF
|
||||
|
||||
if (EXPECTED(arg_num <= MAX_ARG_FLAG_NUM)) {
|
||||
if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
|
||||
ZEND_VM_C_GOTO(send_var_by_ref);
|
||||
ZEND_VM_C_GOTO(send_var_by_ref_simple);
|
||||
}
|
||||
} else if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
|
||||
ZEND_VM_C_LABEL(send_var_by_ref):
|
||||
ZEND_VM_C_LABEL(send_var_by_ref_simple):
|
||||
ZEND_VM_DISPATCH_TO_HANDLER(ZEND_SEND_REF);
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -949,7 +949,7 @@ function gen_handler($f, $spec, $kind, $name, $op1, $op2, $use, $code, $lineno,
|
||||
if ($spec &&
|
||||
isset($extra_spec["DIM_OBJ"]) &&
|
||||
(($op2 == "UNUSED" && $extra_spec["DIM_OBJ"] != 1) ||
|
||||
($op1 == "UNUSED" && $extra_spec["DIM_OBJ"] == 0))) {
|
||||
($op1 == "UNUSED" && $extra_spec["DIM_OBJ"] != 2))) {
|
||||
// Skip useless handlers
|
||||
return;
|
||||
}
|
||||
@ -1184,7 +1184,7 @@ function gen_labels($f, $spec, $kind, $prolog, &$specs, $switch_labels = array()
|
||||
return;
|
||||
} else if (isset($extra_spec["DIM_OBJ"]) &&
|
||||
(($op2 == "UNUSED" && $extra_spec["DIM_OBJ"] != 1) ||
|
||||
($op1 == "UNUSED" && $extra_spec["DIM_OBJ"] == 0))) {
|
||||
($op1 == "UNUSED" && $extra_spec["DIM_OBJ"] != 2))) {
|
||||
// Skip useless handlers
|
||||
gen_null_label($f, $kind, $prolog);
|
||||
$label++;
|
||||
|
@ -21,7 +21,7 @@
|
||||
#include <stdio.h>
|
||||
#include <zend.h>
|
||||
|
||||
static const char *zend_vm_opcodes_names[184] = {
|
||||
static const char *zend_vm_opcodes_names[187] = {
|
||||
"ZEND_NOP",
|
||||
"ZEND_ADD",
|
||||
"ZEND_SUB",
|
||||
@ -206,9 +206,12 @@ static const char *zend_vm_opcodes_names[184] = {
|
||||
"ZEND_FETCH_CLASS_CONSTANT",
|
||||
"ZEND_BIND_LEXICAL",
|
||||
"ZEND_BIND_STATIC",
|
||||
"ZEND_FETCH_THIS",
|
||||
NULL,
|
||||
"ZEND_ISSET_ISEMPTY_THIS",
|
||||
};
|
||||
|
||||
static uint32_t zend_vm_opcodes_flags[184] = {
|
||||
static uint32_t zend_vm_opcodes_flags[187] = {
|
||||
0x00000000,
|
||||
0x00000707,
|
||||
0x00000707,
|
||||
@ -284,7 +287,7 @@ static uint32_t zend_vm_opcodes_flags[184] = {
|
||||
0x00106703,
|
||||
0x08000007,
|
||||
0x00030107,
|
||||
0x00000751,
|
||||
0x00000701,
|
||||
0x00000751,
|
||||
0x00002003,
|
||||
0x03000001,
|
||||
@ -324,7 +327,7 @@ static uint32_t zend_vm_opcodes_flags[184] = {
|
||||
0x01000757,
|
||||
0x01008773,
|
||||
0x00030107,
|
||||
0x00020757,
|
||||
0x00020707,
|
||||
0x00001003,
|
||||
0x00001001,
|
||||
0x01000703,
|
||||
@ -393,6 +396,9 @@ static uint32_t zend_vm_opcodes_flags[184] = {
|
||||
0x00000373,
|
||||
0x00100101,
|
||||
0x00100301,
|
||||
0x00000101,
|
||||
0x00000000,
|
||||
0x00000101,
|
||||
};
|
||||
|
||||
ZEND_API const char* zend_get_opcode_name(zend_uchar opcode) {
|
||||
|
@ -248,7 +248,9 @@ END_EXTERN_C()
|
||||
#define ZEND_FETCH_CLASS_CONSTANT 181
|
||||
#define ZEND_BIND_LEXICAL 182
|
||||
#define ZEND_BIND_STATIC 183
|
||||
#define ZEND_FETCH_THIS 184
|
||||
#define ZEND_ISSET_ISEMPTY_THIS 186
|
||||
|
||||
#define ZEND_VM_LAST_OPCODE 183
|
||||
#define ZEND_VM_LAST_OPCODE 186
|
||||
|
||||
#endif
|
||||
|
@ -72,9 +72,9 @@ typedef struct _literal_info {
|
||||
info[n].u.num = (_num); \
|
||||
} while (0)
|
||||
|
||||
#define LITERAL_INFO_OBJ(n, kind, merge, slots, related, _num) do { \
|
||||
#define LITERAL_INFO_OBJ(n, kind, merge, slots, related) do { \
|
||||
info[n].flags = (LITERAL_EX_OBJ | ((merge) ? LITERAL_MAY_MERGE : 0) | LITERAL_FLAGS(kind, slots, related)); \
|
||||
info[n].u.num = (_num); \
|
||||
info[n].u.num = (uint32_t)-1; \
|
||||
} while (0)
|
||||
|
||||
static void optimizer_literal_obj_info(literal_info *info,
|
||||
@ -92,7 +92,7 @@ static void optimizer_literal_obj_info(literal_info *info,
|
||||
*/
|
||||
if (Z_TYPE(op_array->literals[constant]) == IS_STRING &&
|
||||
op_type == IS_UNUSED) {
|
||||
LITERAL_INFO_OBJ(constant, kind, 1, slots, related, op_array->this_var);
|
||||
LITERAL_INFO_OBJ(constant, kind, 1, slots, related);
|
||||
} else {
|
||||
LITERAL_INFO(constant, kind, 0, slots, related);
|
||||
}
|
||||
@ -421,9 +421,11 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
|
||||
case IS_CONSTANT:
|
||||
if (info[i].flags & LITERAL_MAY_MERGE) {
|
||||
if (info[i].flags & LITERAL_EX_OBJ) {
|
||||
int key_len = MAX_LENGTH_OF_LONG + sizeof("->") - 1 + Z_STRLEN(op_array->literals[i]);
|
||||
int key_len = sizeof("$this->") - 1 + Z_STRLEN(op_array->literals[i]);
|
||||
key = zend_string_alloc(key_len, 0);
|
||||
ZSTR_LEN(key) = snprintf(ZSTR_VAL(key), ZSTR_LEN(key)-1, "%d->%s", info[i].u.num, Z_STRVAL(op_array->literals[i]));
|
||||
memcpy(ZSTR_VAL(key), "$this->", sizeof("$this->") - 1);
|
||||
memcpy(ZSTR_VAL(key) + sizeof("$this->") - 1, Z_STRVAL(op_array->literals[i]), Z_STRLEN(op_array->literals[i]) + 1);
|
||||
ZSTR_LEN(key) = key_len;
|
||||
} else if (info[i].flags & LITERAL_EX_CLASS) {
|
||||
int key_len;
|
||||
zval *class_name = &op_array->literals[(info[i].u.num < i) ? map[info[i].u.num] : info[i].u.num];
|
||||
|
@ -603,7 +603,6 @@ int zend_inference_calc_range(const zend_op_array *op_array, zend_ssa *ssa, int
|
||||
return (tmp->min <= tmp->max);
|
||||
} else if (ssa->vars[var].definition < 0) {
|
||||
if (var < op_array->last_var &&
|
||||
var != EX_VAR_TO_NUM(op_array->this_var) &&
|
||||
op_array->function_name) {
|
||||
|
||||
tmp->min = 0;
|
||||
@ -3246,6 +3245,10 @@ static void zend_update_type_info(const zend_op_array *op_array,
|
||||
}
|
||||
UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def);
|
||||
break;
|
||||
case ZEND_FETCH_THIS:
|
||||
UPDATE_SSA_OBJ_TYPE(op_array->scope, 1, ssa_ops[i].result_def);
|
||||
UPDATE_SSA_TYPE(MAY_BE_RC1|MAY_BE_RCN|MAY_BE_OBJECT, ssa_ops[i].result_def);
|
||||
break;
|
||||
case ZEND_FETCH_OBJ_R:
|
||||
case ZEND_FETCH_OBJ_IS:
|
||||
case ZEND_FETCH_OBJ_RW:
|
||||
@ -4009,13 +4012,7 @@ int zend_ssa_inference(zend_arena **arena, const zend_op_array *op_array, const
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < op_array->last_var; i++) {
|
||||
if (i == EX_VAR_TO_NUM(op_array->this_var)) {
|
||||
ssa_var_info[i].type = MAY_BE_UNDEF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_OBJECT;
|
||||
ssa_var_info[i].ce = op_array->scope;
|
||||
ssa_var_info[i].is_instanceof = 1;
|
||||
} else {
|
||||
ssa_var_info[i].type = MAY_BE_UNDEF | MAY_BE_RCN;
|
||||
}
|
||||
ssa_var_info[i].type = MAY_BE_UNDEF | MAY_BE_RCN;
|
||||
ssa_var_info[i].has_range = 0;
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,11 @@ class TestClass {
|
||||
|
||||
public static function staticMethod() {
|
||||
echo "Called staticMethod()\n";
|
||||
var_dump($this);
|
||||
try {
|
||||
var_dump($this);
|
||||
} catch (Throwable $e) {
|
||||
echo "Exception: " . $e->getMessage() . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
private static function privateMethod() {
|
||||
@ -103,9 +107,7 @@ NULL
|
||||
Warning: ReflectionMethod::invokeArgs() expects parameter 1 to be object, boolean given in %s on line %d
|
||||
NULL
|
||||
Called staticMethod()
|
||||
|
||||
Notice: Undefined variable: this in %s on line %d
|
||||
NULL
|
||||
Exception: Using $this when not in object context
|
||||
NULL
|
||||
|
||||
Private method:
|
||||
|
@ -22,7 +22,11 @@ class TestClass {
|
||||
|
||||
public static function staticMethod() {
|
||||
echo "Called staticMethod()\n";
|
||||
var_dump($this);
|
||||
try {
|
||||
var_dump($this);
|
||||
} catch (Throwable $e) {
|
||||
echo "Exception: " . $e->getMessage() . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
private static function privateMethod() {
|
||||
@ -94,14 +98,10 @@ Static method:
|
||||
Warning: ReflectionMethod::invoke() expects at least 1 parameter, 0 given in %s on line %d
|
||||
NULL
|
||||
Called staticMethod()
|
||||
|
||||
Notice: Undefined variable: this in %s on line %d
|
||||
NULL
|
||||
Exception: Using $this when not in object context
|
||||
NULL
|
||||
Called staticMethod()
|
||||
|
||||
Notice: Undefined variable: this in %s on line %d
|
||||
NULL
|
||||
Exception: Using $this when not in object context
|
||||
NULL
|
||||
|
||||
Method that throws an exception:
|
||||
|
@ -1764,6 +1764,7 @@ PHP_FUNCTION(extract)
|
||||
zend_ulong num_key;
|
||||
int var_exists, count = 0;
|
||||
int extract_refs = 0;
|
||||
int exception_thrown = 0;
|
||||
zend_array *symbol_table;
|
||||
zval var_array;
|
||||
|
||||
@ -1846,12 +1847,6 @@ PHP_FUNCTION(extract)
|
||||
if (var_exists && ZSTR_LEN(var_name) == sizeof("GLOBALS")-1 && !strcmp(ZSTR_VAL(var_name), "GLOBALS")) {
|
||||
break;
|
||||
}
|
||||
if (var_exists && ZSTR_LEN(var_name) == sizeof("this")-1 && !strcmp(ZSTR_VAL(var_name), "this")) {
|
||||
zend_class_entry *scope = zend_get_executed_scope();
|
||||
if (scope && ZSTR_LEN(scope->name) != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
ZVAL_STR_COPY(&final_name, var_name);
|
||||
break;
|
||||
|
||||
@ -1892,6 +1887,15 @@ PHP_FUNCTION(extract)
|
||||
|
||||
if (Z_TYPE(final_name) == IS_STRING && php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) {
|
||||
zval *orig_var;
|
||||
|
||||
if (Z_STRLEN(final_name) == sizeof("this")-1 && !strcmp(Z_STRVAL(final_name), "this")) {
|
||||
if (!exception_thrown) {
|
||||
exception_thrown = 1;
|
||||
zend_throw_error(NULL, "Cannot re-assign $this");
|
||||
}
|
||||
zval_dtor(&final_name);
|
||||
continue;
|
||||
}
|
||||
if (extract_refs) {
|
||||
|
||||
ZVAL_MAKE_REF(entry);
|
||||
|
@ -4614,6 +4614,9 @@ PHP_FUNCTION(parse_str)
|
||||
symbol_table = zend_rebuild_symbol_table();
|
||||
ZVAL_ARR(&tmp, symbol_table);
|
||||
sapi_module.treat_data(PARSE_STRING, res, &tmp);
|
||||
if (UNEXPECTED(zend_hash_del(symbol_table, CG(known_strings)[ZEND_STR_THIS]) == SUCCESS)) {
|
||||
zend_throw_error(NULL, "Cannot re-assign $this");
|
||||
}
|
||||
} else {
|
||||
zval ret;
|
||||
|
||||
|
@ -109,6 +109,25 @@ PHPAPI void php_register_variable_ex(char *var_name, zval *val, zval *track_vars
|
||||
return;
|
||||
}
|
||||
|
||||
if (var_len == sizeof("this")-1 && EG(current_execute_data)) {
|
||||
zend_execute_data *ex = EG(current_execute_data);
|
||||
|
||||
while (ex) {
|
||||
if (ex->func && ZEND_USER_CODE(ex->func->common.type)) {
|
||||
if (ex->symbol_table == symtable1) {
|
||||
if (memcmp(var, "this", sizeof("this")-1) == 0) {
|
||||
zend_throw_error(NULL, "Cannot re-assign $this");
|
||||
zval_dtor(val);
|
||||
free_alloca(var_orig, use_heap);
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
ex = ex->prev_execute_data;
|
||||
}
|
||||
}
|
||||
|
||||
/* GLOBALS hijack attempt, reject parameter */
|
||||
if (symtable1 == &EG(symbol_table) &&
|
||||
var_len == sizeof("GLOBALS")-1 &&
|
||||
|
@ -54,21 +54,25 @@ try {
|
||||
--EXPECTF--
|
||||
Warning: The magic method __call() must have public visibility and cannot be static in %s on line 3
|
||||
---> Invoke __call via simple method call.
|
||||
NULL
|
||||
object(A)#1 (0) {
|
||||
}
|
||||
Exception caught OK; continuing.
|
||||
|
||||
|
||||
---> Invoke __call via scope resolution operator within instance.
|
||||
NULL
|
||||
object(A)#1 (0) {
|
||||
}
|
||||
Exception caught OK; continuing.
|
||||
|
||||
|
||||
---> Invoke __call via scope resolution operator within child instance.
|
||||
NULL
|
||||
object(B)#2 (0) {
|
||||
}
|
||||
Exception caught OK; continuing.
|
||||
|
||||
|
||||
---> Invoke __call via callback.
|
||||
NULL
|
||||
object(B)#2 (0) {
|
||||
}
|
||||
Exception caught OK; continuing.
|
||||
==DONE==
|
||||
|
@ -28,12 +28,4 @@ TestClass::Test2(new stdClass);
|
||||
?>
|
||||
===DONE===
|
||||
--EXPECTF--
|
||||
|
||||
Notice: Undefined variable: this in %sstatic_this.php on line %d
|
||||
NULL
|
||||
|
||||
Notice: Undefined variable: this in %sstatic_this.php on line %d
|
||||
NULL
|
||||
object(stdClass)#%d (0) {
|
||||
}
|
||||
===DONE===
|
||||
Fatal error: Cannot use $this as parameter in %sstatic_this.php on line 16
|
||||
|
Loading…
Reference in New Issue
Block a user