@@ -6503,8 +6503,10 @@ static void zend_is_type_list_redundant_by_single_type(zend_type_list *type_list
6503
6503
}
6504
6504
}
6505
6505
6506
- static zend_type zend_compile_typename (
6507
- zend_ast * ast , bool force_allow_null ) /* {{{ */
6506
+ static zend_type zend_compile_typename (zend_ast * ast , bool force_allow_null );
6507
+
6508
+ static zend_type zend_compile_typename_ex (
6509
+ zend_ast * ast , bool force_allow_null , bool * forced_allow_null ) /* {{{ */
6508
6510
{
6509
6511
bool is_marked_nullable = ast -> attr & ZEND_TYPE_NULLABLE ;
6510
6512
zend_ast_attr orig_ast_attr = ast -> attr ;
@@ -6707,6 +6709,10 @@ static zend_type zend_compile_typename(
6707
6709
zend_error_noreturn (E_COMPILE_ERROR , "null cannot be marked as nullable" );
6708
6710
}
6709
6711
6712
+ if (force_allow_null && !is_marked_nullable && !(type_mask & MAY_BE_NULL )) {
6713
+ * forced_allow_null = true;
6714
+ }
6715
+
6710
6716
if (is_marked_nullable || force_allow_null ) {
6711
6717
ZEND_TYPE_FULL_MASK (type ) |= MAY_BE_NULL ;
6712
6718
type_mask = ZEND_TYPE_PURE_MASK (type );
@@ -6725,6 +6731,12 @@ static zend_type zend_compile_typename(
6725
6731
}
6726
6732
/* }}} */
6727
6733
6734
+ static zend_type zend_compile_typename (zend_ast * ast , bool force_allow_null )
6735
+ {
6736
+ bool forced_allow_null ;
6737
+ return zend_compile_typename_ex (ast , force_allow_null , & forced_allow_null );
6738
+ }
6739
+
6728
6740
/* May convert value from int to float. */
6729
6741
static bool zend_is_valid_default_value (zend_type type , zval * value )
6730
6742
{
@@ -6954,28 +6966,6 @@ static void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, uint32
6954
6966
zend_const_expr_to_zval (
6955
6967
& default_node .u .constant , default_ast_ptr , /* allow_dynamic */ true);
6956
6968
CG (compiler_options ) = cops ;
6957
-
6958
- if (last_required_param != (uint32_t ) -1 && i < last_required_param ) {
6959
- /* Ignore parameters of the form "Type $param = null".
6960
- * This is the PHP 5 style way of writing "?Type $param", so allow it for now. */
6961
- bool is_implicit_nullable =
6962
- type_ast && !(type_ast -> attr & ZEND_TYPE_NULLABLE )
6963
- && Z_TYPE (default_node .u .constant ) == IS_NULL ;
6964
- if (!is_implicit_nullable ) {
6965
- zend_ast * required_param_ast = list -> child [last_required_param ];
6966
- zend_error (E_DEPRECATED ,
6967
- "Optional parameter $%s declared before required parameter $%s "
6968
- "is implicitly treated as a required parameter" ,
6969
- ZSTR_VAL (name ), ZSTR_VAL (zend_ast_get_str (required_param_ast -> child [1 ])));
6970
- }
6971
-
6972
- /* Regardless of whether we issue a deprecation, convert this parameter into
6973
- * a required parameter without a default value. This ensures that it cannot be
6974
- * used as an optional parameter even with named parameters. */
6975
- opcode = ZEND_RECV ;
6976
- default_node .op_type = IS_UNUSED ;
6977
- zval_ptr_dtor (& default_node .u .constant );
6978
- }
6979
6969
} else {
6980
6970
opcode = ZEND_RECV ;
6981
6971
default_node .op_type = IS_UNUSED ;
@@ -6993,12 +6983,13 @@ static void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, uint32
6993
6983
);
6994
6984
}
6995
6985
6986
+ bool forced_allow_nullable = false;
6996
6987
if (type_ast ) {
6997
6988
uint32_t default_type = * default_ast_ptr ? Z_TYPE (default_node .u .constant ) : IS_UNDEF ;
6998
6989
bool force_nullable = default_type == IS_NULL && !property_flags ;
6999
6990
7000
6991
op_array -> fn_flags |= ZEND_ACC_HAS_TYPE_HINTS ;
7001
- arg_info -> type = zend_compile_typename (type_ast , force_nullable );
6992
+ arg_info -> type = zend_compile_typename_ex (type_ast , force_nullable , & forced_allow_nullable );
7002
6993
7003
6994
if (ZEND_TYPE_FULL_MASK (arg_info -> type ) & MAY_BE_VOID ) {
7004
6995
zend_error_noreturn (E_COMPILE_ERROR , "void cannot be used as a parameter type" );
@@ -7017,6 +7008,26 @@ static void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, uint32
7017
7008
ZSTR_VAL (name ), ZSTR_VAL (type_str ));
7018
7009
}
7019
7010
}
7011
+ if (last_required_param != (uint32_t ) -1
7012
+ && i < last_required_param
7013
+ && default_node .op_type == IS_CONST ) {
7014
+ /* Ignore parameters of the form "Type $param = null".
7015
+ * This is the PHP 5 style way of writing "?Type $param", so allow it for now. */
7016
+ if (!forced_allow_nullable ) {
7017
+ zend_ast * required_param_ast = list -> child [last_required_param ];
7018
+ zend_error (E_DEPRECATED ,
7019
+ "Optional parameter $%s declared before required parameter $%s "
7020
+ "is implicitly treated as a required parameter" ,
7021
+ ZSTR_VAL (name ), ZSTR_VAL (zend_ast_get_str (required_param_ast -> child [1 ])));
7022
+ }
7023
+
7024
+ /* Regardless of whether we issue a deprecation, convert this parameter into
7025
+ * a required parameter without a default value. This ensures that it cannot be
7026
+ * used as an optional parameter even with named parameters. */
7027
+ opcode = ZEND_RECV ;
7028
+ default_node .op_type = IS_UNUSED ;
7029
+ zval_ptr_dtor (& default_node .u .constant );
7030
+ }
7020
7031
7021
7032
opline = zend_emit_op (NULL , opcode , NULL , & default_node );
7022
7033
SET_NODE (opline -> result , & var_node );
0 commit comments