Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 116 additions & 0 deletions Zend/tests/partial_application/default_const_expr.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
--TEST--
PFA: constant-expression default for a skipped optional parameter
--FILE--
<?php

namespace App;

const K = 7;

function f($a, $b = K, $c = 0) {
return [$a, $b, $c];
}

function variadic($a, $b = K, $c = 0, ...$args) {
return [$a, $b, $c, $args];
}

function late($a, $b = LATE, $c = 0) {
return [$a, $b, $c];
}

function fallback($a, $b = GLOBAL_ONLY, $c = 0) {
return [$a, $b, $c];
}

class C {
const X = 42;
static function m($a, $b = self::X, $c = 0) {
return [$a, $b, $c];
}
}

enum E {
case A;
case B;
}

function g($a, $b = E::A, $c = 0) {
return [$a, $b->name, $c];
}

$p = f(a: 10, c: ?);
var_dump($p(99));

$v = variadic(a: 10, c: ?, foo: 1);
var_dump($v(99));

$q = C::m(a: 1, c: ?);
var_dump($q(9));

$r = g(a: 1, c: ?);
var_dump($r(9));

$l = late(a: 1, c: ?);
define('App\LATE', 'defined after the partial was created');
var_dump($l(9));

define('GLOBAL_ONLY', 'global fallback');
$s = fallback(a: 1, c: ?);
var_dump($s(9));

?>
--EXPECT--
array(3) {
[0]=>
int(10)
[1]=>
int(7)
[2]=>
int(99)
}
array(4) {
[0]=>
int(10)
[1]=>
int(7)
[2]=>
int(99)
[3]=>
array(1) {
["foo"]=>
int(1)
}
}
array(3) {
[0]=>
int(1)
[1]=>
int(42)
[2]=>
int(9)
}
array(3) {
[0]=>
int(1)
[1]=>
string(1) "A"
[2]=>
int(9)
}
array(3) {
[0]=>
int(1)
[1]=>
string(37) "defined after the partial was created"
[2]=>
int(9)
}
array(3) {
[0]=>
int(1)
[1]=>
string(15) "global fallback"
[2]=>
int(9)
}
43 changes: 28 additions & 15 deletions Zend/zend_compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -11519,12 +11519,25 @@ static void zend_compile_array(znode *result, zend_ast *ast) /* {{{ */
}
/* }}} */

static void zend_emit_fetch_constant(znode *result, zend_string *resolved_name, bool unqualified_in_namespace)
{
zend_op *opline = zend_emit_op_tmp(result, ZEND_FETCH_CONSTANT, NULL, NULL);
opline->op2_type = IS_CONST;

if (unqualified_in_namespace) {
opline->op1.num = IS_CONSTANT_UNQUALIFIED_IN_NAMESPACE;
opline->op2.constant = zend_add_const_name_literal(resolved_name, true);
} else {
opline->op1.num = 0;
opline->op2.constant = zend_add_const_name_literal(resolved_name, false);
}
opline->extended_value = zend_alloc_cache_slot();
}

static void zend_compile_const(znode *result, const zend_ast *ast) /* {{{ */
{
zend_ast *name_ast = ast->child[0];

zend_op *opline;

bool is_fully_qualified;
zend_string *orig_name = zend_ast_get_str(name_ast);
zend_string *resolved_name = zend_resolve_const_name(orig_name, name_ast->attr, &is_fully_qualified);
Expand Down Expand Up @@ -11553,22 +11566,19 @@ static void zend_compile_const(znode *result, const zend_ast *ast) /* {{{ */
return;
}

opline = zend_emit_op_tmp(result, ZEND_FETCH_CONSTANT, NULL, NULL);
opline->op2_type = IS_CONST;

if (is_fully_qualified || !FC(current_namespace)) {
opline->op1.num = 0;
opline->op2.constant = zend_add_const_name_literal(
resolved_name, false);
} else {
opline->op1.num = IS_CONSTANT_UNQUALIFIED_IN_NAMESPACE;
opline->op2.constant = zend_add_const_name_literal(
resolved_name, true);
}
opline->extended_value = zend_alloc_cache_slot();
zend_emit_fetch_constant(result, resolved_name,
!is_fully_qualified && FC(current_namespace));
}
/* }}} */

static void zend_compile_constant(znode *result, zend_ast *ast)
{
zend_string *name = zend_ast_get_constant_name(ast);

zend_emit_fetch_constant(result, zend_string_copy(name),
(ast->attr & IS_CONSTANT_UNQUALIFIED_IN_NAMESPACE) != 0);
}

static void zend_compile_class_const(znode *result, zend_ast *ast) /* {{{ */
{
zend_ast *class_ast;
Expand Down Expand Up @@ -12436,6 +12446,9 @@ static void zend_compile_expr_inner(znode *result, zend_ast *ast) /* {{{ */
case ZEND_AST_CONST:
zend_compile_const(result, ast);
return;
case ZEND_AST_CONSTANT:
zend_compile_constant(result, ast);
return;
case ZEND_AST_CLASS_CONST:
zend_compile_class_const(result, ast);
return;
Expand Down
1 change: 1 addition & 0 deletions Zend/zend_partial.c
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,7 @@ static zend_ast *zp_compile_forwarding_call(
if (Z_TYPE(default_value) == IS_CONSTANT_AST) {
/* Must dup AST because we are going to destroy it */
default_value_ast = zend_ast_dup(Z_ASTVAL(default_value));
zval_ptr_dtor_nogc(&default_value);
} else {
default_value_ast = zend_ast_create_zval(&default_value);
}
Expand Down
Loading