]> granicus.if.org Git - php/commitdiff
Improved type hinting:
authorDmitry Stogov <dmitry@zend.com>
Fri, 20 Mar 2015 13:04:04 +0000 (16:04 +0300)
committerDmitry Stogov <dmitry@zend.com>
Fri, 20 Mar 2015 13:04:04 +0000 (16:04 +0300)
EX_PREV_USES_STRICT_TYPES() and family changed/renamed to fit with other macros
Optimized zend_verify_internal_arg_type() and family (they don't need "strict" argument anymore)
Standerd ZPP is called from VM only for weak type check or strict exception (int -> double)
Fixed ZEND_RECV_VARIADIC
Fixed ZEND_STRLEN

TODO: should we accept IS_NULL for non-nullable arguments?

Zend/zend_API.c
Zend/zend_API.h
Zend/zend_compile.h
Zend/zend_execute.c
Zend/zend_vm_def.h
Zend/zend_vm_execute.h

index 1ef695dd4e932d69be1a794ddb4c1327a9c86a7d..c626a8ddd7e3ef3857fbb7ac37202c5b073d16ae 100644 (file)
@@ -151,7 +151,7 @@ ZEND_API int zend_copy_parameters_array(int param_count, zval *argument_array) /
 
 ZEND_API void zend_wrong_param_count(void) /* {{{ */
 {
-       if (EX_PREV_USES_STRICT_TYPES()) {
+       if (ZEND_ARG_USES_STRICT_TYPES()) {
                zend_wrong_param_count_ex(1);
        } else {
                zend_wrong_param_count_ex(0);
@@ -802,7 +802,7 @@ ZEND_API int zend_parse_parameters_ex(int flags, int num_args, const char *type_
        va_list va;
        int retval;
 
-       if (EX_PREV_USES_STRICT_TYPES()) {
+       if (ZEND_ARG_USES_STRICT_TYPES()) {
                flags |= ZEND_PARSE_PARAMS_STRICT;
        }
 
@@ -822,7 +822,7 @@ ZEND_API int zend_parse_parameters(int num_args, const char *type_spec, ...) /*
        int retval;
        int flags = 0;
 
-       if (EX_PREV_USES_STRICT_TYPES()) {
+       if (ZEND_ARG_USES_STRICT_TYPES()) {
                flags |= ZEND_PARSE_PARAMS_STRICT;
        }
 
@@ -851,7 +851,7 @@ ZEND_API int zend_parse_method_parameters(int num_args, zval *this_ptr, const ch
         * wrong branch here. */
        zend_bool is_method = EG(current_execute_data)->func->common.scope != NULL;
 
-       if (EX_PREV_USES_STRICT_TYPES()) {
+       if (ZEND_ARG_USES_STRICT_TYPES()) {
                flags |= ZEND_PARSE_PARAMS_STRICT;
        }
 
@@ -891,7 +891,7 @@ ZEND_API int zend_parse_method_parameters_ex(int flags, int num_args, zval *this
        zval **object;
        zend_class_entry *ce;
 
-       if (EX_PREV_USES_STRICT_TYPES()) {
+       if (ZEND_ARG_USES_STRICT_TYPES()) {
                flags |= ZEND_PARSE_PARAMS_STRICT;
        }
 
index e0f39e98a21423a820762fa3df1b18ded32cbef0..4da7002477ae43954346103893c9330dba624529 100644 (file)
@@ -720,7 +720,7 @@ ZEND_API void zend_wrong_callback_error(int severity, int num, char *error, zend
 #define ZPP_ERROR_WRONG_COUNT    5
 
 #define ZEND_PARSE_PARAMETERS_START_EX(flags, min_num_args, max_num_args) do { \
-               zend_bool _strict = EX_PREV_USES_STRICT_TYPES(); \
+               zend_bool _strict = ZEND_ARG_USES_STRICT_TYPES(); \
                const int _flags = (flags) | (_strict ? ZEND_PARSE_PARAMS_STRICT : 0); \
                int _min_num_args = (min_num_args); \
                int _max_num_args = (max_num_args); \
index cedd5d680895cd89489b1fb04ceb2a1bcaa030b1..c53833f1498aedd26246d4911bb1c262c1159976 100644 (file)
@@ -462,9 +462,19 @@ struct _zend_execute_data {
 #define EX_CALL_KIND()                 ZEND_CALL_KIND(execute_data)
 #define EX_NUM_ARGS()                  ZEND_CALL_NUM_ARGS(execute_data)
 
-#define EX_USES_STRICT_TYPES()         _EX_USES_STRICT_TYPES(EG(current_execute_data))
-#define EX_PREV_USES_STRICT_TYPES()    _EX_USES_STRICT_TYPES(EG(current_execute_data)->prev_execute_data)
-#define _EX_USES_STRICT_TYPES(ex_data) ((ex_data) && (ex_data)->func && ZEND_USER_CODE((ex_data)->func->type) && ((ex_data)->func->op_array.fn_flags & ZEND_ACC_STRICT_TYPES) ? 1 : 0)
+#define ZEND_CALL_USES_STRICT_TYPES(call) \
+       (((call)->func->common.fn_flags & ZEND_ACC_STRICT_TYPES) != 0)
+
+#define EX_USES_STRICT_TYPES() \
+       ZEND_CALL_USES_STRICT_TYPES(execute_data)
+
+#define ZEND_ARG_USES_STRICT_TYPES() \
+       (EG(current_execute_data)->prev_execute_data && \
+        EG(current_execute_data)->prev_execute_data->func && \
+        ZEND_CALL_USES_STRICT_TYPES(EG(current_execute_data)->prev_execute_data))
+
+#define ZEND_RET_USES_STRICT_TYPES() \
+       ZEND_CALL_USES_STRICT_TYPES(EG(current_execute_data))
 
 #define EX_VAR(n)                              ZEND_CALL_VAR(execute_data, n)
 #define EX_VAR_NUM(n)                  ZEND_CALL_VAR_NUM(execute_data, n)
index 699c1ca3ded0361d29b7f26edc8ec1b356ab5bfd..b98d7cec4705ada8d2c5d9e76c432705f494fcee 100644 (file)
@@ -651,8 +651,10 @@ static int is_null_constant(zval *default_value)
        return 0;
 }
 
-static zend_bool zend_verify_scalar_type_hint(zend_uchar type_hint, zval *arg, zend_bool strict)
+static zend_bool zend_verify_weak_scalar_type_hint(zend_uchar type_hint, zval *arg)
 {
+       zend_bool strict = 0;
+
        switch (type_hint) {
                case _IS_BOOL: {
                        zend_bool dest;
@@ -698,24 +700,24 @@ static zend_bool zend_verify_scalar_type_hint(zend_uchar type_hint, zval *arg, z
        }
 }
 
-static inline int zend_verify_scalar_type_error(zend_uchar type_hint, zend_uchar allow_null, zval *arg, zval *default_value, zend_bool strict)
+static zend_bool zend_verify_scalar_type_hint(zend_uchar type_hint, zval *arg, zend_bool strict)
 {
-       if (UNEXPECTED(!ZEND_SAME_FAKE_TYPE(type_hint,  Z_TYPE_P(arg)))) {
-               if (Z_TYPE_P(arg) == IS_NULL) {
-                       if (!allow_null && (!default_value || !is_null_constant(default_value))) {
-                               return 1;
-                       }
-               } else if (!zend_verify_scalar_type_hint(type_hint, arg, strict)) {
-                       return 1;
+       if (UNEXPECTED(strict)) {
+               /* SSTH Exception: IS_LONG ma be accepted instead as IS_DOUBLE */
+               if (type_hint != IS_DOUBLE || Z_TYPE_P(arg) != IS_LONG) {
+                       return 0;
                }
+       } else if (UNEXPECTED(Z_TYPE_P(arg) == IS_NULL)) {
+               /* FIXME: Is this exception on purpose ??? */
+               return 0;
        }
-       return 0;
+       return zend_verify_weak_scalar_type_hint(type_hint, arg);
 }
 
-static void zend_verify_internal_arg_type(zend_function *zf, uint32_t arg_num, zval *arg, zend_bool strict)
+static void zend_verify_internal_arg_type(zend_function *zf, uint32_t arg_num, zval *arg)
 {
        zend_internal_arg_info *cur_arg_info;
-       char *need_msg;
+       char *need_msg, *class_name;
        zend_class_entry *ce;
 
        if (EXPECTED(arg_num <= zf->internal_function.num_args)) {
@@ -726,39 +728,37 @@ static void zend_verify_internal_arg_type(zend_function *zf, uint32_t arg_num, z
                return;
        }
 
-       if (cur_arg_info->class_name) {
-               char *class_name;
-
+       if (cur_arg_info->type_hint) {
                ZVAL_DEREF(arg);
-               if (Z_TYPE_P(arg) == IS_OBJECT) {
-                       need_msg = zend_verify_internal_arg_class_kind((zend_internal_arg_info*)cur_arg_info, &class_name, &ce);
-                       if (!ce || !instanceof_function(Z_OBJCE_P(arg), ce)) {
-                               zend_verify_arg_error(zf, arg_num, need_msg, class_name, "instance of ", Z_OBJCE_P(arg)->name->val, arg);
+               if (EXPECTED(cur_arg_info->type_hint == Z_TYPE_P(arg))) {
+                       if (cur_arg_info->class_name) {
+                               need_msg = zend_verify_internal_arg_class_kind((zend_internal_arg_info*)cur_arg_info, &class_name, &ce);
+                               if (!ce || !instanceof_function(Z_OBJCE_P(arg), ce)) {
+                                       zend_verify_arg_error(zf, arg_num, need_msg, class_name, "instance of ", Z_OBJCE_P(arg)->name->val, arg);
+                               }
                        }
                } else if (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null) {
-                       need_msg = zend_verify_internal_arg_class_kind((zend_internal_arg_info*)cur_arg_info, &class_name, &ce);
-                       zend_verify_arg_error(zf, arg_num, need_msg, class_name, zend_zval_type_name(arg), "", arg);
-               }
-       } else if (cur_arg_info->type_hint) {
-               ZVAL_DEREF(arg);
-               if (cur_arg_info->type_hint == IS_ARRAY) {
-                       if (Z_TYPE_P(arg) != IS_ARRAY && (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null)) {
-                               zend_verify_arg_error(zf, arg_num, "be of the type array", "", zend_zval_type_name(arg), "", arg);
-                       }
-               } else if (cur_arg_info->type_hint == IS_CALLABLE) {
-                       if (!zend_is_callable(arg, IS_CALLABLE_CHECK_SILENT, NULL) && (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null)) {
-                               zend_verify_arg_error(zf, arg_num, "be callable", "", zend_zval_type_name(arg), "", arg);
+                       if (cur_arg_info->class_name) {
+                               need_msg = zend_verify_internal_arg_class_kind((zend_internal_arg_info*)cur_arg_info, &class_name, &ce);
+                               zend_verify_arg_error(zf, arg_num, need_msg, class_name, zend_zval_type_name(arg), "", arg);
+                       } else if (cur_arg_info->type_hint == IS_CALLABLE) {
+                               if (!zend_is_callable(arg, IS_CALLABLE_CHECK_SILENT, NULL)) {
+                                       zend_verify_arg_error(zf, arg_num, "be callable", "", zend_zval_type_name(arg), "", arg);
+                               }
+                       } else if (cur_arg_info->type_hint == _IS_BOOL &&
+                                  EXPECTED(Z_TYPE_P(arg) == IS_FALSE || Z_TYPE_P(arg) == IS_TRUE)) {
+                               /* pass */
+                       } else if (UNEXPECTED(!zend_verify_scalar_type_hint(cur_arg_info->type_hint, arg, ZEND_CALL_USES_STRICT_TYPES(EG(current_execute_data))))) {
+                               zend_verify_arg_error(zf, arg_num, "be of the type ", zend_get_type_by_const(cur_arg_info->type_hint), zend_zval_type_name(arg), "", arg);
                        }
-               } else if (UNEXPECTED(zend_verify_scalar_type_error(cur_arg_info->type_hint, cur_arg_info->allow_null, arg, NULL, strict))) {
-                       zend_verify_arg_error(zf, arg_num, "be of the type ", zend_get_type_by_const(cur_arg_info->type_hint), zend_zval_type_name(arg), "", arg);
                }
        }
 }
 
-static void zend_verify_arg_type(zend_function *zf, uint32_t arg_num, zval *arg, zval *default_value, zend_bool strict)
+static void zend_verify_arg_type(zend_function *zf, uint32_t arg_num, zval *arg, zval *default_value)
 {
        zend_arg_info *cur_arg_info;
-       char *need_msg;
+       char *need_msg, *class_name;
        zend_class_entry *ce;
 
        if (EXPECTED(arg_num <= zf->common.num_args)) {
@@ -769,31 +769,29 @@ static void zend_verify_arg_type(zend_function *zf, uint32_t arg_num, zval *arg,
                return;
        }
 
-       if (cur_arg_info->class_name) {
-               char *class_name;
-
+       if (cur_arg_info->type_hint) {
                ZVAL_DEREF(arg);
-               if (Z_TYPE_P(arg) == IS_OBJECT) {
-                       need_msg = zend_verify_arg_class_kind(cur_arg_info, &class_name, &ce);
-                       if (!ce || !instanceof_function(Z_OBJCE_P(arg), ce)) {
-                               zend_verify_arg_error(zf, arg_num, need_msg, class_name, "instance of ", Z_OBJCE_P(arg)->name->val, arg);
+               if (EXPECTED(cur_arg_info->type_hint == Z_TYPE_P(arg))) {
+                       if (cur_arg_info->class_name) {
+                               need_msg = zend_verify_arg_class_kind(cur_arg_info, &class_name, &ce);
+                               if (!ce || !instanceof_function(Z_OBJCE_P(arg), ce)) {
+                                       zend_verify_arg_error(zf, arg_num, need_msg, class_name, "instance of ", Z_OBJCE_P(arg)->name->val, arg);
+                               }
                        }
                } else if (Z_TYPE_P(arg) != IS_NULL || !(cur_arg_info->allow_null || (default_value && is_null_constant(default_value)))) {
-                       need_msg = zend_verify_arg_class_kind(cur_arg_info, &class_name, &ce);
-                       zend_verify_arg_error(zf, arg_num, need_msg, class_name, zend_zval_type_name(arg), "", arg);
-               }
-       } else if (cur_arg_info->type_hint) {
-               ZVAL_DEREF(arg);
-               if (cur_arg_info->type_hint == IS_ARRAY) {
-                       if (Z_TYPE_P(arg) != IS_ARRAY && (Z_TYPE_P(arg) != IS_NULL || !(cur_arg_info->allow_null || (default_value && is_null_constant(default_value))))) {
-                               zend_verify_arg_error(zf, arg_num, "be of the type array", "", zend_zval_type_name(arg), "", arg);
-                       }
-               } else if (cur_arg_info->type_hint == IS_CALLABLE) {
-                       if (!zend_is_callable(arg, IS_CALLABLE_CHECK_SILENT, NULL) && (Z_TYPE_P(arg) != IS_NULL || !(cur_arg_info->allow_null || (default_value && is_null_constant(default_value))))) {
-                               zend_verify_arg_error(zf, arg_num, "be callable", "", zend_zval_type_name(arg), "", arg);
+                       if (cur_arg_info->class_name) {
+                               need_msg = zend_verify_arg_class_kind(cur_arg_info, &class_name, &ce);
+                               zend_verify_arg_error(zf, arg_num, need_msg, class_name, zend_zval_type_name(arg), "", arg);
+                       } else if (cur_arg_info->type_hint == IS_CALLABLE) {
+                               if (!zend_is_callable(arg, IS_CALLABLE_CHECK_SILENT, NULL)) {
+                                       zend_verify_arg_error(zf, arg_num, "be callable", "", zend_zval_type_name(arg), "", arg);
+                               }
+                       } else if (cur_arg_info->type_hint == _IS_BOOL &&
+                                  EXPECTED(Z_TYPE_P(arg) == IS_FALSE || Z_TYPE_P(arg) == IS_TRUE)) {
+                               /* pass */
+                       } else if (UNEXPECTED(!zend_verify_scalar_type_hint(cur_arg_info->type_hint, arg, ZEND_ARG_USES_STRICT_TYPES()))) {
+                               zend_verify_arg_error(zf, arg_num, "be of the type ", zend_get_type_by_const(cur_arg_info->type_hint), zend_zval_type_name(arg), "", arg);
                        }
-               } else if (UNEXPECTED(zend_verify_scalar_type_error(cur_arg_info->type_hint, cur_arg_info->allow_null, arg, default_value, strict))) {
-                       zend_verify_arg_error(zf, arg_num, "be of the type ", zend_get_type_by_const(cur_arg_info->type_hint), zend_zval_type_name(arg), "", arg);
                }
        }
 }
@@ -812,15 +810,13 @@ static inline int zend_verify_missing_arg_type(zend_function *zf, uint32_t arg_n
                return 1;
        }
 
-       if (cur_arg_info->class_name) {
-               char *class_name;
+       if (cur_arg_info->type_hint) {
+               if (cur_arg_info->class_name) {
+                       char *class_name;
 
-               need_msg = zend_verify_arg_class_kind(cur_arg_info, &class_name, &ce);
-               zend_verify_arg_error(zf, arg_num, need_msg, class_name, "none", "", NULL);
-               return 0;
-       } else if (cur_arg_info->type_hint) {
-               if (cur_arg_info->type_hint == IS_ARRAY) {
-                       zend_verify_arg_error(zf, arg_num, "be of the type array", "", "none", "", NULL);
+                       need_msg = zend_verify_arg_class_kind(cur_arg_info, &class_name, &ce);
+                       zend_verify_arg_error(zf, arg_num, need_msg, class_name, "none", "", NULL);
+                       return 0;
                } else if (cur_arg_info->type_hint == IS_CALLABLE) {
                        zend_verify_arg_error(zf, arg_num, "be callable", "", "none", "", NULL);
                } else {
@@ -891,75 +887,73 @@ ZEND_API void zend_verify_internal_return_error(const zend_function *zf, const c
 }
 
 #if ZEND_DEBUG
-static int zend_verify_internal_return_type(zend_function *zf, zval *ret, zend_bool strict)
+static int zend_verify_internal_return_type(zend_function *zf, zval *ret)
 {
        zend_arg_info *ret_info = zf->common.arg_info - 1;
-       char *need_msg;
+       char *need_msg, *class_name;
        zend_class_entry *ce;
 
-       if (ret_info->class_name) {
-               char *class_name;
 
-               if (Z_TYPE_P(ret) == IS_OBJECT) {
-                       need_msg = zend_verify_internal_arg_class_kind((zend_internal_arg_info *)ret_info, &class_name, &ce);
-                       if (!ce || !instanceof_function(Z_OBJCE_P(ret), ce)) {
-                               zend_verify_internal_return_error(zf, need_msg, class_name, "instance of ", Z_OBJCE_P(ret)->name->val);
-                               return 0;
+       if (ret_info->type_hint) {
+               if (EXPECTED(ret_info->type_hint == Z_TYPE_P(ret))) {
+                       if (ret_info->class_name) {
+                               need_msg = zend_verify_internal_arg_class_kind((zend_internal_arg_info *)ret_info, &class_name, &ce);
+                               if (!ce || !instanceof_function(Z_OBJCE_P(ret), ce)) {
+                                       zend_verify_internal_return_error(zf, need_msg, class_name, "instance of ", Z_OBJCE_P(ret)->name->val);
+                                       return 0;
+                               }
                        }
                } else if (Z_TYPE_P(ret) != IS_NULL || !ret_info->allow_null) {
-                       need_msg = zend_verify_internal_arg_class_kind((zend_internal_arg_info *)ret_info, &class_name, &ce);
-                       zend_verify_internal_return_error(zf, need_msg, class_name, zend_zval_type_name(ret), "");
-                       return 0;
-               }
-       } else if (ret_info->type_hint) {
-               if (ret_info->type_hint == IS_ARRAY) {
-                       if (Z_TYPE_P(ret) != IS_ARRAY && (Z_TYPE_P(ret) != IS_NULL || !ret_info->allow_null)) {
-                               zend_verify_internal_return_error(zf, "be of the type array", "", zend_zval_type_name(ret), "");
-                               return 0;
-                       }
-               } else if (ret_info->type_hint == IS_CALLABLE) {
-                       if (!zend_is_callable(ret, IS_CALLABLE_CHECK_SILENT, NULL) && (Z_TYPE_P(ret) != IS_NULL || !ret_info->allow_null)) {
-                               zend_verify_internal_return_error(zf, "be callable", "", zend_zval_type_name(ret), "");
+                       if (ret_info->class_name) {
+                               need_msg = zend_verify_internal_arg_class_kind((zend_internal_arg_info *)ret_info, &class_name, &ce);
+                               zend_verify_internal_return_error(zf, need_msg, class_name, zend_zval_type_name(ret), "");
+                       } else if (ret_info->type_hint == IS_CALLABLE) {
+                               if (!zend_is_callable(ret, IS_CALLABLE_CHECK_SILENT, NULL) && (Z_TYPE_P(ret) != IS_NULL || !ret_info->allow_null)) {
+                                       zend_verify_internal_return_error(zf, "be callable", "", zend_zval_type_name(ret), "");
+                                       return 0;
+                               }
+                       } else if (ret_info->type_hint == _IS_BOOL &&
+                                  EXPECTED(Z_TYPE_P(ret) == IS_FALSE || Z_TYPE_P(ret) == IS_TRUE)) {
+                               /* pass */
+                       } else {
+                               /* Use strict check to verify return value of internal function */
+                               zend_verify_internal_return_error(zf, "be of the type ", zend_get_type_by_const(ret_info->type_hint), zend_zval_type_name(ret), "");
                                return 0;
                        }
-               } else if (UNEXPECTED(zend_verify_scalar_type_error(ret_info->type_hint, ret_info->allow_null, ret, NULL, strict))) {
-                       zend_verify_internal_return_error(zf, "be of the type ", zend_get_type_by_const(ret_info->type_hint), zend_zval_type_name(ret), "");
-                       return 0;
                }
        }
        return 1;
 }
 #endif
 
-static void zend_verify_return_type(zend_function *zf, zval *ret, zend_bool strict)
+static void zend_verify_return_type(zend_function *zf, zval *ret)
 {
        zend_arg_info *ret_info = zf->common.arg_info - 1;
-       char *need_msg;
+       char *need_msg, *class_name;
        zend_class_entry *ce;
 
-       if (ret_info->class_name) {
-               char *class_name;
-
-               if (Z_TYPE_P(ret) == IS_OBJECT) {
-                       need_msg = zend_verify_arg_class_kind(ret_info, &class_name, &ce);
-                       if (!ce || !instanceof_function(Z_OBJCE_P(ret), ce)) {
-                               zend_verify_return_error(zf, need_msg, class_name, "instance of ", Z_OBJCE_P(ret)->name->val);
+       if (ret_info->type_hint) {
+               if (EXPECTED(ret_info->type_hint == Z_TYPE_P(ret))) {
+                       if (ret_info->class_name) {
+                               need_msg = zend_verify_arg_class_kind(ret_info, &class_name, &ce);
+                               if (!ce || !instanceof_function(Z_OBJCE_P(ret), ce)) {
+                                       zend_verify_return_error(zf, need_msg, class_name, "instance of ", Z_OBJCE_P(ret)->name->val);
+                               }
                        }
                } else if (Z_TYPE_P(ret) != IS_NULL || !ret_info->allow_null) {
-                       need_msg = zend_verify_arg_class_kind(ret_info, &class_name, &ce);
-                       zend_verify_return_error(zf, need_msg, class_name, zend_zval_type_name(ret), "");
-               }
-       } else if (ret_info->type_hint) {
-               if (ret_info->type_hint == IS_ARRAY) {
-                       if (Z_TYPE_P(ret) != IS_ARRAY && (Z_TYPE_P(ret) != IS_NULL || !ret_info->allow_null)) {
-                               zend_verify_return_error(zf, "be of the type array", "", zend_zval_type_name(ret), "");
-                       }
-               } else if (ret_info->type_hint == IS_CALLABLE) {
-                       if (!zend_is_callable(ret, IS_CALLABLE_CHECK_SILENT, NULL) && (Z_TYPE_P(ret) != IS_NULL || !ret_info->allow_null)) {
-                               zend_verify_return_error(zf, "be callable", "", zend_zval_type_name(ret), "");
+                       if (ret_info->class_name) {
+                               need_msg = zend_verify_arg_class_kind(ret_info, &class_name, &ce);
+                               zend_verify_return_error(zf, need_msg, class_name, zend_zval_type_name(ret), "");
+                       } else if (ret_info->type_hint == IS_CALLABLE) {
+                               if (!zend_is_callable(ret, IS_CALLABLE_CHECK_SILENT, NULL)) {
+                                       zend_verify_return_error(zf, "be callable", "", zend_zval_type_name(ret), "");
+                               }
+                       } else if (ret_info->type_hint == _IS_BOOL &&
+                                  EXPECTED(Z_TYPE_P(ret) == IS_FALSE || Z_TYPE_P(ret) == IS_TRUE)) {
+                               /* pass */
+                       } else if (UNEXPECTED(!zend_verify_scalar_type_hint(ret_info->type_hint, ret, ZEND_RET_USES_STRICT_TYPES()))) {
+                               zend_verify_return_error(zf, "be of the type ", zend_get_type_by_const(ret_info->type_hint), zend_zval_type_name(ret), "");
                        }
-               } else if (UNEXPECTED(zend_verify_scalar_type_error(ret_info->type_hint, ret_info->allow_null, ret, NULL, strict))) {
-                       zend_verify_return_error(zf, "be of the type ", zend_get_type_by_const(ret_info->type_hint), zend_zval_type_name(ret), "");
                }
        }
 }
@@ -970,15 +964,13 @@ static inline int zend_verify_missing_return_type(zend_function *zf)
        char *need_msg;
        zend_class_entry *ce;
 
-       if (ret_info->class_name) {
-               char *class_name;
+       if (ret_info->type_hint) {
+               if (ret_info->class_name) {
+                       char *class_name;
 
-               need_msg = zend_verify_arg_class_kind(ret_info, &class_name, &ce);
-               zend_verify_return_error(zf, need_msg, class_name, "none", "");
-               return 0;
-       } else if (ret_info->type_hint) {
-               if (ret_info->type_hint == IS_ARRAY) {
-                       zend_verify_return_error(zf, "be of the type array", "", "none", "");
+                       need_msg = zend_verify_arg_class_kind(ret_info, &class_name, &ce);
+                       zend_verify_return_error(zf, need_msg, class_name, "none", "");
+                       return 0;
                } else if (ret_info->type_hint == IS_CALLABLE) {
                        zend_verify_return_error(zf, "be callable", "", "none", "");
                } else {
index 2cc3588606cd9eaf920f867d540f42518d23c1c7..fd586e79cb71986f9ef16bcf894959130923f851 100644 (file)
@@ -3232,7 +3232,7 @@ ZEND_VM_HANDLER(129, ZEND_DO_ICALL, ANY, ANY)
        ZEND_ASSERT(
                !call->func ||
                !(call->func->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) ||
-               zend_verify_internal_return_type(call->func, EX_VAR(opline->result.var), EX_USES_STRICT_TYPES()));
+               zend_verify_internal_return_type(call->func, EX_VAR(opline->result.var)));
 
        EG(current_execute_data) = call->prev_execute_data;
        zend_vm_stack_free_args(call);
@@ -3339,7 +3339,7 @@ ZEND_VM_HANDLER(131, ZEND_DO_FCALL_BY_NAME, ANY, ANY)
                        zval *p = ZEND_CALL_ARG(call, 1);
 
                        for (i = 0; i < num_args; ++i) {
-                               zend_verify_internal_arg_type(fbc, i + 1, p, EX_USES_STRICT_TYPES());
+                               zend_verify_internal_arg_type(fbc, i + 1, p);
                                p++;
                        }
                        if (UNEXPECTED(EG(exception) != NULL)) {
@@ -3360,7 +3360,7 @@ ZEND_VM_HANDLER(131, ZEND_DO_FCALL_BY_NAME, ANY, ANY)
                ZEND_ASSERT(
                        !call->func ||
                        !(call->func->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) ||
-                       zend_verify_internal_return_type(call->func, EX_VAR(opline->result.var), EX_USES_STRICT_TYPES()));
+                       zend_verify_internal_return_type(call->func, EX_VAR(opline->result.var)));
 
                EG(current_execute_data) = call->prev_execute_data;
                zend_vm_stack_free_args(call);
@@ -3465,7 +3465,7 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY)
                        zval *p = ZEND_CALL_ARG(call, 1);
 
                        for (i = 0; i < num_args; ++i) {
-                               zend_verify_internal_arg_type(fbc, i + 1, p, EX_USES_STRICT_TYPES());
+                               zend_verify_internal_arg_type(fbc, i + 1, p);
                                if (UNEXPECTED(EG(exception) != NULL)) {
                                        EG(current_execute_data) = call->prev_execute_data;
                                        zend_vm_stack_free_args(call);
@@ -3497,7 +3497,7 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY)
                ZEND_ASSERT(
                        !call->func ||
                        !(call->func->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) ||
-                       zend_verify_internal_return_type(call->func, EX_VAR(opline->result.var), EX_USES_STRICT_TYPES()));
+                       zend_verify_internal_return_type(call->func, EX_VAR(opline->result.var)));
 
                EG(current_execute_data) = call->prev_execute_data;
                zend_vm_stack_free_args(call);
@@ -3615,7 +3615,7 @@ ZEND_VM_HANDLER(124, ZEND_VERIFY_RETURN_TYPE, CONST|TMP|VAR|UNUSED|CV, UNUSED)
                        }
                }
 
-               zend_verify_return_type(EX(func), retval_ptr, EX_USES_STRICT_TYPES());
+               zend_verify_return_type(EX(func), retval_ptr);
 #endif
        }
        CHECK_EXCEPTION();
@@ -4387,7 +4387,7 @@ ZEND_VM_HANDLER(63, ZEND_RECV, ANY, ANY)
        } else if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) {
                zval *param = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var);
 
-               zend_verify_arg_type(EX(func), arg_num, param, NULL, EX_PREV_USES_STRICT_TYPES());
+               zend_verify_arg_type(EX(func), arg_num, param, NULL);
                CHECK_EXCEPTION();
        }
 
@@ -4415,7 +4415,7 @@ ZEND_VM_HANDLER(64, ZEND_RECV_INIT, ANY, CONST)
        }
 
        if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) {
-               zend_verify_arg_type(EX(func), arg_num, param, EX_CONSTANT(opline->op2), EX_PREV_USES_STRICT_TYPES());
+               zend_verify_arg_type(EX(func), arg_num, param, EX_CONSTANT(opline->op2));
        }
 
        CHECK_EXCEPTION();
@@ -4442,7 +4442,7 @@ ZEND_VM_HANDLER(164, ZEND_RECV_VARIADIC, ANY, ANY)
                        param = EX_VAR_NUM(EX(func)->op_array.last_var + EX(func)->op_array.T);
                        if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) {
                                do {
-                                       zend_verify_arg_type(EX(func), arg_num, param, NULL, EX_USES_STRICT_TYPES());
+                                       zend_verify_arg_type(EX(func), arg_num, param, NULL);
                                        if (Z_OPT_REFCOUNTED_P(param)) Z_ADDREF_P(param);
                                        ZEND_HASH_FILL_ADD(param);
                                        param++;
@@ -7268,35 +7268,42 @@ ZEND_VM_HANDLER(121, ZEND_STRLEN, CONST|TMPVAR|CV, ANY)
 ZEND_VM_C_LABEL(try_strlen):
        if (EXPECTED(Z_TYPE_P(value) == IS_STRING)) {
                ZVAL_LONG(EX_VAR(opline->result.var), Z_STRLEN_P(value));
-       } else if (EXPECTED(!EX_USES_STRICT_TYPES())) {
+       } else {
+               zend_bool strict;
+
                if ((OP1_TYPE & (IS_VAR|IS_CV)) && Z_TYPE_P(value) == IS_REFERENCE) {
                        value = Z_REFVAL_P(value);
                        ZEND_VM_C_GOTO(try_strlen);
-               } else if (Z_TYPE_P(value) < IS_TRUE) {
-                       ZVAL_LONG(EX_VAR(opline->result.var), 0);
-               } else if (Z_TYPE_P(value) == IS_TRUE) {
-                       ZVAL_LONG(EX_VAR(opline->result.var), 1);
-               } else if (Z_TYPE_P(value) <= IS_DOUBLE) {
-                       zend_string *str = zval_get_string(value);
-                       ZVAL_LONG(EX_VAR(opline->result.var), str->len);
-                       zend_string_release(str);
-               } else if (Z_TYPE_P(value) == IS_OBJECT) {
-                       zend_string *str;
-                       zval tmp;
-
-                       ZVAL_COPY(&tmp, value);
-                       if (parse_arg_object_to_str(&tmp, &str, IS_STRING) == FAILURE) {
-                               ZEND_VM_C_GOTO(strlen_error);
-                       }
-                       ZVAL_LONG(EX_VAR(opline->result.var), str->len);
-                       zval_dtor(&tmp);
-               } else {
-ZEND_VM_C_LABEL(strlen_error):
-                       zend_internal_type_error(0, "strlen() expects parameter 1 to be string, %s given", zend_get_type_by_const(Z_TYPE_P(value)));
-                       ZVAL_NULL(EX_VAR(opline->result.var));
                }
-       } else {
-               zend_internal_type_error(1, "strlen() expects parameter 1 to be string, %s given", zend_get_type_by_const(Z_TYPE_P(value)));
+               strict = EX_USES_STRICT_TYPES();
+               do {
+                       if (EXPECTED(!strict)) {
+                               if (Z_TYPE_P(value) < IS_TRUE) {
+                                       ZVAL_LONG(EX_VAR(opline->result.var), 0);
+                                       break;
+                               } else if (Z_TYPE_P(value) == IS_TRUE) {
+                                       ZVAL_LONG(EX_VAR(opline->result.var), 1);
+                                       break;
+                               } else if (Z_TYPE_P(value) <= IS_DOUBLE) {
+                                       zend_string *str = zval_get_string(value);
+                                       ZVAL_LONG(EX_VAR(opline->result.var), str->len);
+                                       zend_string_release(str);
+                                       break;
+                               } else if (Z_TYPE_P(value) == IS_OBJECT) {
+                                       zend_string *str;
+                                       zval tmp;
+
+                                       ZVAL_COPY(&tmp, value);
+                                       if (parse_arg_object_to_str(&tmp, &str, IS_STRING) == SUCCESS) {
+                                               ZVAL_LONG(EX_VAR(opline->result.var), str->len);
+                                               zval_dtor(&tmp);
+                                               break;
+                                       }
+                               }
+                       }
+                       zend_internal_type_error(strict, "strlen() expects parameter 1 to be string, %s given", zend_get_type_by_const(Z_TYPE_P(value)));
+                       ZVAL_NULL(EX_VAR(opline->result.var));
+               } while (0);
        }
        FREE_OP1();
        CHECK_EXCEPTION();
index 2ee2cf4d53cae0bdb970442ffbd985595fe21999..ebc21017ac0372cefa97ea2e90a7f44caef66a27 100644 (file)
@@ -563,7 +563,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_ICALL_SPEC_HANDLER(ZEND_OPC
        ZEND_ASSERT(
                !call->func ||
                !(call->func->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) ||
-               zend_verify_internal_return_type(call->func, EX_VAR(opline->result.var), EX_USES_STRICT_TYPES()));
+               zend_verify_internal_return_type(call->func, EX_VAR(opline->result.var)));
 
        EG(current_execute_data) = call->prev_execute_data;
        zend_vm_stack_free_args(call);
@@ -670,7 +670,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER(
                        zval *p = ZEND_CALL_ARG(call, 1);
 
                        for (i = 0; i < num_args; ++i) {
-                               zend_verify_internal_arg_type(fbc, i + 1, p, EX_USES_STRICT_TYPES());
+                               zend_verify_internal_arg_type(fbc, i + 1, p);
                                p++;
                        }
                        if (UNEXPECTED(EG(exception) != NULL)) {
@@ -691,7 +691,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER(
                ZEND_ASSERT(
                        !call->func ||
                        !(call->func->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) ||
-                       zend_verify_internal_return_type(call->func, EX_VAR(opline->result.var), EX_USES_STRICT_TYPES()));
+                       zend_verify_internal_return_type(call->func, EX_VAR(opline->result.var)));
 
                EG(current_execute_data) = call->prev_execute_data;
                zend_vm_stack_free_args(call);
@@ -796,7 +796,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_HANDLER(ZEND_OPC
                        zval *p = ZEND_CALL_ARG(call, 1);
 
                        for (i = 0; i < num_args; ++i) {
-                               zend_verify_internal_arg_type(fbc, i + 1, p, EX_USES_STRICT_TYPES());
+                               zend_verify_internal_arg_type(fbc, i + 1, p);
                                if (UNEXPECTED(EG(exception) != NULL)) {
                                        EG(current_execute_data) = call->prev_execute_data;
                                        zend_vm_stack_free_args(call);
@@ -828,7 +828,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_HANDLER(ZEND_OPC
                ZEND_ASSERT(
                        !call->func ||
                        !(call->func->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) ||
-                       zend_verify_internal_return_type(call->func, EX_VAR(opline->result.var), EX_USES_STRICT_TYPES()));
+                       zend_verify_internal_return_type(call->func, EX_VAR(opline->result.var)));
 
                EG(current_execute_data) = call->prev_execute_data;
                zend_vm_stack_free_args(call);
@@ -1218,7 +1218,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_RECV_SPEC_HANDLER(ZEND_OPCODE_
        } else if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) {
                zval *param = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var);
 
-               zend_verify_arg_type(EX(func), arg_num, param, NULL, EX_PREV_USES_STRICT_TYPES());
+               zend_verify_arg_type(EX(func), arg_num, param, NULL);
                CHECK_EXCEPTION();
        }
 
@@ -1245,7 +1245,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_RECV_VARIADIC_SPEC_HANDLER(ZEN
                        param = EX_VAR_NUM(EX(func)->op_array.last_var + EX(func)->op_array.T);
                        if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) {
                                do {
-                                       zend_verify_arg_type(EX(func), arg_num, param, NULL, EX_USES_STRICT_TYPES());
+                                       zend_verify_arg_type(EX(func), arg_num, param, NULL);
                                        if (Z_OPT_REFCOUNTED_P(param)) Z_ADDREF_P(param);
                                        ZEND_HASH_FILL_ADD(param);
                                        param++;
@@ -2078,7 +2078,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_RECV_INIT_SPEC_CONST_HANDLER(Z
        }
 
        if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) {
-               zend_verify_arg_type(EX(func), arg_num, param, EX_CONSTANT(opline->op2), EX_PREV_USES_STRICT_TYPES());
+               zend_verify_arg_type(EX(func), arg_num, param, EX_CONSTANT(opline->op2));
        }
 
        CHECK_EXCEPTION();
@@ -3809,35 +3809,42 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_STRLEN_SPEC_CONST_HANDLER(ZEND
 try_strlen:
        if (EXPECTED(Z_TYPE_P(value) == IS_STRING)) {
                ZVAL_LONG(EX_VAR(opline->result.var), Z_STRLEN_P(value));
-       } else if (EXPECTED(!EX_USES_STRICT_TYPES())) {
+       } else {
+               zend_bool strict;
+
                if ((IS_CONST & (IS_VAR|IS_CV)) && Z_TYPE_P(value) == IS_REFERENCE) {
                        value = Z_REFVAL_P(value);
                        goto try_strlen;
-               } else if (Z_TYPE_P(value) < IS_TRUE) {
-                       ZVAL_LONG(EX_VAR(opline->result.var), 0);
-               } else if (Z_TYPE_P(value) == IS_TRUE) {
-                       ZVAL_LONG(EX_VAR(opline->result.var), 1);
-               } else if (Z_TYPE_P(value) <= IS_DOUBLE) {
-                       zend_string *str = zval_get_string(value);
-                       ZVAL_LONG(EX_VAR(opline->result.var), str->len);
-                       zend_string_release(str);
-               } else if (Z_TYPE_P(value) == IS_OBJECT) {
-                       zend_string *str;
-                       zval tmp;
-
-                       ZVAL_COPY(&tmp, value);
-                       if (parse_arg_object_to_str(&tmp, &str, IS_STRING) == FAILURE) {
-                               goto strlen_error;
-                       }
-                       ZVAL_LONG(EX_VAR(opline->result.var), str->len);
-                       zval_dtor(&tmp);
-               } else {
-strlen_error:
-                       zend_internal_type_error(0, "strlen() expects parameter 1 to be string, %s given", zend_get_type_by_const(Z_TYPE_P(value)));
-                       ZVAL_NULL(EX_VAR(opline->result.var));
                }
-       } else {
-               zend_internal_type_error(1, "strlen() expects parameter 1 to be string, %s given", zend_get_type_by_const(Z_TYPE_P(value)));
+               strict = EX_USES_STRICT_TYPES();
+               do {
+                       if (EXPECTED(!strict)) {
+                               if (Z_TYPE_P(value) < IS_TRUE) {
+                                       ZVAL_LONG(EX_VAR(opline->result.var), 0);
+                                       break;
+                               } else if (Z_TYPE_P(value) == IS_TRUE) {
+                                       ZVAL_LONG(EX_VAR(opline->result.var), 1);
+                                       break;
+                               } else if (Z_TYPE_P(value) <= IS_DOUBLE) {
+                                       zend_string *str = zval_get_string(value);
+                                       ZVAL_LONG(EX_VAR(opline->result.var), str->len);
+                                       zend_string_release(str);
+                                       break;
+                               } else if (Z_TYPE_P(value) == IS_OBJECT) {
+                                       zend_string *str;
+                                       zval tmp;
+
+                                       ZVAL_COPY(&tmp, value);
+                                       if (parse_arg_object_to_str(&tmp, &str, IS_STRING) == SUCCESS) {
+                                               ZVAL_LONG(EX_VAR(opline->result.var), str->len);
+                                               zval_dtor(&tmp);
+                                               break;
+                                       }
+                               }
+                       }
+                       zend_internal_type_error(strict, "strlen() expects parameter 1 to be string, %s given", zend_get_type_by_const(Z_TYPE_P(value)));
+                       ZVAL_NULL(EX_VAR(opline->result.var));
+               } while (0);
        }
 
        CHECK_EXCEPTION();
@@ -6988,7 +6995,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_CONST_
                        }
                }
 
-               zend_verify_return_type(EX(func), retval_ptr, EX_USES_STRICT_TYPES());
+               zend_verify_return_type(EX(func), retval_ptr);
 #endif
        }
        CHECK_EXCEPTION();
@@ -11949,7 +11956,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_TMP_UN
                        }
                }
 
-               zend_verify_return_type(EX(func), retval_ptr, EX_USES_STRICT_TYPES());
+               zend_verify_return_type(EX(func), retval_ptr);
 #endif
        }
        CHECK_EXCEPTION();
@@ -17310,7 +17317,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_VAR_UN
                        }
                }
 
-               zend_verify_return_type(EX(func), retval_ptr, EX_USES_STRICT_TYPES());
+               zend_verify_return_type(EX(func), retval_ptr);
 #endif
        }
        CHECK_EXCEPTION();
@@ -22928,7 +22935,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_UNUSED
                        }
                }
 
-               zend_verify_return_type(EX(func), retval_ptr, EX_USES_STRICT_TYPES());
+               zend_verify_return_type(EX(func), retval_ptr);
 #endif
        }
        CHECK_EXCEPTION();
@@ -27324,35 +27331,42 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_STRLEN_SPEC_CV_HANDLER(ZEND_OP
 try_strlen:
        if (EXPECTED(Z_TYPE_P(value) == IS_STRING)) {
                ZVAL_LONG(EX_VAR(opline->result.var), Z_STRLEN_P(value));
-       } else if (EXPECTED(!EX_USES_STRICT_TYPES())) {
+       } else {
+               zend_bool strict;
+
                if ((IS_CV & (IS_VAR|IS_CV)) && Z_TYPE_P(value) == IS_REFERENCE) {
                        value = Z_REFVAL_P(value);
                        goto try_strlen;
-               } else if (Z_TYPE_P(value) < IS_TRUE) {
-                       ZVAL_LONG(EX_VAR(opline->result.var), 0);
-               } else if (Z_TYPE_P(value) == IS_TRUE) {
-                       ZVAL_LONG(EX_VAR(opline->result.var), 1);
-               } else if (Z_TYPE_P(value) <= IS_DOUBLE) {
-                       zend_string *str = zval_get_string(value);
-                       ZVAL_LONG(EX_VAR(opline->result.var), str->len);
-                       zend_string_release(str);
-               } else if (Z_TYPE_P(value) == IS_OBJECT) {
-                       zend_string *str;
-                       zval tmp;
-
-                       ZVAL_COPY(&tmp, value);
-                       if (parse_arg_object_to_str(&tmp, &str, IS_STRING) == FAILURE) {
-                               goto strlen_error;
-                       }
-                       ZVAL_LONG(EX_VAR(opline->result.var), str->len);
-                       zval_dtor(&tmp);
-               } else {
-strlen_error:
-                       zend_internal_type_error(0, "strlen() expects parameter 1 to be string, %s given", zend_get_type_by_const(Z_TYPE_P(value)));
-                       ZVAL_NULL(EX_VAR(opline->result.var));
                }
-       } else {
-               zend_internal_type_error(1, "strlen() expects parameter 1 to be string, %s given", zend_get_type_by_const(Z_TYPE_P(value)));
+               strict = EX_USES_STRICT_TYPES();
+               do {
+                       if (EXPECTED(!strict)) {
+                               if (Z_TYPE_P(value) < IS_TRUE) {
+                                       ZVAL_LONG(EX_VAR(opline->result.var), 0);
+                                       break;
+                               } else if (Z_TYPE_P(value) == IS_TRUE) {
+                                       ZVAL_LONG(EX_VAR(opline->result.var), 1);
+                                       break;
+                               } else if (Z_TYPE_P(value) <= IS_DOUBLE) {
+                                       zend_string *str = zval_get_string(value);
+                                       ZVAL_LONG(EX_VAR(opline->result.var), str->len);
+                                       zend_string_release(str);
+                                       break;
+                               } else if (Z_TYPE_P(value) == IS_OBJECT) {
+                                       zend_string *str;
+                                       zval tmp;
+
+                                       ZVAL_COPY(&tmp, value);
+                                       if (parse_arg_object_to_str(&tmp, &str, IS_STRING) == SUCCESS) {
+                                               ZVAL_LONG(EX_VAR(opline->result.var), str->len);
+                                               zval_dtor(&tmp);
+                                               break;
+                                       }
+                               }
+                       }
+                       zend_internal_type_error(strict, "strlen() expects parameter 1 to be string, %s given", zend_get_type_by_const(Z_TYPE_P(value)));
+                       ZVAL_NULL(EX_VAR(opline->result.var));
+               } while (0);
        }
 
        CHECK_EXCEPTION();
@@ -31875,7 +31889,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_CV_UNU
                        }
                }
 
-               zend_verify_return_type(EX(func), retval_ptr, EX_USES_STRICT_TYPES());
+               zend_verify_return_type(EX(func), retval_ptr);
 #endif
        }
        CHECK_EXCEPTION();
@@ -37592,35 +37606,42 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_STRLEN_SPEC_TMPVAR_HANDLER(ZEN
 try_strlen:
        if (EXPECTED(Z_TYPE_P(value) == IS_STRING)) {
                ZVAL_LONG(EX_VAR(opline->result.var), Z_STRLEN_P(value));
-       } else if (EXPECTED(!EX_USES_STRICT_TYPES())) {
+       } else {
+               zend_bool strict;
+
                if (((IS_TMP_VAR|IS_VAR) & (IS_VAR|IS_CV)) && Z_TYPE_P(value) == IS_REFERENCE) {
                        value = Z_REFVAL_P(value);
                        goto try_strlen;
-               } else if (Z_TYPE_P(value) < IS_TRUE) {
-                       ZVAL_LONG(EX_VAR(opline->result.var), 0);
-               } else if (Z_TYPE_P(value) == IS_TRUE) {
-                       ZVAL_LONG(EX_VAR(opline->result.var), 1);
-               } else if (Z_TYPE_P(value) <= IS_DOUBLE) {
-                       zend_string *str = zval_get_string(value);
-                       ZVAL_LONG(EX_VAR(opline->result.var), str->len);
-                       zend_string_release(str);
-               } else if (Z_TYPE_P(value) == IS_OBJECT) {
-                       zend_string *str;
-                       zval tmp;
-
-                       ZVAL_COPY(&tmp, value);
-                       if (parse_arg_object_to_str(&tmp, &str, IS_STRING) == FAILURE) {
-                               goto strlen_error;
-                       }
-                       ZVAL_LONG(EX_VAR(opline->result.var), str->len);
-                       zval_dtor(&tmp);
-               } else {
-strlen_error:
-                       zend_internal_type_error(0, "strlen() expects parameter 1 to be string, %s given", zend_get_type_by_const(Z_TYPE_P(value)));
-                       ZVAL_NULL(EX_VAR(opline->result.var));
                }
-       } else {
-               zend_internal_type_error(1, "strlen() expects parameter 1 to be string, %s given", zend_get_type_by_const(Z_TYPE_P(value)));
+               strict = EX_USES_STRICT_TYPES();
+               do {
+                       if (EXPECTED(!strict)) {
+                               if (Z_TYPE_P(value) < IS_TRUE) {
+                                       ZVAL_LONG(EX_VAR(opline->result.var), 0);
+                                       break;
+                               } else if (Z_TYPE_P(value) == IS_TRUE) {
+                                       ZVAL_LONG(EX_VAR(opline->result.var), 1);
+                                       break;
+                               } else if (Z_TYPE_P(value) <= IS_DOUBLE) {
+                                       zend_string *str = zval_get_string(value);
+                                       ZVAL_LONG(EX_VAR(opline->result.var), str->len);
+                                       zend_string_release(str);
+                                       break;
+                               } else if (Z_TYPE_P(value) == IS_OBJECT) {
+                                       zend_string *str;
+                                       zval tmp;
+
+                                       ZVAL_COPY(&tmp, value);
+                                       if (parse_arg_object_to_str(&tmp, &str, IS_STRING) == SUCCESS) {
+                                               ZVAL_LONG(EX_VAR(opline->result.var), str->len);
+                                               zval_dtor(&tmp);
+                                               break;
+                                       }
+                               }
+                       }
+                       zend_internal_type_error(strict, "strlen() expects parameter 1 to be string, %s given", zend_get_type_by_const(Z_TYPE_P(value)));
+                       ZVAL_NULL(EX_VAR(opline->result.var));
+               } while (0);
        }
        zval_ptr_dtor_nogc(free_op1);
        CHECK_EXCEPTION();