mirror of
https://github.com/php/php-src.git
synced 2024-11-23 18:04:36 +08:00
Merge branch 'PHP-5.6'
This commit is contained in:
commit
4facc35413
114
Zend/tests/arg_unpack/basic.phpt
Normal file
114
Zend/tests/arg_unpack/basic.phpt
Normal file
@ -0,0 +1,114 @@
|
||||
--TEST--
|
||||
Basic argument unpacking
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
function test(...$args) {
|
||||
var_dump($args);
|
||||
}
|
||||
|
||||
function test2($arg1, $arg2, $arg3 = null) {
|
||||
var_dump($arg1, $arg2, $arg3);
|
||||
}
|
||||
|
||||
function getArray($array) {
|
||||
return $array;
|
||||
}
|
||||
|
||||
function arrayGen($array) {
|
||||
foreach ($array as $element) {
|
||||
yield $element;
|
||||
}
|
||||
}
|
||||
|
||||
$array = [1, 2, 3];
|
||||
|
||||
test(...[]);
|
||||
test(...[1, 2, 3]);
|
||||
test(...$array);
|
||||
test(...getArray([1, 2, 3]));
|
||||
test(...arrayGen([]));
|
||||
test(...arrayGen([1, 2, 3]));
|
||||
|
||||
test(1, ...[2, 3], ...[4, 5], 6);
|
||||
test(1, ...getArray([2, 3]), ...arrayGen([4, 5]), 6);
|
||||
|
||||
test2(...[1, 2]);
|
||||
test2(...[1, 2, 3]);
|
||||
test2(...[1], ...[], ...[], ...[2, 3], 4, ...[5, 6]);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
array(0) {
|
||||
}
|
||||
array(3) {
|
||||
[0]=>
|
||||
int(1)
|
||||
[1]=>
|
||||
int(2)
|
||||
[2]=>
|
||||
int(3)
|
||||
}
|
||||
array(3) {
|
||||
[0]=>
|
||||
int(1)
|
||||
[1]=>
|
||||
int(2)
|
||||
[2]=>
|
||||
int(3)
|
||||
}
|
||||
array(3) {
|
||||
[0]=>
|
||||
int(1)
|
||||
[1]=>
|
||||
int(2)
|
||||
[2]=>
|
||||
int(3)
|
||||
}
|
||||
array(0) {
|
||||
}
|
||||
array(3) {
|
||||
[0]=>
|
||||
int(1)
|
||||
[1]=>
|
||||
int(2)
|
||||
[2]=>
|
||||
int(3)
|
||||
}
|
||||
array(6) {
|
||||
[0]=>
|
||||
int(1)
|
||||
[1]=>
|
||||
int(2)
|
||||
[2]=>
|
||||
int(3)
|
||||
[3]=>
|
||||
int(4)
|
||||
[4]=>
|
||||
int(5)
|
||||
[5]=>
|
||||
int(6)
|
||||
}
|
||||
array(6) {
|
||||
[0]=>
|
||||
int(1)
|
||||
[1]=>
|
||||
int(2)
|
||||
[2]=>
|
||||
int(3)
|
||||
[3]=>
|
||||
int(4)
|
||||
[4]=>
|
||||
int(5)
|
||||
[5]=>
|
||||
int(6)
|
||||
}
|
||||
int(1)
|
||||
int(2)
|
||||
NULL
|
||||
int(1)
|
||||
int(2)
|
||||
int(3)
|
||||
int(1)
|
||||
int(2)
|
||||
int(3)
|
149
Zend/tests/arg_unpack/by_ref.phpt
Normal file
149
Zend/tests/arg_unpack/by_ref.phpt
Normal file
@ -0,0 +1,149 @@
|
||||
--TEST--
|
||||
Argument unpacking with by-ref arguments
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
error_reporting(E_ALL);
|
||||
|
||||
function test1(&...$args) {
|
||||
foreach ($args as &$arg) {
|
||||
$arg++;
|
||||
}
|
||||
}
|
||||
|
||||
test1(...[1, 2, 3]);
|
||||
|
||||
$array = [1, 2, 3];
|
||||
test1(...$array);
|
||||
var_dump($array);
|
||||
|
||||
$array1 = [1, 2]; $val2 = 3; $array2 = [4, 5];
|
||||
test1(...$array1, $val2, ...$array2);
|
||||
var_dump($array1, $val2, $array2);
|
||||
|
||||
function test2($val1, &$ref1, $val2, &$ref2) {
|
||||
$ref1++;
|
||||
$ref2++;
|
||||
}
|
||||
|
||||
$array = [1, 2, 3, 4];
|
||||
test2(...$array);
|
||||
var_dump($array);
|
||||
|
||||
$a = $b = $c = $d = 0;
|
||||
|
||||
$array = [];
|
||||
test2(...$array, $a, $b, $c, $d);
|
||||
var_dump($array, $a, $b, $c, $d);
|
||||
|
||||
$array = [1];
|
||||
test2(...$array, $a, $b, $c, $d);
|
||||
var_dump($array, $a, $b, $c, $d);
|
||||
|
||||
$array = [1, 2];
|
||||
test2(...$array, $a, $b, $c, $d);
|
||||
var_dump($array, $a, $b, $c, $d);
|
||||
|
||||
$array = [1, 2, 3];
|
||||
test2(...$array, $a, $b, $c, $d);
|
||||
var_dump($array, $a, $b, $c, $d);
|
||||
|
||||
$vars = [];
|
||||
$array = [];
|
||||
test2(...$array, $vars['a'], $vars['b'], $vars['c'], $vars['d']);
|
||||
var_dump($vars);
|
||||
|
||||
$vars = [];
|
||||
$array = [1];
|
||||
test2(...$array, $vars['a'], $vars['b'], $vars['c'], $vars['d']);
|
||||
var_dump($vars);
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
array(3) {
|
||||
[0]=>
|
||||
int(2)
|
||||
[1]=>
|
||||
int(3)
|
||||
[2]=>
|
||||
int(4)
|
||||
}
|
||||
array(2) {
|
||||
[0]=>
|
||||
int(2)
|
||||
[1]=>
|
||||
int(3)
|
||||
}
|
||||
int(4)
|
||||
array(2) {
|
||||
[0]=>
|
||||
int(5)
|
||||
[1]=>
|
||||
int(6)
|
||||
}
|
||||
array(4) {
|
||||
[0]=>
|
||||
int(1)
|
||||
[1]=>
|
||||
int(3)
|
||||
[2]=>
|
||||
int(3)
|
||||
[3]=>
|
||||
int(5)
|
||||
}
|
||||
array(0) {
|
||||
}
|
||||
int(0)
|
||||
int(1)
|
||||
int(0)
|
||||
int(1)
|
||||
array(1) {
|
||||
[0]=>
|
||||
int(1)
|
||||
}
|
||||
int(1)
|
||||
int(1)
|
||||
int(1)
|
||||
int(1)
|
||||
array(2) {
|
||||
[0]=>
|
||||
int(1)
|
||||
[1]=>
|
||||
int(3)
|
||||
}
|
||||
int(1)
|
||||
int(2)
|
||||
int(1)
|
||||
int(1)
|
||||
array(3) {
|
||||
[0]=>
|
||||
int(1)
|
||||
[1]=>
|
||||
int(3)
|
||||
[2]=>
|
||||
int(3)
|
||||
}
|
||||
int(2)
|
||||
int(2)
|
||||
int(1)
|
||||
int(1)
|
||||
|
||||
Notice: Undefined index: a in %s on line %d
|
||||
|
||||
Notice: Undefined index: c in %s on line %d
|
||||
array(2) {
|
||||
["b"]=>
|
||||
int(1)
|
||||
["d"]=>
|
||||
int(1)
|
||||
}
|
||||
|
||||
Notice: Undefined index: b in %s on line %d
|
||||
|
||||
Notice: Undefined index: d in %s on line %d
|
||||
array(2) {
|
||||
["a"]=>
|
||||
int(1)
|
||||
["c"]=>
|
||||
int(1)
|
||||
}
|
37
Zend/tests/arg_unpack/dynamic.phpt
Normal file
37
Zend/tests/arg_unpack/dynamic.phpt
Normal file
@ -0,0 +1,37 @@
|
||||
--TEST--
|
||||
Unpack arguments for dynamic call
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$fn = function(...$args) {
|
||||
var_dump($args);
|
||||
};
|
||||
|
||||
$fn(...[]);
|
||||
$fn(...[1, 2, 3]);
|
||||
$fn(1, ...[2, 3], ...[], 4, 5);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
array(0) {
|
||||
}
|
||||
array(3) {
|
||||
[0]=>
|
||||
int(1)
|
||||
[1]=>
|
||||
int(2)
|
||||
[2]=>
|
||||
int(3)
|
||||
}
|
||||
array(5) {
|
||||
[0]=>
|
||||
int(1)
|
||||
[1]=>
|
||||
int(2)
|
||||
[2]=>
|
||||
int(3)
|
||||
[3]=>
|
||||
int(4)
|
||||
[4]=>
|
||||
int(5)
|
||||
}
|
43
Zend/tests/arg_unpack/internal.phpt
Normal file
43
Zend/tests/arg_unpack/internal.phpt
Normal file
@ -0,0 +1,43 @@
|
||||
--TEST--
|
||||
Argument unpacking with internal functions
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$arrays = [
|
||||
[1, 2, 3],
|
||||
[4, 5, 6],
|
||||
[7, 8, 9],
|
||||
];
|
||||
var_dump(array_map(null, ...$arrays));
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
array(3) {
|
||||
[0]=>
|
||||
array(3) {
|
||||
[0]=>
|
||||
int(1)
|
||||
[1]=>
|
||||
int(4)
|
||||
[2]=>
|
||||
int(7)
|
||||
}
|
||||
[1]=>
|
||||
array(3) {
|
||||
[0]=>
|
||||
int(2)
|
||||
[1]=>
|
||||
int(5)
|
||||
[2]=>
|
||||
int(8)
|
||||
}
|
||||
[2]=>
|
||||
array(3) {
|
||||
[0]=>
|
||||
int(3)
|
||||
[1]=>
|
||||
int(6)
|
||||
[2]=>
|
||||
int(9)
|
||||
}
|
||||
}
|
59
Zend/tests/arg_unpack/invalid_type.phpt
Normal file
59
Zend/tests/arg_unpack/invalid_type.phpt
Normal file
@ -0,0 +1,59 @@
|
||||
--TEST--
|
||||
Only arrays and Traversables can be unpacked
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
function test(...$args) {
|
||||
var_dump($args);
|
||||
}
|
||||
|
||||
test(...null);
|
||||
test(...42);
|
||||
test(...new stdClass);
|
||||
|
||||
test(1, 2, 3, ..."foo", ...[4, 5]);
|
||||
test(1, 2, ...new StdClass, 3, ...3.14, ...[4, 5]);
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Warning: Only arrays and Traversables can be unpacked in %s on line %d
|
||||
array(0) {
|
||||
}
|
||||
|
||||
Warning: Only arrays and Traversables can be unpacked in %s on line %d
|
||||
array(0) {
|
||||
}
|
||||
|
||||
Warning: Only arrays and Traversables can be unpacked in %s on line %d
|
||||
array(0) {
|
||||
}
|
||||
|
||||
Warning: Only arrays and Traversables can be unpacked in %s on line %d
|
||||
array(5) {
|
||||
[0]=>
|
||||
int(1)
|
||||
[1]=>
|
||||
int(2)
|
||||
[2]=>
|
||||
int(3)
|
||||
[3]=>
|
||||
int(4)
|
||||
[4]=>
|
||||
int(5)
|
||||
}
|
||||
|
||||
Warning: Only arrays and Traversables can be unpacked in %s on line %d
|
||||
|
||||
Warning: Only arrays and Traversables can be unpacked in %s on line %d
|
||||
array(5) {
|
||||
[0]=>
|
||||
int(1)
|
||||
[1]=>
|
||||
int(2)
|
||||
[2]=>
|
||||
int(3)
|
||||
[3]=>
|
||||
int(4)
|
||||
[4]=>
|
||||
int(5)
|
||||
}
|
45
Zend/tests/arg_unpack/method.phpt
Normal file
45
Zend/tests/arg_unpack/method.phpt
Normal file
@ -0,0 +1,45 @@
|
||||
--TEST--
|
||||
Unpack arguments for method calls
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class Foo {
|
||||
public function test(...$args) {
|
||||
var_dump($args);
|
||||
}
|
||||
|
||||
public static function test2(...$args) {
|
||||
var_dump($args);
|
||||
}
|
||||
}
|
||||
|
||||
$foo = new Foo;
|
||||
$foo->test(...[1, 2], 3, 4, ...[], 5);
|
||||
Foo::test2(1, 2, ...[3, 4], ...[], 5);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
array(5) {
|
||||
[0]=>
|
||||
int(1)
|
||||
[1]=>
|
||||
int(2)
|
||||
[2]=>
|
||||
int(3)
|
||||
[3]=>
|
||||
int(4)
|
||||
[4]=>
|
||||
int(5)
|
||||
}
|
||||
array(5) {
|
||||
[0]=>
|
||||
int(1)
|
||||
[1]=>
|
||||
int(2)
|
||||
[2]=>
|
||||
int(3)
|
||||
[3]=>
|
||||
int(4)
|
||||
[4]=>
|
||||
int(5)
|
||||
}
|
39
Zend/tests/arg_unpack/new.phpt
Normal file
39
Zend/tests/arg_unpack/new.phpt
Normal file
@ -0,0 +1,39 @@
|
||||
--TEST--
|
||||
Unpack arguments for new expression
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class Foo {
|
||||
public function __construct(...$args) {
|
||||
var_dump($args);
|
||||
}
|
||||
}
|
||||
|
||||
new Foo(...[]);
|
||||
new Foo(...[1, 2, 3]);
|
||||
new Foo(...[1], 2, ...[], ...[3, 4], 5);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
array(0) {
|
||||
}
|
||||
array(3) {
|
||||
[0]=>
|
||||
int(1)
|
||||
[1]=>
|
||||
int(2)
|
||||
[2]=>
|
||||
int(3)
|
||||
}
|
||||
array(5) {
|
||||
[0]=>
|
||||
int(1)
|
||||
[1]=>
|
||||
int(2)
|
||||
[2]=>
|
||||
int(3)
|
||||
[3]=>
|
||||
int(4)
|
||||
[4]=>
|
||||
int(5)
|
||||
}
|
20
Zend/tests/arg_unpack/string_keys.phpt
Normal file
20
Zend/tests/arg_unpack/string_keys.phpt
Normal file
@ -0,0 +1,20 @@
|
||||
--TEST--
|
||||
Argument unpacking does not work with string keys (forward compatibility for named args)
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
set_error_handler(function($errno, $errstr) {
|
||||
var_dump($errstr);
|
||||
});
|
||||
|
||||
var_dump(...[1, 2, "foo" => 3, 4]);
|
||||
var_dump(...new ArrayIterator([1, 2, "foo" => 3, 4]));
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
string(36) "Cannot unpack array with string keys"
|
||||
int(1)
|
||||
int(2)
|
||||
string(42) "Cannot unpack Traversable with string keys"
|
||||
int(1)
|
||||
int(2)
|
33
Zend/tests/arg_unpack/traversable_throwing_exception.phpt
Normal file
33
Zend/tests/arg_unpack/traversable_throwing_exception.phpt
Normal file
@ -0,0 +1,33 @@
|
||||
--TEST--
|
||||
Traversables that throw exceptions are properly handled during argument unpack
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
function test(...$args) {
|
||||
var_dump($args);
|
||||
}
|
||||
|
||||
class Foo implements IteratorAggregate {
|
||||
public function getIterator() {
|
||||
throw new Exception('getIterator');
|
||||
}
|
||||
}
|
||||
|
||||
function gen() {
|
||||
yield 1;
|
||||
yield 2;
|
||||
throw new Exception('gen');
|
||||
}
|
||||
|
||||
try {
|
||||
test(1, 2, ...new Foo, 3, 4);
|
||||
} catch (Exception $e) { var_dump($e->getMessage()); }
|
||||
|
||||
try {
|
||||
test(1, 2, ...gen(), 3, 4);
|
||||
} catch (Exception $e) { var_dump($e->getMessage()); }
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
string(11) "getIterator"
|
||||
string(3) "gen"
|
@ -0,0 +1,34 @@
|
||||
--TEST--
|
||||
Traversables cannot be unpacked into by-reference parameters
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
function test($val1, $val2, $val3, &$ref) {
|
||||
$ref = 42;
|
||||
}
|
||||
|
||||
function gen($array) {
|
||||
foreach ($array as $element) {
|
||||
yield $element;
|
||||
}
|
||||
}
|
||||
|
||||
test(...gen([1, 2, 3]), $a);
|
||||
var_dump($a);
|
||||
test(1, 2, 3, $b, ...gen([4, 5, 6]));
|
||||
var_dump($b);
|
||||
|
||||
test(...gen([1, 2, 3, 4]));
|
||||
test(1, 2, ...gen([3, 4]));
|
||||
test(...gen([1, 2]), ...gen([3, 4]));
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
int(42)
|
||||
int(42)
|
||||
|
||||
Warning: Cannot pass by-reference argument 4 of test() by unpacking a Traversable, passing by-value instead in %s on line %d
|
||||
|
||||
Warning: Cannot pass by-reference argument 4 of test() by unpacking a Traversable, passing by-value instead in %s on line %d
|
||||
|
||||
Warning: Cannot pass by-reference argument 4 of test() by unpacking a Traversable, passing by-value instead in %s on line %d
|
@ -2549,8 +2549,11 @@ void zend_do_end_function_call(znode *function_name, znode *result, const znode
|
||||
}
|
||||
opline = &CG(active_op_array)->opcodes[Z_LVAL(function_name->u.constant)];
|
||||
} else {
|
||||
zend_function **function_ptr_ptr;
|
||||
zend_stack_top(&CG(function_call_stack), (void **) &function_ptr_ptr);
|
||||
|
||||
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
|
||||
if (!is_method && !is_dynamic_fcall && function_name->op_type==IS_CONST) {
|
||||
if (*function_ptr_ptr) {
|
||||
opline->opcode = ZEND_DO_FCALL;
|
||||
SET_NODE(opline->op1, function_name);
|
||||
SET_UNUSED(opline->op2);
|
||||
@ -2562,6 +2565,13 @@ void zend_do_end_function_call(znode *function_name, znode *result, const znode
|
||||
SET_UNUSED(opline->op1);
|
||||
SET_UNUSED(opline->op2);
|
||||
opline->op2.num = --CG(context).nested_calls;
|
||||
|
||||
/* This would normally be a ZEND_DO_FCALL, but was forced to use
|
||||
* ZEND_DO_FCALL_BY_NAME due to a ... argument. In this case we need to
|
||||
* free the function_name */
|
||||
if (!is_method && !is_dynamic_fcall && function_name->op_type==IS_CONST) {
|
||||
zval_dtor(&function_name->u.constant);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2582,9 +2592,9 @@ void zend_do_end_function_call(znode *function_name, znode *result, const znode
|
||||
void zend_do_pass_param(znode *param, zend_uchar op, int offset TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
zend_op *opline;
|
||||
int original_op=op;
|
||||
int original_op = op;
|
||||
zend_function **function_ptr_ptr, *function_ptr;
|
||||
int send_by_reference;
|
||||
int send_by_reference = 0;
|
||||
int send_function = 0;
|
||||
|
||||
zend_stack_top(&CG(function_call_stack), (void **) &function_ptr_ptr);
|
||||
@ -2607,22 +2617,19 @@ void zend_do_pass_param(znode *param, zend_uchar op, int offset TSRMLS_DC) /* {{
|
||||
|
||||
if (function_ptr) {
|
||||
if (ARG_MAY_BE_SENT_BY_REF(function_ptr, (zend_uint) offset)) {
|
||||
if (param->op_type & (IS_VAR|IS_CV) && original_op != ZEND_SEND_VAL) {
|
||||
send_by_reference = 1;
|
||||
if (op == ZEND_SEND_VAR && zend_is_function_or_method_call(param)) {
|
||||
if (op == ZEND_SEND_VAR && param->op_type & (IS_VAR|IS_CV)) {
|
||||
send_by_reference = ZEND_ARG_SEND_BY_REF;
|
||||
if (zend_is_function_or_method_call(param)) {
|
||||
/* Method call */
|
||||
op = ZEND_SEND_VAR_NO_REF;
|
||||
send_function = ZEND_ARG_SEND_FUNCTION | ZEND_ARG_SEND_SILENT;
|
||||
}
|
||||
} else {
|
||||
op = ZEND_SEND_VAL;
|
||||
send_by_reference = 0;
|
||||
}
|
||||
} else {
|
||||
send_by_reference = ARG_SHOULD_BE_SENT_BY_REF(function_ptr, (zend_uint) offset) ? ZEND_ARG_SEND_BY_REF : 0;
|
||||
} else if (ARG_SHOULD_BE_SENT_BY_REF(function_ptr, (zend_uint) offset)) {
|
||||
send_by_reference = ZEND_ARG_SEND_BY_REF;
|
||||
}
|
||||
} else {
|
||||
send_by_reference = 0;
|
||||
}
|
||||
|
||||
if (op == ZEND_SEND_VAR && zend_is_function_or_method_call(param)) {
|
||||
@ -2690,6 +2697,39 @@ void zend_do_pass_param(znode *param, zend_uchar op, int offset TSRMLS_DC) /* {{
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
void zend_do_unpack_params(znode *params, int offset TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
zend_op *opline;
|
||||
zend_function **function_ptr_ptr;
|
||||
|
||||
zend_stack_top(&CG(function_call_stack), (void **) &function_ptr_ptr);
|
||||
if (*function_ptr_ptr) {
|
||||
/* If argument unpacking is used argument numbers and sending modes can no longer be
|
||||
* computed at compile time, thus we need access to EX(call). In order to have it we
|
||||
* retroactively emit a ZEND_INIT_FCALL_BY_NAME opcode. */
|
||||
zval func_name;
|
||||
ZVAL_STRING(&func_name, (*function_ptr_ptr)->common.function_name, 1);
|
||||
|
||||
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
|
||||
opline->opcode = ZEND_INIT_FCALL_BY_NAME;
|
||||
opline->result.num = CG(context).nested_calls;
|
||||
SET_UNUSED(opline->op1);
|
||||
opline->op2_type = IS_CONST;
|
||||
opline->op2.constant = zend_add_func_name_literal(CG(active_op_array), &func_name TSRMLS_CC);
|
||||
GET_CACHE_SLOT(opline->op2.constant);
|
||||
|
||||
++CG(context).nested_calls;
|
||||
*function_ptr_ptr = NULL;
|
||||
}
|
||||
|
||||
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
|
||||
opline->opcode = ZEND_SEND_UNPACK;
|
||||
SET_NODE(opline->op1, params);
|
||||
SET_UNUSED(opline->op2);
|
||||
opline->op2.num = (zend_uint) offset;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static int generate_free_switch_expr(const zend_switch_entry *switch_entry TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
zend_op *opline;
|
||||
|
@ -383,6 +383,7 @@ typedef struct _call_slot {
|
||||
zend_function *fbc;
|
||||
zval *object;
|
||||
zend_class_entry *called_scope;
|
||||
zend_uint num_additional_args;
|
||||
zend_bool is_ctor_call;
|
||||
zend_bool is_ctor_result_used;
|
||||
} call_slot;
|
||||
@ -554,6 +555,7 @@ void zend_do_early_binding(TSRMLS_D);
|
||||
ZEND_API void zend_do_delayed_early_binding(const zend_op_array *op_array TSRMLS_DC);
|
||||
|
||||
void zend_do_pass_param(znode *param, zend_uchar op, int offset TSRMLS_DC);
|
||||
void zend_do_unpack_params(znode *params, int offset TSRMLS_DC);
|
||||
|
||||
|
||||
void zend_do_boolean_or_begin(znode *expr1, znode *op_token TSRMLS_DC);
|
||||
|
@ -1684,6 +1684,13 @@ ZEND_API zend_execute_data *zend_create_execute_data_from_op_array(zend_op_array
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
zend_always_inline zend_bool zend_is_by_ref_func_arg_fetch(zend_op *opline, call_slot *call TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
zend_uint arg_num = (opline->extended_value & ZEND_FETCH_ARG_MASK) + call->num_additional_args;
|
||||
return ARG_SHOULD_BE_SENT_BY_REF(call->fbc, arg_num);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
#define ZEND_VM_NEXT_OPCODE() \
|
||||
CHECK_SYMBOL_TABLES() \
|
||||
ZEND_VM_INC_OPCODE(); \
|
||||
|
@ -585,9 +585,11 @@ non_empty_function_call_parameter_list:
|
||||
expr_without_variable { Z_LVAL($$.u.constant) = 1; zend_do_pass_param(&$1, ZEND_SEND_VAL, Z_LVAL($$.u.constant) TSRMLS_CC); }
|
||||
| variable { Z_LVAL($$.u.constant) = 1; zend_do_pass_param(&$1, ZEND_SEND_VAR, Z_LVAL($$.u.constant) TSRMLS_CC); }
|
||||
| '&' w_variable { Z_LVAL($$.u.constant) = 1; zend_do_pass_param(&$2, ZEND_SEND_REF, Z_LVAL($$.u.constant) TSRMLS_CC); }
|
||||
| T_ELLIPSIS expr { Z_LVAL($$.u.constant) = 0; zend_do_unpack_params(&$2, Z_LVAL($$.u.constant) TSRMLS_CC); }
|
||||
| non_empty_function_call_parameter_list ',' expr_without_variable { Z_LVAL($$.u.constant)=Z_LVAL($1.u.constant)+1; zend_do_pass_param(&$3, ZEND_SEND_VAL, Z_LVAL($$.u.constant) TSRMLS_CC); }
|
||||
| non_empty_function_call_parameter_list ',' variable { Z_LVAL($$.u.constant)=Z_LVAL($1.u.constant)+1; zend_do_pass_param(&$3, ZEND_SEND_VAR, Z_LVAL($$.u.constant) TSRMLS_CC); }
|
||||
| non_empty_function_call_parameter_list ',' '&' w_variable { Z_LVAL($$.u.constant)=Z_LVAL($1.u.constant)+1; zend_do_pass_param(&$4, ZEND_SEND_REF, Z_LVAL($$.u.constant) TSRMLS_CC); }
|
||||
| non_empty_function_call_parameter_list ',' T_ELLIPSIS expr { Z_LVAL($$.u.constant)=Z_LVAL($1.u.constant); zend_do_unpack_params(&$4, Z_LVAL($$.u.constant) TSRMLS_CC); }
|
||||
;
|
||||
|
||||
global_var_list:
|
||||
|
@ -1143,7 +1143,7 @@ ZEND_VM_HANDLER(92, ZEND_FETCH_FUNC_ARG, CONST|TMP|VAR|CV, UNUSED|CONST|VAR)
|
||||
USE_OPLINE
|
||||
|
||||
ZEND_VM_DISPATCH_TO_HELPER_EX(zend_fetch_var_address_helper, type,
|
||||
ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R);
|
||||
zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC) ? BP_VAR_W : BP_VAR_R);
|
||||
}
|
||||
|
||||
ZEND_VM_HANDLER(95, ZEND_FETCH_UNSET, CONST|TMP|VAR|CV, UNUSED|CONST|VAR)
|
||||
@ -1251,9 +1251,8 @@ ZEND_VM_HANDLER(93, ZEND_FETCH_DIM_FUNC_ARG, VAR|CV, CONST|TMP|VAR|UNUSED|CV)
|
||||
|
||||
SAVE_OPLINE();
|
||||
|
||||
if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) {
|
||||
if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) {
|
||||
zval **container = GET_OP1_ZVAL_PTR_PTR(BP_VAR_W);
|
||||
|
||||
if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) {
|
||||
zend_error_noreturn(E_ERROR, "Cannot use string offset as an array");
|
||||
}
|
||||
@ -1488,7 +1487,7 @@ ZEND_VM_HANDLER(94, ZEND_FETCH_OBJ_FUNC_ARG, VAR|UNUSED|CV, CONST|TMP|VAR|CV)
|
||||
{
|
||||
USE_OPLINE
|
||||
|
||||
if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) {
|
||||
if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) {
|
||||
/* Behave like FETCH_OBJ_W */
|
||||
zend_free_op free_op1, free_op2;
|
||||
zval *property;
|
||||
@ -1902,6 +1901,7 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY)
|
||||
USE_OPLINE
|
||||
zend_bool should_change_scope = 0;
|
||||
zend_function *fbc = EX(function_state).function;
|
||||
zend_uint num_args;
|
||||
|
||||
SAVE_OPLINE();
|
||||
EX(object) = EX(call)->object;
|
||||
@ -1946,19 +1946,18 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY)
|
||||
EG(called_scope) = EX(call)->called_scope;
|
||||
}
|
||||
|
||||
num_args = opline->extended_value + EX(call)->num_additional_args;
|
||||
EX(function_state).arguments = zend_vm_stack_top(TSRMLS_C);
|
||||
zend_vm_stack_push((void*)(zend_uintptr_t)opline->extended_value TSRMLS_CC);
|
||||
zend_vm_stack_push((void*)(zend_uintptr_t) num_args TSRMLS_CC);
|
||||
LOAD_OPLINE();
|
||||
|
||||
if (fbc->type == ZEND_INTERNAL_FUNCTION) {
|
||||
if (fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
|
||||
zend_uint i=0;
|
||||
zval **p = (zval**)EX(function_state).arguments;
|
||||
ulong arg_count = opline->extended_value;
|
||||
zend_uint i;
|
||||
void **p = EX(function_state).arguments - num_args;
|
||||
|
||||
while (arg_count>0) {
|
||||
zend_verify_arg_type(fbc, ++i, *(p-arg_count), 0 TSRMLS_CC);
|
||||
arg_count--;
|
||||
for (i = 0; i < num_args; ++i, ++p) {
|
||||
zend_verify_arg_type(fbc, i + 1, (zval *) *p, 0 TSRMLS_CC);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1972,7 +1971,7 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY)
|
||||
|
||||
if (!zend_execute_internal) {
|
||||
/* saves one function call if zend_execute_internal is not used */
|
||||
fbc->internal_function.handler(opline->extended_value, ret->var.ptr, &ret->var.ptr, EX(object), RETURN_VALUE_USED(opline) TSRMLS_CC);
|
||||
fbc->internal_function.handler(num_args, ret->var.ptr, &ret->var.ptr, EX(object), RETURN_VALUE_USED(opline) TSRMLS_CC);
|
||||
} else {
|
||||
zend_execute_internal(execute_data, NULL, RETURN_VALUE_USED(opline) TSRMLS_CC);
|
||||
}
|
||||
@ -2022,7 +2021,7 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY)
|
||||
|
||||
/* Not sure what should be done here if it's a static method */
|
||||
if (EXPECTED(EX(object) != NULL)) {
|
||||
Z_OBJ_HT_P(EX(object))->call_method(fbc->common.function_name, opline->extended_value, EX_T(opline->result.var).var.ptr, &EX_T(opline->result.var).var.ptr, EX(object), RETURN_VALUE_USED(opline) TSRMLS_CC);
|
||||
Z_OBJ_HT_P(EX(object))->call_method(fbc->common.function_name, num_args, EX_T(opline->result.var).var.ptr, &EX_T(opline->result.var).var.ptr, EX(object), RETURN_VALUE_USED(opline) TSRMLS_CC);
|
||||
} else {
|
||||
zend_error_noreturn(E_ERROR, "Cannot call overloaded function for non-object");
|
||||
}
|
||||
@ -2476,6 +2475,8 @@ ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, TMP|VAR|UNUSED|CV, CONST|TMP|VAR|CV)
|
||||
call->object = this_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
call->num_additional_args = 0;
|
||||
call->is_ctor_call = 0;
|
||||
EX(call) = call;
|
||||
|
||||
@ -2602,6 +2603,8 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMP|VAR|UNUS
|
||||
call->called_scope = Z_OBJCE_P(call->object);
|
||||
}
|
||||
}
|
||||
|
||||
call->num_additional_args = 0;
|
||||
call->is_ctor_call = 0;
|
||||
EX(call) = call;
|
||||
|
||||
@ -2625,10 +2628,13 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV)
|
||||
} else {
|
||||
CACHE_PTR(opline->op2.literal->cache_slot, call->fbc);
|
||||
}
|
||||
|
||||
call->object = NULL;
|
||||
call->called_scope = NULL;
|
||||
call->num_additional_args = 0;
|
||||
call->is_ctor_call = 0;
|
||||
EX(call) = call;
|
||||
|
||||
/*CHECK_EXCEPTION();*/
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
} else {
|
||||
@ -2653,10 +2659,13 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV)
|
||||
}
|
||||
efree(lcname);
|
||||
FREE_OP2();
|
||||
|
||||
call->object = NULL;
|
||||
call->called_scope = NULL;
|
||||
call->num_additional_args = 0;
|
||||
call->is_ctor_call = 0;
|
||||
EX(call) = call;
|
||||
|
||||
CHECK_EXCEPTION();
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
} else if (OP2_TYPE != IS_CONST && OP2_TYPE != IS_TMP_VAR &&
|
||||
@ -2673,8 +2682,11 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV)
|
||||
} else {
|
||||
FREE_OP2();
|
||||
}
|
||||
|
||||
call->num_additional_args = 0;
|
||||
call->is_ctor_call = 0;
|
||||
EX(call) = call;
|
||||
|
||||
CHECK_EXCEPTION();
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
} else if (OP2_TYPE != IS_CONST &&
|
||||
@ -2740,8 +2752,11 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV)
|
||||
if (UNEXPECTED(call->fbc == NULL)) {
|
||||
zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, Z_STRVAL_PP(method));
|
||||
}
|
||||
|
||||
call->num_additional_args = 0;
|
||||
call->is_ctor_call = 0;
|
||||
EX(call) = call;
|
||||
|
||||
FREE_OP2();
|
||||
CHECK_EXCEPTION();
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
@ -2779,7 +2794,9 @@ ZEND_VM_HANDLER(69, ZEND_INIT_NS_FCALL_BY_NAME, ANY, CONST)
|
||||
|
||||
call->object = NULL;
|
||||
call->called_scope = NULL;
|
||||
call->num_additional_args = 0;
|
||||
call->is_ctor_call = 0;
|
||||
|
||||
EX(call) = call;
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
}
|
||||
@ -2805,9 +2822,11 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, CONST, ANY)
|
||||
} else {
|
||||
CACHE_PTR(opline->op1.literal->cache_slot, EX(function_state).function);
|
||||
}
|
||||
|
||||
call->fbc = EX(function_state).function;
|
||||
call->object = NULL;
|
||||
call->called_scope = NULL;
|
||||
call->num_additional_args = 0;
|
||||
call->is_ctor_call = 0;
|
||||
EX(call) = call;
|
||||
|
||||
@ -3039,10 +3058,13 @@ ZEND_VM_HANDLER(65, ZEND_SEND_VAL, CONST|TMP, ANY)
|
||||
USE_OPLINE
|
||||
|
||||
SAVE_OPLINE();
|
||||
if (opline->extended_value==ZEND_DO_FCALL_BY_NAME
|
||||
&& ARG_MUST_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) {
|
||||
zend_error_noreturn(E_ERROR, "Cannot pass parameter %d by reference", opline->op2.opline_num);
|
||||
if (opline->extended_value == ZEND_DO_FCALL_BY_NAME) {
|
||||
int arg_num = opline->op2.num + EX(call)->num_additional_args;
|
||||
if (ARG_MUST_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) {
|
||||
zend_error_noreturn(E_ERROR, "Cannot pass parameter %d by reference", arg_num);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
zval *valptr;
|
||||
zval *value;
|
||||
@ -3100,14 +3122,18 @@ ZEND_VM_HANDLER(106, ZEND_SEND_VAR_NO_REF, VAR|CV, ANY)
|
||||
USE_OPLINE
|
||||
zend_free_op free_op1;
|
||||
zval *varptr;
|
||||
int arg_num;
|
||||
|
||||
SAVE_OPLINE();
|
||||
if (opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) { /* Had function_ptr at compile_time */
|
||||
if (!(opline->extended_value & ZEND_ARG_SEND_BY_REF)) {
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_send_by_var_helper);
|
||||
}
|
||||
} else if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) {
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_send_by_var_helper);
|
||||
} else {
|
||||
arg_num = opline->op2.num + EX(call)->num_additional_args;
|
||||
if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) {
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_send_by_var_helper);
|
||||
}
|
||||
}
|
||||
|
||||
varptr = GET_OP1_ZVAL_PTR(BP_VAR_R);
|
||||
@ -3125,7 +3151,7 @@ ZEND_VM_HANDLER(106, ZEND_SEND_VAR_NO_REF, VAR|CV, ANY)
|
||||
|
||||
if ((opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) ?
|
||||
!(opline->extended_value & ZEND_ARG_SEND_SILENT) :
|
||||
!ARG_MAY_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) {
|
||||
!ARG_MAY_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) {
|
||||
zend_error(E_STRICT, "Only variables should be passed by reference");
|
||||
}
|
||||
ALLOC_ZVAL(valptr);
|
||||
@ -3162,9 +3188,11 @@ ZEND_VM_HANDLER(67, ZEND_SEND_REF, VAR|CV, ANY)
|
||||
}
|
||||
|
||||
if (opline->extended_value == ZEND_DO_FCALL_BY_NAME &&
|
||||
EX(function_state).function->type == ZEND_INTERNAL_FUNCTION &&
|
||||
!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) {
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_send_by_var_helper);
|
||||
EX(function_state).function->type == ZEND_INTERNAL_FUNCTION) {
|
||||
int arg_num = opline->op2.num + EX(call)->num_additional_args;
|
||||
if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) {
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_send_by_var_helper);
|
||||
}
|
||||
}
|
||||
|
||||
SEPARATE_ZVAL_TO_MAKE_IS_REF(varptr_ptr);
|
||||
@ -3181,14 +3209,164 @@ ZEND_VM_HANDLER(66, ZEND_SEND_VAR, VAR|CV, ANY)
|
||||
{
|
||||
USE_OPLINE
|
||||
|
||||
if ((opline->extended_value == ZEND_DO_FCALL_BY_NAME)
|
||||
&& ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) {
|
||||
ZEND_VM_DISPATCH_TO_HANDLER(ZEND_SEND_REF);
|
||||
if (opline->extended_value == ZEND_DO_FCALL_BY_NAME) {
|
||||
int arg_num = opline->op2.num + EX(call)->num_additional_args;
|
||||
if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) {
|
||||
ZEND_VM_DISPATCH_TO_HANDLER(ZEND_SEND_REF);
|
||||
}
|
||||
}
|
||||
SAVE_OPLINE();
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_send_by_var_helper);
|
||||
}
|
||||
|
||||
ZEND_VM_HANDLER(165, ZEND_SEND_UNPACK, ANY, ANY)
|
||||
{
|
||||
USE_OPLINE
|
||||
zend_free_op free_op1;
|
||||
zval *args;
|
||||
int arg_num;
|
||||
SAVE_OPLINE();
|
||||
|
||||
args = GET_OP1_ZVAL_PTR(BP_VAR_R);
|
||||
arg_num = opline->op2.num + EX(call)->num_additional_args + 1;
|
||||
|
||||
switch (Z_TYPE_P(args)) {
|
||||
case IS_ARRAY: {
|
||||
HashTable *ht = Z_ARRVAL_P(args);
|
||||
HashPosition pos;
|
||||
zval **arg_ptr, *arg;
|
||||
|
||||
ZEND_VM_STACK_GROW_IF_NEEDED(zend_hash_num_elements(ht));
|
||||
|
||||
for (zend_hash_internal_pointer_reset_ex(ht, &pos);
|
||||
zend_hash_get_current_data_ex(ht, (void **) &arg_ptr, &pos) == SUCCESS;
|
||||
zend_hash_move_forward_ex(ht, &pos), ++arg_num
|
||||
) {
|
||||
char *name;
|
||||
zend_uint name_len;
|
||||
zend_ulong index;
|
||||
|
||||
if (zend_hash_get_current_key_ex(ht, &name, &name_len, &index, 0, &pos) == HASH_KEY_IS_STRING) {
|
||||
zend_error(E_RECOVERABLE_ERROR, "Cannot unpack array with string keys");
|
||||
FREE_OP1();
|
||||
CHECK_EXCEPTION();
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
}
|
||||
|
||||
if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) {
|
||||
SEPARATE_ZVAL_TO_MAKE_IS_REF(arg_ptr);
|
||||
arg = *arg_ptr;
|
||||
Z_ADDREF_P(arg);
|
||||
} else if (Z_ISREF_PP(arg_ptr)) {
|
||||
ALLOC_ZVAL(arg);
|
||||
MAKE_COPY_ZVAL(arg_ptr, arg);
|
||||
} else {
|
||||
arg = *arg_ptr;
|
||||
Z_ADDREF_P(arg);
|
||||
}
|
||||
|
||||
zend_vm_stack_push(arg TSRMLS_CC);
|
||||
EX(call)->num_additional_args++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IS_OBJECT: {
|
||||
zend_class_entry *ce = Z_OBJCE_P(args);
|
||||
zend_object_iterator *iter;
|
||||
|
||||
if (!ce || !ce->get_iterator) {
|
||||
zend_error(E_WARNING, "Only arrays and Traversables can be unpacked");
|
||||
break;
|
||||
}
|
||||
|
||||
iter = ce->get_iterator(ce, args, 0 TSRMLS_CC);
|
||||
if (UNEXPECTED(!iter)) {
|
||||
FREE_OP1();
|
||||
if (!EG(exception)) {
|
||||
zend_throw_exception_ex(
|
||||
NULL, 0 TSRMLS_CC, "Object of type %s did not create an Iterator", ce->name
|
||||
);
|
||||
}
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
|
||||
if (iter->funcs->rewind) {
|
||||
iter->funcs->rewind(iter TSRMLS_CC);
|
||||
if (UNEXPECTED(EG(exception) != NULL)) {
|
||||
ZEND_VM_C_GOTO(unpack_iter_dtor);
|
||||
}
|
||||
}
|
||||
|
||||
for (; iter->funcs->valid(iter TSRMLS_CC) == SUCCESS; ++arg_num) {
|
||||
zval **arg_ptr, *arg;
|
||||
|
||||
if (UNEXPECTED(EG(exception) != NULL)) {
|
||||
ZEND_VM_C_GOTO(unpack_iter_dtor);
|
||||
}
|
||||
|
||||
iter->funcs->get_current_data(iter, &arg_ptr TSRMLS_CC);
|
||||
if (UNEXPECTED(EG(exception) != NULL)) {
|
||||
ZEND_VM_C_GOTO(unpack_iter_dtor);
|
||||
}
|
||||
|
||||
if (iter->funcs->get_current_key) {
|
||||
zval key;
|
||||
iter->funcs->get_current_key(iter, &key TSRMLS_CC);
|
||||
if (UNEXPECTED(EG(exception) != NULL)) {
|
||||
ZEND_VM_C_GOTO(unpack_iter_dtor);
|
||||
}
|
||||
|
||||
if (Z_TYPE(key) == IS_STRING) {
|
||||
zend_error(E_RECOVERABLE_ERROR,
|
||||
"Cannot unpack Traversable with string keys");
|
||||
zval_dtor(&key);
|
||||
ZEND_VM_C_GOTO(unpack_iter_dtor);
|
||||
}
|
||||
|
||||
zval_dtor(&key);
|
||||
}
|
||||
|
||||
if (ARG_MUST_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) {
|
||||
zend_error(
|
||||
E_WARNING, "Cannot pass by-reference argument %d of %s%s%s()"
|
||||
" by unpacking a Traversable, passing by-value instead", arg_num,
|
||||
EX(call)->fbc->common.scope ? EX(call)->fbc->common.scope->name : "",
|
||||
EX(call)->fbc->common.scope ? "::" : "",
|
||||
EX(call)->fbc->common.function_name
|
||||
);
|
||||
}
|
||||
|
||||
if (Z_ISREF_PP(arg_ptr)) {
|
||||
ALLOC_ZVAL(arg);
|
||||
MAKE_COPY_ZVAL(arg_ptr, arg);
|
||||
} else {
|
||||
arg = *arg_ptr;
|
||||
Z_ADDREF_P(arg);
|
||||
}
|
||||
|
||||
ZEND_VM_STACK_GROW_IF_NEEDED(1);
|
||||
zend_vm_stack_push(arg TSRMLS_CC);
|
||||
EX(call)->num_additional_args++;
|
||||
|
||||
iter->funcs->move_forward(iter TSRMLS_CC);
|
||||
if (UNEXPECTED(EG(exception) != NULL)) {
|
||||
ZEND_VM_C_GOTO(unpack_iter_dtor);
|
||||
}
|
||||
}
|
||||
|
||||
ZEND_VM_C_LABEL(unpack_iter_dtor):
|
||||
iter->funcs->dtor(iter TSRMLS_CC);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
zend_error(E_WARNING, "Only arrays and Traversables can be unpacked");
|
||||
}
|
||||
|
||||
FREE_OP1();
|
||||
CHECK_EXCEPTION();
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
}
|
||||
|
||||
ZEND_VM_HANDLER(63, ZEND_RECV, ANY, ANY)
|
||||
{
|
||||
USE_OPLINE
|
||||
@ -3424,6 +3602,7 @@ ZEND_VM_HANDLER(68, ZEND_NEW, ANY, ANY)
|
||||
call->fbc = constructor;
|
||||
call->object = object_zval;
|
||||
call->called_scope = EX_T(opline->op1.var).class_entry;
|
||||
call->num_additional_args = 0;
|
||||
call->is_ctor_call = 1;
|
||||
call->is_ctor_result_used = RETURN_VALUE_USED(opline);
|
||||
EX(call) = call;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -21,7 +21,7 @@
|
||||
#include <stdio.h>
|
||||
#include <zend.h>
|
||||
|
||||
const char *zend_vm_opcodes_map[165] = {
|
||||
const char *zend_vm_opcodes_map[166] = {
|
||||
"ZEND_NOP",
|
||||
"ZEND_ADD",
|
||||
"ZEND_SUB",
|
||||
@ -187,6 +187,7 @@ const char *zend_vm_opcodes_map[165] = {
|
||||
"ZEND_FAST_CALL",
|
||||
"ZEND_FAST_RET",
|
||||
"ZEND_RECV_VARIADIC",
|
||||
"ZEND_SEND_UNPACK",
|
||||
};
|
||||
|
||||
ZEND_API const char* zend_get_opcode_name(zend_uchar opcode) {
|
||||
|
@ -170,5 +170,6 @@ ZEND_API const char *zend_get_opcode_name(zend_uchar opcode);
|
||||
#define ZEND_FAST_CALL 162
|
||||
#define ZEND_FAST_RET 163
|
||||
#define ZEND_RECV_VARIADIC 164
|
||||
#define ZEND_SEND_UNPACK 165
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user