@@ -6466,7 +6466,6 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, uint32_t fall
6466
6466
uint32_t i ;
6467
6467
zend_op_array * op_array = CG (active_op_array );
6468
6468
zend_arg_info * arg_infos ;
6469
- zend_string * optional_param = NULL ;
6470
6469
6471
6470
if (return_type_ast || fallback_return_type ) {
6472
6471
/* Use op_array->arg_info[-1] for return type */
@@ -6489,6 +6488,17 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, uint32_t fall
6489
6488
arg_infos = safe_emalloc (sizeof (zend_arg_info ), list -> children , 0 );
6490
6489
}
6491
6490
6491
+ /* Find last required parameter number for deprecation message. */
6492
+ uint32_t last_required_param = (uint32_t ) -1 ;
6493
+ for (i = 0 ; i < list -> children ; ++ i ) {
6494
+ zend_ast * param_ast = list -> child [i ];
6495
+ zend_ast * default_ast_ptr = param_ast -> child [2 ];
6496
+ bool is_variadic = (param_ast -> attr & ZEND_PARAM_VARIADIC ) != 0 ;
6497
+ if (!default_ast_ptr && !is_variadic ) {
6498
+ last_required_param = i ;
6499
+ }
6500
+ }
6501
+
6492
6502
for (i = 0 ; i < list -> children ; ++ i ) {
6493
6503
zend_ast * param_ast = list -> child [i ];
6494
6504
zend_ast * type_ast = param_ast -> child [0 ];
@@ -6544,23 +6554,30 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, uint32_t fall
6544
6554
zend_const_expr_to_zval (& default_node .u .constant , default_ast_ptr );
6545
6555
CG (compiler_options ) = cops ;
6546
6556
6547
- if (! optional_param ) {
6557
+ if (last_required_param != ( uint32_t ) -1 && i < last_required_param ) {
6548
6558
/* Ignore parameters of the form "Type $param = null".
6549
6559
* This is the PHP 5 style way of writing "?Type $param", so allow it for now. */
6550
6560
bool is_implicit_nullable =
6551
6561
type_ast && Z_TYPE (default_node .u .constant ) == IS_NULL ;
6552
6562
if (!is_implicit_nullable ) {
6553
- optional_param = name ;
6563
+ zend_ast * required_param_ast = list -> child [last_required_param ];
6564
+ zend_error (E_DEPRECATED ,
6565
+ "Optional parameter $%s declared before required parameter $%s "
6566
+ "is implicitly treated as a required parameter" ,
6567
+ ZSTR_VAL (name ), ZSTR_VAL (zend_ast_get_str (required_param_ast -> child [1 ])));
6554
6568
}
6569
+
6570
+ /* Regardless of whether we issue a deprecation, convert this parameter into
6571
+ * a required parameter without a default value. This ensures that it cannot be
6572
+ * used as an optional parameter even with named parameters. */
6573
+ opcode = ZEND_RECV ;
6574
+ default_node .op_type = IS_UNUSED ;
6575
+ zval_ptr_dtor (& default_node .u .constant );
6555
6576
}
6556
6577
} else {
6557
6578
opcode = ZEND_RECV ;
6558
6579
default_node .op_type = IS_UNUSED ;
6559
6580
op_array -> required_num_args = i + 1 ;
6560
- if (optional_param ) {
6561
- zend_error (E_DEPRECATED , "Required parameter $%s follows optional parameter $%s" ,
6562
- ZSTR_VAL (name ), ZSTR_VAL (optional_param ));
6563
- }
6564
6581
}
6565
6582
6566
6583
arg_info = & arg_infos [i ];
0 commit comments