Browse Source

Refactor error implementation significantly to centralize error mode behavior. Add zend_internal_type_error() function

pull/1180/head
Anthony Ferrara 11 years ago
parent
commit
7feebead1b
  1. 160
      Zend/tests/typehints/scalar_basic.phpt
  2. 29
      Zend/zend.c
  3. 2
      Zend/zend.h
  4. 35
      Zend/zend_API.c
  5. 13
      Zend/zend_exceptions.c
  6. 1
      Zend/zend_exceptions.h
  7. 72
      Zend/zend_execute.c
  8. 4
      Zend/zend_execute.h

160
Zend/tests/typehints/scalar_basic.phpt

@ -6,7 +6,6 @@ Scalar type hint basics
$errnames = [
E_NOTICE => 'E_NOTICE',
E_WARNING => 'E_WARNING',
E_RECOVERABLE_ERROR => 'E_RECOVERABLE_ERROR'
];
set_error_handler(function (int $errno, string $errmsg, string $file, int $line) use ($errnames) {
echo "$errnames[$errno]: $errmsg on line $line\n";
@ -48,194 +47,231 @@ $values = [
foreach ($functions as $type => $function) {
echo PHP_EOL, "Testing '$type' typehint:", PHP_EOL;
foreach ($values as $value) {
echo "*** Trying ";
echo PHP_EOL . "*** Trying ";
var_dump($value);
var_dump($function($value));
try {
var_dump($function($value));
} catch (\TypeException $e) {
echo "*** Caught " . $e->getMessage() . PHP_EOL;
}
}
}
echo PHP_EOL . "Done";
?>
--EXPECTF--
Testing 'int' typehint:
*** Trying int(1)
int(1)
*** Trying string(1) "1"
int(1)
*** Trying float(1)
int(1)
*** Trying float(1.5)
int(1)
*** Trying string(2) "1a"
E_NOTICE: A non well formed numeric value encountered on line %d
int(1)
*** Trying string(1) "a"
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type integer, string given, called in %s on line %d and defined on line %d
string(1) "a"
*** Caught Argument 1 passed to {closure}() must be of the type integer, string given, called in %s on line %d and defined in %s on line %d
*** Trying string(0) ""
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type integer, string given, called in %s on line %d and defined on line %d
string(0) ""
*** Caught Argument 1 passed to {closure}() must be of the type integer, string given, called in %s on line %d and defined in %s on line %d
*** Trying int(%d)
int(%d)
*** Trying float(NAN)
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type integer, float given, called in %s on line %d and defined on line %d
float(NAN)
*** Caught Argument 1 passed to {closure}() must be of the type integer, float given, called in %s on line %d and defined in %s on line %d
*** Trying bool(true)
int(1)
*** Trying bool(false)
int(0)
*** Trying NULL
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type integer, null given, called in %s on line %d and defined on line %d
NULL
*** Caught Argument 1 passed to {closure}() must be of the type integer, null given, called in %s on line %d and defined in %s on line %d
*** Trying array(0) {
}
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type integer, array given, called in %s on line %d and defined on line %d
array(0) {
}
*** Caught Argument 1 passed to {closure}() must be of the type integer, array given, called in %s on line %d and defined in %s on line %d
*** Trying object(stdClass)#%s (0) {
}
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type integer, object given, called in %s on line %d and defined on line %d
object(stdClass)#%s (0) {
}
*** Caught Argument 1 passed to {closure}() must be of the type integer, object given, called in %s on line %d and defined in %s on line %d
*** Trying object(Stringable)#%s (0) {
}
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type integer, object given, called in %s on line %d and defined on line %d
object(Stringable)#%s (0) {
}
*** Caught Argument 1 passed to {closure}() must be of the type integer, object given, called in %s on line %d and defined in %s on line %d
*** Trying resource(%d) of type (stream)
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type integer, resource given, called in %s on line %d and defined on line %d
resource(%d) of type (stream)
*** Caught Argument 1 passed to {closure}() must be of the type integer, resource given, called in %s on line %d and defined in %s on line %d
Testing 'float' typehint:
*** Trying int(1)
float(1)
*** Trying string(1) "1"
float(1)
*** Trying float(1)
float(1)
*** Trying float(1.5)
float(1.5)
*** Trying string(2) "1a"
E_NOTICE: A non well formed numeric value encountered on line %d
float(1)
*** Trying string(1) "a"
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type float, string given, called in %s on line %d and defined on line %d
string(1) "a"
*** Caught Argument 1 passed to {closure}() must be of the type float, string given, called in %s on line %d and defined in %s on line %d
*** Trying string(0) ""
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type float, string given, called in %s on line %d and defined on line %d
string(0) ""
*** Caught Argument 1 passed to {closure}() must be of the type float, string given, called in %s on line %d and defined in %s on line %d
*** Trying int(%d)
float(%s)
*** Trying float(NAN)
float(NAN)
*** Trying bool(true)
float(1)
*** Trying bool(false)
float(0)
*** Trying NULL
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type float, null given, called in %s on line %d and defined on line %d
NULL
*** Caught Argument 1 passed to {closure}() must be of the type float, null given, called in %s on line %d and defined in %s on line %d
*** Trying array(0) {
}
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type float, array given, called in %s on line %d and defined on line %d
array(0) {
}
*** Caught Argument 1 passed to {closure}() must be of the type float, array given, called in %s on line %d and defined in %s on line %d
*** Trying object(stdClass)#%s (0) {
}
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type float, object given, called in %s on line %d and defined on line %d
object(stdClass)#%s (0) {
}
*** Caught Argument 1 passed to {closure}() must be of the type float, object given, called in %s on line %d and defined in %s on line %d
*** Trying object(Stringable)#%s (0) {
}
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type float, object given, called in %s on line %d and defined on line %d
object(Stringable)#%s (0) {
}
*** Caught Argument 1 passed to {closure}() must be of the type float, object given, called in %s on line %d and defined in %s on line %d
*** Trying resource(%d) of type (stream)
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type float, resource given, called in %s on line %d and defined on line %d
resource(%d) of type (stream)
*** Caught Argument 1 passed to {closure}() must be of the type float, resource given, called in %s on line %d and defined in %s on line %d
Testing 'string' typehint:
*** Trying int(1)
string(1) "1"
*** Trying string(1) "1"
string(1) "1"
*** Trying float(1)
string(1) "1"
*** Trying float(1.5)
string(3) "1.5"
*** Trying string(2) "1a"
string(2) "1a"
*** Trying string(1) "a"
string(1) "a"
*** Trying string(0) ""
string(0) ""
*** Trying int(%d)
string(%d) "%d"
*** Trying float(NAN)
string(3) "NAN"
*** Trying bool(true)
string(1) "1"
*** Trying bool(false)
string(0) ""
*** Trying NULL
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type string, null given, called in %s on line %d and defined on line %d
NULL
*** Caught Argument 1 passed to {closure}() must be of the type string, null given, called in %s on line %d and defined in %s on line %d
*** Trying array(0) {
}
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type string, array given, called in %s on line %d and defined on line %d
array(0) {
}
*** Caught Argument 1 passed to {closure}() must be of the type string, array given, called in %s on line %d and defined in %s on line %d
*** Trying object(stdClass)#%s (0) {
}
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type string, object given, called in %s on line %d and defined on line %d
object(stdClass)#%s (0) {
}
*** Caught Argument 1 passed to {closure}() must be of the type string, object given, called in %s on line %d and defined in %s on line %d
*** Trying object(Stringable)#%s (0) {
}
string(6) "foobar"
*** Trying resource(%d) of type (stream)
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type string, resource given, called in %s on line %d and defined on line %d
resource(%d) of type (stream)
*** Caught Argument 1 passed to {closure}() must be of the type string, resource given, called in %s on line %d and defined in %s on line %d
Testing 'bool' typehint:
*** Trying int(1)
bool(true)
*** Trying string(1) "1"
bool(true)
*** Trying float(1)
bool(true)
*** Trying float(1.5)
bool(true)
*** Trying string(2) "1a"
bool(true)
*** Trying string(1) "a"
bool(true)
*** Trying string(0) ""
bool(false)
*** Trying int(%d)
bool(true)
*** Trying float(NAN)
bool(true)
*** Trying bool(true)
bool(true)
*** Trying bool(false)
bool(false)
*** Trying NULL
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type boolean, null given, called in %s on line %d and defined on line %d
NULL
*** Caught Argument 1 passed to {closure}() must be of the type boolean, null given, called in %s on line %d and defined in %s on line %d
*** Trying array(0) {
}
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type boolean, array given, called in %s on line %d and defined on line %d
array(0) {
}
*** Caught Argument 1 passed to {closure}() must be of the type boolean, array given, called in %s on line %d and defined in %s on line %d
*** Trying object(stdClass)#%s (0) {
}
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type boolean, object given, called in %s on line %d and defined on line %d
object(stdClass)#%s (0) {
}
*** Caught Argument 1 passed to {closure}() must be of the type boolean, object given, called in %s on line %d and defined in %s on line %d
*** Trying object(Stringable)#%s (0) {
}
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type boolean, object given, called in %s on line %d and defined on line %d
object(Stringable)#%s (0) {
}
*** Caught Argument 1 passed to {closure}() must be of the type boolean, object given, called in %s on line %d and defined in %s on line %d
*** Trying resource(%d) of type (stream)
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type boolean, resource given, called in %s on line %d and defined on line %d
resource(%d) of type (stream)
*** Caught Argument 1 passed to {closure}() must be of the type boolean, resource given, called in %s on line %d and defined in %s on line %d
Done

29
Zend/zend.c

@ -1277,6 +1277,35 @@ ZEND_API ZEND_NORETURN void zend_error_noreturn(int type, const char *format, ..
# endif
#endif
ZEND_API void zend_type_error(const char *format, ...) /* {{{ */
{
va_list va;
char *message = NULL;
va_start(va, format);
zend_vspprintf(&message, 0, format, va);
zend_throw_exception(zend_get_type_exception(), message, 0);
efree(message);
va_end(va);
} /* }}} */
ZEND_API void zend_internal_type_error(zend_bool strict, const char *format, ...) /* {{{ */
{
va_list va;
char *message = NULL;
va_start(va, format);
zend_vspprintf(&message, 0, format, va);
if (strict) {
zend_throw_exception(zend_get_type_exception(), message, 0);
} else {
zend_error(E_WARNING, message);
}
efree(message);
va_end(va);
} /* }}} */
ZEND_API void zend_output_debug_string(zend_bool trigger_break, const char *format, ...) /* {{{ */
{
#if ZEND_DEBUG

2
Zend/zend.h

@ -285,6 +285,8 @@ extern ZEND_API char *(*zend_getenv)(char *name, size_t name_len);
extern ZEND_API zend_string *(*zend_resolve_path)(const char *filename, int filename_len);
ZEND_API void zend_error(int type, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3);
ZEND_API void zend_type_error(const char *format, ...);
ZEND_API void zend_internal_type_error(zend_bool strict, const char *format, ...);
void zenderror(const char *error);

35
Zend/zend_API.c

@ -153,9 +153,8 @@ ZEND_API void _zend_wrong_param_count(zend_bool strict) /* {{{ */
{
const char *space;
const char *class_name = get_active_class_name(&space);
int error_type = strict ? (E_EXCEPTION | E_ERROR) : E_WARNING;
zend_error(error_type, "Wrong parameter count for %s%s%s()", class_name, space, get_active_function_name());
zend_internal_type_error(strict, "Wrong parameter count for %s%s%s()", class_name, space, get_active_function_name());
}
/* }}} */
@ -239,9 +238,8 @@ ZEND_API void zend_wrong_paramers_count_error(int num_args, int min_num_args, in
{
zend_function *active_function = EG(current_execute_data)->func;
const char *class_name = active_function->common.scope ? active_function->common.scope->name->val : "";
int error_type = strict ? (E_EXCEPTION | E_ERROR) : E_WARNING;
zend_error(error_type, "%s%s%s() expects %s %d parameter%s, %d given",
zend_internal_type_error(strict, "%s%s%s() expects %s %d parameter%s, %d given",
class_name, \
class_name[0] ? "::" : "", \
active_function->common.function_name->val,
@ -260,9 +258,8 @@ ZEND_API void zend_wrong_paramer_type_error(int num, zend_expected_type expected
Z_EXPECTED_TYPES(Z_EXPECTED_TYPE_STR)
NULL
};
int error_type = strict ? (E_EXCEPTION | E_ERROR) : E_WARNING;
zend_error(error_type, "%s%s%s() expects parameter %d to be %s, %s given",
zend_internal_type_error(strict, "%s%s%s() expects parameter %d to be %s, %s given",
class_name, space, get_active_function_name(), num, expected_error[expected_type], zend_zval_type_name(arg));
}
/* }}} */
@ -271,9 +268,8 @@ ZEND_API void zend_wrong_paramer_class_error(int num, char *name, zval *arg, zen
{
const char *space;
const char *class_name = get_active_class_name(&space);
int error_type = strict ? (E_EXCEPTION | E_ERROR) : E_WARNING;
zend_error(error_type, "%s%s%s() expects parameter %d to be %s, %s given",
zend_internal_type_error(strict, "%s%s%s() expects parameter %d to be %s, %s given",
class_name, space, get_active_function_name(), num, name, zend_zval_type_name(arg));
}
/* }}} */
@ -292,7 +288,6 @@ ZEND_API void zend_wrong_callback_error(int severity, int num, char *error) /* {
ZEND_API int zend_parse_arg_class(zval *arg, zend_class_entry **pce, int num, int check_null, zend_bool strict) /* {{{ */
{
zend_class_entry *ce_base = *pce;
int error_type = strict ? (E_EXCEPTION | E_ERROR) : E_WARNING;
if (check_null && Z_TYPE_P(arg) == IS_NULL) {
*pce = NULL;
@ -305,7 +300,7 @@ ZEND_API int zend_parse_arg_class(zval *arg, zend_class_entry **pce, int num, in
const char *space;
const char *class_name = get_active_class_name(&space);
zend_error(error_type, "%s%s%s() expects parameter %d to be a class name derived from %s, '%s' given",
zend_internal_type_error(strict, "%s%s%s() expects parameter %d to be a class name derived from %s, '%s' given",
class_name, space, get_active_function_name(), num,
ce_base->name->val, Z_STRVAL_P(arg));
*pce = NULL;
@ -316,7 +311,7 @@ ZEND_API int zend_parse_arg_class(zval *arg, zend_class_entry **pce, int num, in
const char *space;
const char *class_name = get_active_class_name(&space);
zend_error(error_type, "%s%s%s() expects parameter %d to be a valid class name, '%s' given",
zend_internal_type_error(strict, "%s%s%s() expects parameter %d to be a valid class name, '%s' given",
class_name, space, get_active_function_name(), num,
Z_STRVAL_P(arg));
return 0;
@ -580,7 +575,6 @@ static int zend_parse_arg(int arg_num, zval *arg, va_list *va, const char **spec
{
const char *expected_type = NULL;
char *error = NULL;
int error_type = strict ? (E_EXCEPTION | E_ERROR) : E_WARNING;
int severity;
expected_type = zend_parse_arg_impl(arg_num, arg, va, spec, &error, &severity, strict);
@ -590,11 +584,11 @@ static int zend_parse_arg(int arg_num, zval *arg, va_list *va, const char **spec
const char *class_name = get_active_class_name(&space);
if (error) {
zend_error(error_type, "%s%s%s() expects parameter %d %s",
class_name, space, get_active_function_name(), arg_num, error);
zend_internal_type_error(strict, "%s%s%s() expects parameter %d %s",
class_name, space, get_active_function_name(), arg_num, error);
efree(error);
} else {
zend_error(error_type, "%s%s%s() expects parameter %d to be %s, %s given",
zend_internal_type_error(strict, "%s%s%s() expects parameter %d to be %s, %s given",
class_name, space, get_active_function_name(), arg_num, expected_type,
zend_zval_type_name(arg));
}
@ -636,7 +630,6 @@ static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va,
zend_bool have_varargs = 0;
zval **varargs = NULL;
int *n_varargs = NULL;
int error_type = strict ? (E_EXCEPTION | E_ERROR) : E_WARNING;
for (spec_walk = type_spec; *spec_walk; spec_walk++) {
c = *spec_walk;
@ -670,7 +663,7 @@ static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va,
zend_function *active_function = EG(current_execute_data)->func;
const char *class_name = active_function->common.scope ? active_function->common.scope->name->val : "";
zend_error(error_type, "%s%s%s(): only one varargs specifier (* or +) is permitted",
zend_error(E_WARNING, "%s%s%s(): only one varargs specifier (* or +) is permitted",
class_name,
class_name[0] ? "::" : "",
active_function->common.function_name->val);
@ -690,7 +683,7 @@ static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va,
if (!quiet) {
zend_function *active_function = EG(current_execute_data)->func;
const char *class_name = active_function->common.scope ? active_function->common.scope->name->val : "";
zend_error(error_type, "%s%s%s(): bad type specifier while parsing parameters",
zend_error(E_WARNING, "%s%s%s(): bad type specifier while parsing parameters",
class_name,
class_name[0] ? "::" : "",
active_function->common.function_name->val);
@ -713,7 +706,7 @@ static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va,
if (!quiet) {
zend_function *active_function = EG(current_execute_data)->func;
const char *class_name = active_function->common.scope ? active_function->common.scope->name->val : "";
zend_error(error_type, "%s%s%s() expects %s %d parameter%s, %d given",
zend_internal_type_error(strict, "%s%s%s() expects %s %d parameter%s, %d given",
class_name,
class_name[0] ? "::" : "",
active_function->common.function_name->val,
@ -728,7 +721,7 @@ static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va,
arg_count = ZEND_CALL_NUM_ARGS(EG(current_execute_data));
if (num_args > arg_count) {
zend_error(error_type, "%s(): could not obtain parameters for parsing",
zend_error(E_WARNING, "%s(): could not obtain parameters for parsing",
get_active_function_name());
return FAILURE;
}
@ -782,7 +775,7 @@ static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va,
if (0 == (type_spec)[0] && 0 != __num_args && !(flags & ZEND_PARSE_PARAMS_QUIET)) { \
const char *__space; \
const char * __class_name = get_active_class_name(&__space); \
zend_error((flags & ZEND_PARSE_PARAMS_STRICT) ? (E_EXCEPTION | E_ERROR) : E_WARNING, "%s%s%s() expects exactly 0 parameters, %d given", \
zend_internal_type_error((flags & ZEND_PARSE_PARAMS_STRICT), "%s%s%s() expects exactly 0 parameters, %d given", \
__class_name, __space, \
get_active_function_name(), __num_args); \
return FAILURE; \

13
Zend/zend_exceptions.c

@ -35,6 +35,7 @@ static zend_class_entry *default_exception_ce;
static zend_class_entry *error_exception_ce;
static zend_class_entry *engine_exception_ce;
static zend_class_entry *parse_exception_ce;
static zend_class_entry *type_exception_ce;
static zend_object_handlers default_exception_handlers;
ZEND_API void (*zend_throw_exception_hook)(zval *ex);
@ -778,6 +779,10 @@ void zend_register_default_exception(void) /* {{{ */
INIT_CLASS_ENTRY(ce, "ParseException", NULL);
parse_exception_ce = zend_register_internal_class_ex(&ce, base_exception_ce);
parse_exception_ce->create_object = zend_default_exception_new;
INIT_CLASS_ENTRY(ce, "TypeException", NULL);
type_exception_ce = zend_register_internal_class_ex(&ce, engine_exception_ce);
type_exception_ce->create_object = zend_default_exception_new;
}
/* }}} */
@ -811,6 +816,12 @@ ZEND_API zend_class_entry *zend_get_parse_exception(void) /* {{{ */
}
/* }}} */
ZEND_API zend_class_entry *zend_get_type_exception(void) /* {{{ */
{
return type_exception_ce;
}
/* }}} */
ZEND_API zend_object *zend_throw_exception(zend_class_entry *exception_ce, const char *message, zend_long code) /* {{{ */
{
@ -892,7 +903,7 @@ ZEND_API void zend_exception_error(zend_object *ex, int severity) /* {{{ */
ZVAL_OBJ(&exception, ex);
ce_exception = Z_OBJCE(exception);
EG(exception) = NULL;
if (ce_exception == parse_exception_ce || ce_exception == engine_exception_ce) {
if (ce_exception == parse_exception_ce || ce_exception == engine_exception_ce || ce_exception == type_exception_ce) {
zend_string *message = zval_get_string(GET_PROPERTY(&exception, "message"));
zend_string *file = zval_get_string(GET_PROPERTY_SILENT(&exception, "file"));
zend_long line = zval_get_long(GET_PROPERTY_SILENT(&exception, "line"));

1
Zend/zend_exceptions.h

@ -39,6 +39,7 @@ ZEND_API zend_class_entry *zend_exception_get_default(void);
ZEND_API zend_class_entry *zend_get_error_exception(void);
ZEND_API zend_class_entry *zend_get_engine_exception(void);
ZEND_API zend_class_entry *zend_get_parse_exception(void);
ZEND_API zend_class_entry *zend_get_type_exception(void);
ZEND_API void zend_register_default_classes(void);
/* exception_ce NULL or zend_exception_get_default() or a derived class

72
Zend/zend_execute.c

@ -598,7 +598,7 @@ ZEND_API char * zend_verify_arg_class_kind(const zend_arg_info *cur_arg_info, ch
}
}
ZEND_API void zend_verify_arg_error(int error_type, const zend_function *zf, uint32_t arg_num, const char *need_msg, const char *need_kind, const char *given_msg, const char *given_kind, zval *arg)
ZEND_API void zend_verify_arg_error(const zend_function *zf, uint32_t arg_num, const char *need_msg, const char *need_kind, const char *given_msg, const char *given_kind, zval *arg)
{
zend_execute_data *ptr = EG(current_execute_data)->prev_execute_data;
const char *fname = zf->common.function_name->val;
@ -621,16 +621,19 @@ ZEND_API void zend_verify_arg_error(int error_type, const zend_function *zf, uin
}
if (ptr && ptr->func && ZEND_USER_CODE(ptr->func->common.type)) {
zend_error(error_type, "Argument %d passed to %s%s%s() must %s%s, %s%s given, called in %s on line %d and defined", arg_num, fclass, fsep, fname, need_msg, need_kind, given_msg, given_kind, ptr->func->op_array.filename->val, ptr->opline->lineno);
zend_type_error("Argument %d passed to %s%s%s() must %s%s, %s%s given, called in %s on line %d and defined in %s on line %d",
arg_num, fclass, fsep, fname, need_msg, need_kind, given_msg, given_kind,
ptr->func->op_array.filename->val, ptr->opline->lineno,
zf->op_array.filename->val, EG(current_execute_data)->opline->lineno);
} else {
zend_error(error_type, "Argument %d passed to %s%s%s() must %s%s, %s%s given", arg_num, fclass, fsep, fname, need_msg, need_kind, given_msg, given_kind);
zend_type_error("Argument %d passed to %s%s%s() must %s%s, %s%s given", arg_num, fclass, fsep, fname, need_msg, need_kind, given_msg, given_kind);
}
if (arg) {
ZVAL_COPY_VALUE(arg, &old_arg);
}
} else {
zend_error(error_type, "Argument %d passed to %s%s%s() must %s%s, %s%s given", arg_num, fclass, fsep, fname, need_msg, need_kind, given_msg, given_kind);
zend_type_error("Argument %d passed to %s%s%s() must %s%s, %s%s given", arg_num, fclass, fsep, fname, need_msg, need_kind, given_msg, given_kind);
}
}
@ -717,27 +720,27 @@ static void zend_verify_internal_arg_type(zend_function *zf, uint32_t arg_num, z
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(E_EXCEPTION | E_ERROR, zf, arg_num, need_msg, class_name, "instance of ", Z_OBJCE_P(arg)->name->val, arg);
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(E_EXCEPTION | E_ERROR, zf, arg_num, need_msg, class_name, zend_zval_type_name(arg), "", arg);
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(E_EXCEPTION | E_ERROR, zf, arg_num, "be of the type array", "", zend_zval_type_name(arg), "", arg);
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(E_EXCEPTION | E_ERROR, zf, arg_num, "be callable", "", zend_zval_type_name(arg), "", arg);
zend_verify_arg_error(zf, arg_num, "be callable", "", zend_zval_type_name(arg), "", arg);
}
} else if (UNEXPECTED(!ZEND_SAME_FAKE_TYPE(cur_arg_info->type_hint, Z_TYPE_P(arg)))) {
if (Z_TYPE_P(arg) == IS_NULL) {
if (!cur_arg_info->allow_null) {
failure:
zend_verify_arg_error(E_EXCEPTION | E_ERROR, zf, arg_num, "be of the type ", zend_get_type_by_const(cur_arg_info->type_hint), zend_zval_type_name(arg), "", arg);
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);
}
return;
}
@ -769,27 +772,27 @@ static void zend_verify_arg_type(zend_function *zf, uint32_t arg_num, zval *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(E_EXCEPTION | E_ERROR, zf, arg_num, need_msg, class_name, "instance of ", Z_OBJCE_P(arg)->name->val, arg);
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(E_EXCEPTION | E_ERROR, zf, arg_num, need_msg, class_name, zend_zval_type_name(arg), "", arg);
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(E_EXCEPTION | E_ERROR, zf, arg_num, "be of the type array", "", zend_zval_type_name(arg), "", arg);
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(E_EXCEPTION | E_ERROR, zf, arg_num, "be callable", "", zend_zval_type_name(arg), "", arg);
zend_verify_arg_error(zf, arg_num, "be callable", "", zend_zval_type_name(arg), "", arg);
}
} else if (UNEXPECTED(!ZEND_SAME_FAKE_TYPE(cur_arg_info->type_hint, Z_TYPE_P(arg)))) {
if (Z_TYPE_P(arg) == IS_NULL) {
if (!cur_arg_info->allow_null) {
failure:
zend_verify_arg_error(E_EXCEPTION | E_ERROR, zf, arg_num, "be of the type ", zend_get_type_by_const(cur_arg_info->type_hint), zend_zval_type_name(arg), "", arg);
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);
}
return;
}
@ -818,15 +821,15 @@ static inline int zend_verify_missing_arg_type(zend_function *zf, uint32_t arg_n
char *class_name;
need_msg = zend_verify_arg_class_kind(cur_arg_info, &class_name, &ce);
zend_verify_arg_error(E_EXCEPTION | E_ERROR, zf, arg_num, need_msg, class_name, "none", "", NULL);
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(E_EXCEPTION | E_ERROR, zf, arg_num, "be of the type array", "", "none", "", NULL);
zend_verify_arg_error(zf, arg_num, "be of the type array", "", "none", "", NULL);
} else if (cur_arg_info->type_hint == IS_CALLABLE) {
zend_verify_arg_error(E_EXCEPTION | E_ERROR, zf, arg_num, "be callable", "", "none", "", NULL);
zend_verify_arg_error(zf, arg_num, "be callable", "", "none", "", NULL);
} else {
zend_verify_arg_error(E_EXCEPTION | E_ERROR, zf, arg_num, "be of the type ", zend_get_type_by_const(cur_arg_info->type_hint), "none", "", NULL);
zend_verify_arg_error(zf, arg_num, "be of the type ", zend_get_type_by_const(cur_arg_info->type_hint), "none", "", NULL);
}
return 0;
}
@ -850,7 +853,7 @@ static void zend_verify_missing_arg(zend_execute_data *execute_data, uint32_t ar
}
}
ZEND_API void zend_verify_return_error(int error_type, const zend_function *zf, const char *need_msg, const char *need_kind, const char *returned_msg, const char *returned_kind)
ZEND_API void zend_verify_return_error(const zend_function *zf, const char *need_msg, const char *need_kind, const char *returned_msg, const char *returned_kind)
{
const char *fname = zf->common.function_name->val;
const char *fsep;
@ -864,8 +867,7 @@ ZEND_API void zend_verify_return_error(int error_type, const zend_function *zf,
fclass = "";
}
zend_error(error_type,
"Return value of %s%s%s() must %s%s, %s%s returned",
zend_type_error("Return value of %s%s%s() must %s%s, %s%s returned",
fclass, fsep, fname, need_msg, need_kind, returned_msg, returned_kind);
}
@ -882,30 +884,30 @@ static int zend_verify_internal_return_type(zend_function *zf, zval *ret, zend_b
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_return_error(E_CORE_ERROR, zf, need_msg, class_name, "instance of ", Z_OBJCE_P(ret)->name->val);
zend_verify_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_return_error(E_CORE_ERROR, zf, need_msg, class_name, zend_zval_type_name(ret), "");
zend_verify_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_return_error(E_CORE_ERROR, zf, "be of the type array", "", zend_zval_type_name(ret), "");
zend_verify_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_return_error(E_CORE_ERROR, zf, "be callable", "", zend_zval_type_name(ret), "");
zend_verify_return_error(zf, "be callable", "", zend_zval_type_name(ret), "");
return 0;
}
} else if (UNEXPECTED(!ZEND_SAME_FAKE_TYPE(ret_info->type_hint, Z_TYPE_P(ret)))) {
if (Z_TYPE_P(ret) == IS_NULL) {
if (!ret_info->allow_null) {
failure:
zend_verify_return_error(E_EXCEPTION | E_ERROR, zf, "be of the type ", zend_get_type_by_const(ret_info->type_hint), zend_zval_type_name(ret), "");
zend_verify_return_error(zf, "be of the type ", zend_get_type_by_const(ret_info->type_hint), zend_zval_type_name(ret), "");
}
return 0;
}
@ -930,26 +932,26 @@ static void zend_verify_return_type(zend_function *zf, zval *ret, zend_bool stri
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(E_EXCEPTION | E_ERROR, zf, need_msg, class_name, "instance of ", Z_OBJCE_P(ret)->name->val);
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(E_EXCEPTION | E_ERROR, zf, need_msg, class_name, zend_zval_type_name(ret), "");
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(E_EXCEPTION | E_ERROR, zf, "be of the type array", "", zend_zval_type_name(ret), "");
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(E_EXCEPTION | E_ERROR, zf, "be callable", "", zend_zval_type_name(ret), "");
zend_verify_return_error(zf, "be callable", "", zend_zval_type_name(ret), "");
}
} else if (UNEXPECTED(!ZEND_SAME_FAKE_TYPE(ret_info->type_hint, Z_TYPE_P(ret)))) {
if (Z_TYPE_P(ret) == IS_NULL) {
if (!ret_info->allow_null) {
failure:
zend_verify_return_error(E_EXCEPTION | E_ERROR, zf, "be of the type ", zend_get_type_by_const(ret_info->type_hint), zend_zval_type_name(ret), "");
zend_verify_return_error(zf, "be of the type ", zend_get_type_by_const(ret_info->type_hint), zend_zval_type_name(ret), "");
}
return;
}
@ -970,15 +972,15 @@ static inline int zend_verify_missing_return_type(zend_function *zf)
char *class_name;
need_msg = zend_verify_arg_class_kind(ret_info, &class_name, &ce);
zend_verify_return_error(E_EXCEPTION | E_ERROR, zf, need_msg, class_name, "none", "");
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(E_EXCEPTION | E_ERROR, zf, "be of the type array", "", "none", "");
zend_verify_return_error(zf, "be of the type array", "", "none", "");
} else if (ret_info->type_hint == IS_CALLABLE) {
zend_verify_return_error(E_EXCEPTION | E_ERROR, zf, "be callable", "", "none", "");
zend_verify_return_error(zf, "be callable", "", "none", "");
} else {
zend_verify_return_error(E_EXCEPTION | E_ERROR, zf, "be of the type ", zend_get_type_by_const(ret_info->type_hint), "none", "");
zend_verify_return_error(zf, "be of the type ", zend_get_type_by_const(ret_info->type_hint), "none", "");
}
return 0;
}

4
Zend/zend_execute.h

@ -49,8 +49,8 @@ ZEND_API int zend_eval_stringl_ex(char *str, size_t str_len, zval *retval_ptr, c
ZEND_API char * zend_verify_internal_arg_class_kind(const zend_internal_arg_info *cur_arg_info, char **class_name, zend_class_entry **pce);
ZEND_API char * zend_verify_arg_class_kind(const zend_arg_info *cur_arg_info, char **class_name, zend_class_entry **pce);
ZEND_API void zend_verify_arg_error(int error_type, const zend_function *zf, uint32_t arg_num, const char *need_msg, const char *need_kind, const char *given_msg, const char *given_kind, zval *arg);
ZEND_API void zend_verify_return_error(int error_type, const zend_function *zf, const char *need_msg, const char *need_kind, const char *returned_msg, const char *returned_kind);
ZEND_API void zend_verify_arg_error(const zend_function *zf, uint32_t arg_num, const char *need_msg, const char *need_kind, const char *given_msg, const char *given_kind, zval *arg);
ZEND_API void zend_verify_return_error(const zend_function *zf, const char *need_msg, const char *need_kind, const char *returned_msg, const char *returned_kind);
static zend_always_inline zval* zend_assign_to_variable(zval *variable_ptr, zval *value, zend_uchar value_type)
{

Loading…
Cancel
Save