Skip to content

Commit 3b08f53

Browse files
committed
Deprecate required param after optional
As an exception, we allow "Type $foo = null" to occur before a required parameter, because this pattern was used as a replacement for nullable types in PHP versions older than 7.1. Closes GH-5067.
1 parent 9d79e51 commit 3b08f53

File tree

8 files changed

+55
-21
lines changed

8 files changed

+55
-21
lines changed

UPGRADING

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,13 @@ PHP 8.0 UPGRADE NOTES
142142

143143
The name shown above is still followed by a null byte and and a unique
144144
suffix.
145+
. Declaring a required parameter after an optional one is deprecated. As an
146+
exception, declaring a parameter of the form "Type $param = null" before
147+
a required one continues to be allowed, because this pattern was sometimes
148+
used to achieve nullable types in older PHP versions.
149+
150+
function test($a = [], $b) {} // Deprecated
151+
function test(Foo $a = null, $b) {} // Allowed
145152

146153
- COM:
147154
. Removed the ability to import case-insensitive constants from type

Zend/tests/call_user_func_005.phpt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ var_dump(call_user_func(array('foo', 'teste')));
1818

1919
?>
2020
--EXPECTF--
21+
Deprecated: Required parameter $b follows optional parameter $a in %s on line %d
2122
string(1) "x"
2223
array(1) {
2324
[0]=>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
--TEST--
2+
Required parameter after optional is deprecated
3+
--FILE--
4+
<?php
5+
6+
function test($testA = null, $testB = null, $testC) {}
7+
function test2(Type $test2A = null, $test2B = null, $test2C) {}
8+
function test3(Type $test3A = null, Type2 $test3B = null, $test3C) {}
9+
10+
?>
11+
--EXPECTF--
12+
Deprecated: Required parameter $testC follows optional parameter $testA in %s on line %d
13+
14+
Deprecated: Required parameter $test2C follows optional parameter $test2B in %s on line %d

Zend/tests/traits/bug60717.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ namespace HTML
99
{
1010
function text($text);
1111
function attributes(array $attributes = null);
12-
function textArea(array $attributes = null, $value);
12+
function textArea(?array $attributes, $value);
1313
}
1414

1515
trait TextUTF8
@@ -19,7 +19,7 @@ namespace HTML
1919

2020
trait TextArea
2121
{
22-
function textArea(array $attributes = null, $value) {}
22+
function textArea(?array $attributes, $value) {}
2323
abstract function attributes(array $attributes = null);
2424
abstract function text($text);
2525
}

Zend/zend_compile.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5720,6 +5720,7 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast) /* {{{ */
57205720
uint32_t i;
57215721
zend_op_array *op_array = CG(active_op_array);
57225722
zend_arg_info *arg_infos;
5723+
zend_string *optional_param = NULL;
57235724

57245725
if (return_type_ast) {
57255726
/* Use op_array->arg_info[-1] for return type */
@@ -5788,10 +5789,24 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast) /* {{{ */
57885789
default_node.op_type = IS_CONST;
57895790
zend_const_expr_to_zval(&default_node.u.constant, default_ast);
57905791
CG(compiler_options) = cops;
5792+
5793+
if (!optional_param) {
5794+
/* Ignore parameters of the form "Type $param = null".
5795+
* This is the PHP 5 style way of writing "?Type $param", so allow it for now. */
5796+
zend_bool is_implicit_nullable =
5797+
type_ast && Z_TYPE(default_node.u.constant) == IS_NULL;
5798+
if (!is_implicit_nullable) {
5799+
optional_param = name;
5800+
}
5801+
}
57915802
} else {
57925803
opcode = ZEND_RECV;
57935804
default_node.op_type = IS_UNUSED;
57945805
op_array->required_num_args = i + 1;
5806+
if (optional_param) {
5807+
zend_error(E_DEPRECATED, "Required parameter $%s follows optional parameter $%s",
5808+
ZSTR_VAL(name), ZSTR_VAL(optional_param));
5809+
}
57955810
}
57965811

57975812
arg_info = &arg_infos[i];

ext/reflection/tests/ReflectionClass_isArray.phpt

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ public bool ReflectionParameter::isArray ( void );
44
marcosptf - <[email protected]> - @phpsp - sao paulo - br
55
--FILE--
66
<?php
7-
function testReflectionIsArray($a = null, $b = 0, array $c, $d=true, array $e, $f=1.5, $g="", array $h, $i="#F989898") {}
7+
8+
function testReflectionIsArray(array $a, ?array $b, iterable $c, array|string $d) {}
89

910
$reflection = new ReflectionFunction('testReflectionIsArray');
1011

@@ -13,12 +14,7 @@ foreach ($reflection->getParameters() as $parameter) {
1314
}
1415
?>
1516
--EXPECT--
16-
bool(false)
17-
bool(false)
1817
bool(true)
19-
bool(false)
2018
bool(true)
2119
bool(false)
2220
bool(false)
23-
bool(true)
24-
bool(false)

ext/reflection/tests/ReflectionType_001.phpt

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
ReflectionParameter::get/hasType and ReflectionType tests
33
--FILE--
44
<?php
5-
function foo(stdClass $a, array $b, callable $c, stdClass $d = null, $e = null, string $f, bool $g, int $h, float $i, NotExisting $j) { }
5+
function foo(stdClass $a, array $b, callable $c, string $f, bool $g, int $h, float $i, NotExisting $j, stdClass $d = null, $e = null) { }
66

77
function bar(): stdClass { return new stdClass; }
88

@@ -120,36 +120,36 @@ bool(true)
120120
string(8) "callable"
121121
** Function 0 - Parameter 3
122122
bool(true)
123-
bool(true)
124-
bool(false)
125-
string(8) "stdClass"
126-
** Function 0 - Parameter 4
127-
bool(false)
128-
** Function 0 - Parameter 5
129-
bool(true)
130123
bool(false)
131124
bool(true)
132125
string(6) "string"
133-
** Function 0 - Parameter 6
126+
** Function 0 - Parameter 4
134127
bool(true)
135128
bool(false)
136129
bool(true)
137130
string(4) "bool"
138-
** Function 0 - Parameter 7
131+
** Function 0 - Parameter 5
139132
bool(true)
140133
bool(false)
141134
bool(true)
142135
string(3) "int"
143-
** Function 0 - Parameter 8
136+
** Function 0 - Parameter 6
144137
bool(true)
145138
bool(false)
146139
bool(true)
147140
string(5) "float"
148-
** Function 0 - Parameter 9
141+
** Function 0 - Parameter 7
149142
bool(true)
150143
bool(false)
151144
bool(false)
152145
string(11) "NotExisting"
146+
** Function 0 - Parameter 8
147+
bool(true)
148+
bool(true)
149+
bool(false)
150+
string(8) "stdClass"
151+
** Function 0 - Parameter 9
152+
bool(false)
153153
** Function 1 - Parameter 0
154154
bool(true)
155155
bool(false)

ext/reflection/tests/bug62715.phpt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ foreach ($r->getParameters() as $p) {
1616
}
1717
}
1818
?>
19-
--EXPECT--
19+
--EXPECTF--
20+
Deprecated: Required parameter $c follows optional parameter $b in %s on line %d
2021
bool(true)
2122
bool(true)
2223
bool(false)

0 commit comments

Comments
 (0)