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.
This commit is contained in:
Nikita Popov 2020-01-09 12:21:02 +01:00
parent 9d79e510d5
commit 3b08f53c97
8 changed files with 55 additions and 21 deletions

View File

@ -142,6 +142,13 @@ PHP 8.0 UPGRADE NOTES
The name shown above is still followed by a null byte and and a unique
suffix.
. Declaring a required parameter after an optional one is deprecated. As an
exception, declaring a parameter of the form "Type $param = null" before
a required one continues to be allowed, because this pattern was sometimes
used to achieve nullable types in older PHP versions.
function test($a = [], $b) {} // Deprecated
function test(Foo $a = null, $b) {} // Allowed
- COM:
. Removed the ability to import case-insensitive constants from type

View File

@ -18,6 +18,7 @@ var_dump(call_user_func(array('foo', 'teste')));
?>
--EXPECTF--
Deprecated: Required parameter $b follows optional parameter $a in %s on line %d
string(1) "x"
array(1) {
[0]=>

View File

@ -0,0 +1,14 @@
--TEST--
Required parameter after optional is deprecated
--FILE--
<?php
function test($testA = null, $testB = null, $testC) {}
function test2(Type $test2A = null, $test2B = null, $test2C) {}
function test3(Type $test3A = null, Type2 $test3B = null, $test3C) {}
?>
--EXPECTF--
Deprecated: Required parameter $testC follows optional parameter $testA in %s on line %d
Deprecated: Required parameter $test2C follows optional parameter $test2B in %s on line %d

View File

@ -9,7 +9,7 @@ namespace HTML
{
function text($text);
function attributes(array $attributes = null);
function textArea(array $attributes = null, $value);
function textArea(?array $attributes, $value);
}
trait TextUTF8
@ -19,7 +19,7 @@ namespace HTML
trait TextArea
{
function textArea(array $attributes = null, $value) {}
function textArea(?array $attributes, $value) {}
abstract function attributes(array $attributes = null);
abstract function text($text);
}

View File

@ -5720,6 +5720,7 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast) /* {{{ */
uint32_t i;
zend_op_array *op_array = CG(active_op_array);
zend_arg_info *arg_infos;
zend_string *optional_param = NULL;
if (return_type_ast) {
/* 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) /* {{{ */
default_node.op_type = IS_CONST;
zend_const_expr_to_zval(&default_node.u.constant, default_ast);
CG(compiler_options) = cops;
if (!optional_param) {
/* Ignore parameters of the form "Type $param = null".
* This is the PHP 5 style way of writing "?Type $param", so allow it for now. */
zend_bool is_implicit_nullable =
type_ast && Z_TYPE(default_node.u.constant) == IS_NULL;
if (!is_implicit_nullable) {
optional_param = name;
}
}
} else {
opcode = ZEND_RECV;
default_node.op_type = IS_UNUSED;
op_array->required_num_args = i + 1;
if (optional_param) {
zend_error(E_DEPRECATED, "Required parameter $%s follows optional parameter $%s",
ZSTR_VAL(name), ZSTR_VAL(optional_param));
}
}
arg_info = &arg_infos[i];

View File

@ -4,7 +4,8 @@ public bool ReflectionParameter::isArray ( void );
marcosptf - <marcosptf@yahoo.com.br> - @phpsp - sao paulo - br
--FILE--
<?php
function testReflectionIsArray($a = null, $b = 0, array $c, $d=true, array $e, $f=1.5, $g="", array $h, $i="#F989898") {}
function testReflectionIsArray(array $a, ?array $b, iterable $c, array|string $d) {}
$reflection = new ReflectionFunction('testReflectionIsArray');
@ -13,12 +14,7 @@ foreach ($reflection->getParameters() as $parameter) {
}
?>
--EXPECT--
bool(false)
bool(false)
bool(true)
bool(false)
bool(true)
bool(false)
bool(false)
bool(true)
bool(false)

View File

@ -2,7 +2,7 @@
ReflectionParameter::get/hasType and ReflectionType tests
--FILE--
<?php
function foo(stdClass $a, array $b, callable $c, stdClass $d = null, $e = null, string $f, bool $g, int $h, float $i, NotExisting $j) { }
function foo(stdClass $a, array $b, callable $c, string $f, bool $g, int $h, float $i, NotExisting $j, stdClass $d = null, $e = null) { }
function bar(): stdClass { return new stdClass; }
@ -120,36 +120,36 @@ bool(true)
string(8) "callable"
** Function 0 - Parameter 3
bool(true)
bool(true)
bool(false)
string(8) "stdClass"
** Function 0 - Parameter 4
bool(false)
** Function 0 - Parameter 5
bool(true)
bool(false)
bool(true)
string(6) "string"
** Function 0 - Parameter 6
** Function 0 - Parameter 4
bool(true)
bool(false)
bool(true)
string(4) "bool"
** Function 0 - Parameter 7
** Function 0 - Parameter 5
bool(true)
bool(false)
bool(true)
string(3) "int"
** Function 0 - Parameter 8
** Function 0 - Parameter 6
bool(true)
bool(false)
bool(true)
string(5) "float"
** Function 0 - Parameter 9
** Function 0 - Parameter 7
bool(true)
bool(false)
bool(false)
string(11) "NotExisting"
** Function 0 - Parameter 8
bool(true)
bool(true)
bool(false)
string(8) "stdClass"
** Function 0 - Parameter 9
bool(false)
** Function 1 - Parameter 0
bool(true)
bool(false)

View File

@ -16,7 +16,8 @@ foreach ($r->getParameters() as $p) {
}
}
?>
--EXPECT--
--EXPECTF--
Deprecated: Required parameter $c follows optional parameter $b in %s on line %d
bool(true)
bool(true)
bool(false)