From 12ee17d5e079bbf02ecc7a8e4567977f4ebaf78d Mon Sep 17 00:00:00 2001 From: Davey Shafik Date: Tue, 30 Aug 2016 12:09:26 -0700 Subject: [PATCH] Implement \ArgumentCountError exception --- Zend/tests/bug38047.phpt | 2 +- Zend/tests/bug55705.phpt | 2 +- Zend/tests/bug70689.phpt | 2 +- .../argument_count_correct.phpt | 20 +++++++ .../argument_count_correct_strict.phpt | 20 +++++++ .../argument_count_incorrect_internal.phpt | 10 ++++ ...ument_count_incorrect_internal_strict.phpt | 18 +++++++ .../argument_count_incorrect_userland.phpt | 44 +++++++++++++++ ...ument_count_incorrect_userland_strict.phpt | 54 +++++++++++++++++++ ..._parameters_do_not_have_default_value.phpt | 2 +- Zend/zend.c | 17 ++++++ Zend/zend.h | 1 + Zend/zend_API.c | 22 ++++---- Zend/zend_exceptions.c | 7 ++- Zend/zend_exceptions.h | 1 + Zend/zend_execute.c | 28 +++++----- .../ReflectionMethod_invokeArgs_error1.phpt | 2 +- .../tests/ReflectionMethod_invoke_error2.phpt | 2 +- ext/standard/tests/assert/assert_error2.phpt | 2 +- ext/standard/tests/file/bug38450_3.phpt | 2 +- tests/classes/interfaces_003.phpt | 2 +- 21 files changed, 228 insertions(+), 32 deletions(-) create mode 100644 Zend/tests/function_arguments/argument_count_correct.phpt create mode 100644 Zend/tests/function_arguments/argument_count_correct_strict.phpt create mode 100644 Zend/tests/function_arguments/argument_count_incorrect_internal.phpt create mode 100644 Zend/tests/function_arguments/argument_count_incorrect_internal_strict.phpt create mode 100644 Zend/tests/function_arguments/argument_count_incorrect_userland.phpt create mode 100644 Zend/tests/function_arguments/argument_count_incorrect_userland_strict.phpt diff --git a/Zend/tests/bug38047.phpt b/Zend/tests/bug38047.phpt index 09739d23eb..e6eeb6631d 100644 --- a/Zend/tests/bug38047.phpt +++ b/Zend/tests/bug38047.phpt @@ -44,7 +44,7 @@ Non-static method A::A_ftk() should not be called statically 2 %sbug38047.php:36 kalus_error_handler() -Fatal error: Uncaught Error: Too few arguments to function A::A_ftk(), 0 passed in %sbug38047.php on line 36 and exactly 1 expected in %sbug38047.php:7 +Fatal error: Uncaught ArgumentCountError: Too few arguments to function A::A_ftk(), 0 passed in %sbug38047.php on line 36 and exactly 1 expected in %sbug38047.php:7 Stack trace: #0 %sbug38047.php(36): A::A_ftk() #1 {main} diff --git a/Zend/tests/bug55705.phpt b/Zend/tests/bug55705.phpt index fc17139344..06811bbc1b 100644 --- a/Zend/tests/bug55705.phpt +++ b/Zend/tests/bug55705.phpt @@ -6,7 +6,7 @@ function f(callable $c) {} f(); ?> --EXPECTF-- -Fatal error: Uncaught Error: Too few arguments to function f(), 0 passed in %s on line 3 and exactly 1 expected in %s:2 +Fatal error: Uncaught ArgumentCountError: Too few arguments to function f(), 0 passed in %s on line 3 and exactly 1 expected in %s:2 Stack trace: #0 %s(%d): f() #1 {main} diff --git a/Zend/tests/bug70689.phpt b/Zend/tests/bug70689.phpt index 286b6f4225..882dd89b75 100644 --- a/Zend/tests/bug70689.phpt +++ b/Zend/tests/bug70689.phpt @@ -19,7 +19,7 @@ try { ?> --EXPECTF-- -Fatal error: Uncaught Error: Too few arguments to function foo(), 0 passed in %sbug70689.php on line 12 and exactly 1 expected in %sbug70689.php:3 +Fatal error: Uncaught ArgumentCountError: Too few arguments to function foo(), 0 passed in %sbug70689.php on line 12 and exactly 1 expected in %sbug70689.php:3 Stack trace: #0 %sbug70689.php(12): foo() #1 {main} diff --git a/Zend/tests/function_arguments/argument_count_correct.phpt b/Zend/tests/function_arguments/argument_count_correct.phpt new file mode 100644 index 0000000000..44a87b8ba8 --- /dev/null +++ b/Zend/tests/function_arguments/argument_count_correct.phpt @@ -0,0 +1,20 @@ +--TEST-- +Call function with correct number of arguments +--FILE-- +getMessage() . PHP_EOL; +} + +array_diff([]); +--EXPECTF-- +ArgumentCountError +substr() expects at least 2 parameters, 1 given + +Warning: array_diff(): at least 2 parameters are required, 1 given in %s \ No newline at end of file diff --git a/Zend/tests/function_arguments/argument_count_incorrect_userland.phpt b/Zend/tests/function_arguments/argument_count_incorrect_userland.phpt new file mode 100644 index 0000000000..97faa4eb5c --- /dev/null +++ b/Zend/tests/function_arguments/argument_count_incorrect_userland.phpt @@ -0,0 +1,44 @@ +--TEST-- +Call userland function with incorrect number of arguments +--FILE-- +getMessage() . PHP_EOL; +} + +try { + function bar($foo, $bar) { } + bar(1); +} catch (\Error $e) { + echo get_class($e) . PHP_EOL; + echo $e->getMessage() . PHP_EOL; +} + +function bat(int $foo, string $bar) { } + +try { + bat(123); +} catch (\Error $e) { + echo get_class($e) . PHP_EOL; + echo $e->getMessage() . PHP_EOL; +} + +try { + bat("123"); +} catch (\Error $e) { + echo get_class($e) . PHP_EOL; + echo $e->getMessage() . PHP_EOL; +} +--EXPECTF-- +ArgumentCountError +Too few arguments to function foo(), 0 passed in %s and exactly 1 expected +ArgumentCountError +Too few arguments to function bar(), 1 passed in %s and exactly 2 expected +ArgumentCountError +Too few arguments to function bat(), 1 passed in %s and exactly 2 expected +ArgumentCountError +Too few arguments to function bat(), 1 passed in %s and exactly 2 expected \ No newline at end of file diff --git a/Zend/tests/function_arguments/argument_count_incorrect_userland_strict.phpt b/Zend/tests/function_arguments/argument_count_incorrect_userland_strict.phpt new file mode 100644 index 0000000000..9029dc2625 --- /dev/null +++ b/Zend/tests/function_arguments/argument_count_incorrect_userland_strict.phpt @@ -0,0 +1,54 @@ +--TEST-- +Call userland function with incorrect number of arguments with strict types +--FILE-- +getMessage() . PHP_EOL; +} + +try { + function bar($foo, $bar) { } + bar(1); +} catch (\Error $e) { + echo get_class($e) . PHP_EOL; + echo $e->getMessage() . PHP_EOL; +} + +function bat(int $foo, string $bar) { } + +try { + bat(123); +} catch (\Error $e) { + echo get_class($e) . PHP_EOL; + echo $e->getMessage() . PHP_EOL; +} + +try { + bat("123"); +} catch (\Error $e) { + echo get_class($e) . PHP_EOL; + echo $e->getMessage() . PHP_EOL; +} + +try { + bat(123, 456); +} catch (\Error $e) { + echo get_class($e) . PHP_EOL; + echo $e->getMessage() . PHP_EOL; +} +--EXPECTF-- +ArgumentCountError +Too few arguments to function foo(), 0 passed in %s and exactly 1 expected +ArgumentCountError +Too few arguments to function bar(), 1 passed in %s and exactly 2 expected +ArgumentCountError +Too few arguments to function bat(), 1 passed in %s and exactly 2 expected +TypeError +Argument 1 passed to bat() must be of the type integer, string given, called in %s +TypeError +Argument 2 passed to bat() must be of the type string, integer given, called in %s \ No newline at end of file diff --git a/Zend/tests/nullable_types/nullable_type_parameters_do_not_have_default_value.phpt b/Zend/tests/nullable_types/nullable_type_parameters_do_not_have_default_value.phpt index 5de93bb7d6..3050feed53 100644 --- a/Zend/tests/nullable_types/nullable_type_parameters_do_not_have_default_value.phpt +++ b/Zend/tests/nullable_types/nullable_type_parameters_do_not_have_default_value.phpt @@ -9,7 +9,7 @@ function f(?callable $p) {} f(); --EXPECTF-- -Fatal error: Uncaught Error: Too few arguments to function f(), 0 passed in %snullable_type_parameters_do_not_have_default_value.php on line %d and exactly 1 expected in %s:%d +Fatal error: Uncaught ArgumentCountError: Too few arguments to function f(), 0 passed in %snullable_type_parameters_do_not_have_default_value.php on line %d and exactly 1 expected in %s:%d Stack trace: #%d %s #%d %s diff --git a/Zend/zend.c b/Zend/zend.c index 118bd6c496..12801c8b70 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -1372,6 +1372,23 @@ ZEND_API ZEND_COLD void zend_internal_type_error(zend_bool throw_exception, cons va_end(va); } /* }}} */ +ZEND_API ZEND_COLD void zend_internal_argument_count_error(zend_bool throw_exception, const char *format, ...) /* {{{ */ +{ + va_list va; + char *message = NULL; + + va_start(va, format); + zend_vspprintf(&message, 0, format, va); + if (throw_exception) { + zend_throw_exception(zend_ce_argument_count_error, message, 0); + } else { + zend_error(E_WARNING, "%s", message); + } + efree(message); + + va_end(va); +} /* }}} */ + ZEND_API ZEND_COLD void zend_output_debug_string(zend_bool trigger_break, const char *format, ...) /* {{{ */ { #if ZEND_DEBUG diff --git a/Zend/zend.h b/Zend/zend.h index 94f2fbdcf4..04c9052e28 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -271,6 +271,7 @@ ZEND_API ZEND_COLD void zend_error(int type, const char *format, ...) ZEND_ATTRI ZEND_API ZEND_COLD void zend_throw_error(zend_class_entry *exception_ce, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3); ZEND_API ZEND_COLD void zend_type_error(const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 1, 2); ZEND_API ZEND_COLD void zend_internal_type_error(zend_bool throw_exception, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3); +ZEND_API ZEND_COLD void zend_internal_argument_count_error(zend_bool throw_exception, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3); ZEND_COLD void zenderror(const char *error); diff --git a/Zend/zend_API.c b/Zend/zend_API.c index fb0194f4af..c7727bdca7 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -157,7 +157,7 @@ ZEND_API ZEND_COLD void zend_wrong_param_count(void) /* {{{ */ const char *space; const char *class_name = get_active_class_name(&space); - zend_internal_type_error(ZEND_ARG_USES_STRICT_TYPES(), "Wrong parameter count for %s%s%s()", class_name, space, get_active_function_name()); + zend_internal_argument_count_error(ZEND_ARG_USES_STRICT_TYPES(), "Wrong parameter count for %s%s%s()", class_name, space, get_active_function_name()); } /* }}} */ @@ -208,14 +208,16 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameters_count_error(int num_ zend_function *active_function = EG(current_execute_data)->func; const char *class_name = active_function->common.scope ? ZSTR_VAL(active_function->common.scope->name) : ""; - zend_internal_type_error(ZEND_ARG_USES_STRICT_TYPES(), "%s%s%s() expects %s %d parameter%s, %d given", - class_name, \ - class_name[0] ? "::" : "", \ - ZSTR_VAL(active_function->common.function_name), - min_num_args == max_num_args ? "exactly" : num_args < min_num_args ? "at least" : "at most", - num_args < min_num_args ? min_num_args : max_num_args, - (num_args < min_num_args ? min_num_args : max_num_args) == 1 ? "" : "s", - num_args); + zend_internal_argument_count_error( + ZEND_ARG_USES_STRICT_TYPES(), + "%s%s%s() expects %s %d parameter%s, %d given", + class_name, \ + class_name[0] ? "::" : "", \ + ZSTR_VAL(active_function->common.function_name), + min_num_args == max_num_args ? "exactly" : num_args < min_num_args ? "at least" : "at most", + num_args < min_num_args ? min_num_args : max_num_args, + (num_args < min_num_args ? min_num_args : max_num_args) == 1 ? "" : "s", + num_args); } /* }}} */ @@ -875,7 +877,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 ? ZSTR_VAL(active_function->common.scope->name) : ""; zend_bool throw_exception = ZEND_ARG_USES_STRICT_TYPES() || (flags & ZEND_PARSE_PARAMS_THROW); - zend_internal_type_error(throw_exception, "%s%s%s() expects %s %d parameter%s, %d given", + zend_internal_argument_count_error(throw_exception, "%s%s%s() expects %s %d parameter%s, %d given", class_name, class_name[0] ? "::" : "", ZSTR_VAL(active_function->common.function_name), diff --git a/Zend/zend_exceptions.c b/Zend/zend_exceptions.c index 5301850310..dc073de633 100644 --- a/Zend/zend_exceptions.c +++ b/Zend/zend_exceptions.c @@ -36,6 +36,7 @@ ZEND_API zend_class_entry *zend_ce_error_exception; ZEND_API zend_class_entry *zend_ce_error; ZEND_API zend_class_entry *zend_ce_parse_error; ZEND_API zend_class_entry *zend_ce_type_error; +ZEND_API zend_class_entry *zend_ce_argument_count_error; ZEND_API zend_class_entry *zend_ce_arithmetic_error; ZEND_API zend_class_entry *zend_ce_division_by_zero_error; @@ -709,7 +710,7 @@ ZEND_METHOD(exception, __toString) ZVAL_UNDEF(&trace); } - if (Z_OBJCE_P(exception) == zend_ce_type_error && strstr(ZSTR_VAL(message), ", called in ")) { + if ((Z_OBJCE_P(exception) == zend_ce_type_error || Z_OBJCE_P(exception) == zend_ce_argument_count_error) && strstr(ZSTR_VAL(message), ", called in ")) { zend_string *real_message = zend_strpprintf(0, "%s and defined", ZSTR_VAL(message)); zend_string_release(message); message = real_message; @@ -859,6 +860,10 @@ void zend_register_default_exception(void) /* {{{ */ zend_ce_type_error = zend_register_internal_class_ex(&ce, zend_ce_error); zend_ce_type_error->create_object = zend_default_exception_new; + INIT_CLASS_ENTRY(ce, "ArgumentCountError", NULL); + zend_ce_argument_count_error = zend_register_internal_class_ex(&ce, zend_ce_type_error); + zend_ce_argument_count_error->create_object = zend_default_exception_new; + INIT_CLASS_ENTRY(ce, "ArithmeticError", NULL); zend_ce_arithmetic_error = zend_register_internal_class_ex(&ce, zend_ce_error); zend_ce_arithmetic_error->create_object = zend_default_exception_new; diff --git a/Zend/zend_exceptions.h b/Zend/zend_exceptions.h index 04857f29fa..18caf35553 100644 --- a/Zend/zend_exceptions.h +++ b/Zend/zend_exceptions.h @@ -32,6 +32,7 @@ extern ZEND_API zend_class_entry *zend_ce_error_exception; extern ZEND_API zend_class_entry *zend_ce_error; extern ZEND_API zend_class_entry *zend_ce_parse_error; extern ZEND_API zend_class_entry *zend_ce_type_error; +extern ZEND_API zend_class_entry *zend_ce_argument_count_error; extern ZEND_API zend_class_entry *zend_ce_arithmetic_error; extern ZEND_API zend_class_entry *zend_ce_division_by_zero_error; diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index f0f249e243..c748a77711 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -696,20 +696,24 @@ static ZEND_COLD void zend_verify_arg_error( const char *fname, *fsep, *fclass; const char *need_msg, *need_kind, *need_or_null, *given_msg, *given_kind; - zend_verify_type_error_common( - zf, arg_info, ce, value, - &fname, &fsep, &fclass, &need_msg, &need_kind, &need_or_null, &given_msg, &given_kind); - - if (zf->common.type == ZEND_USER_FUNCTION) { - if (ptr && ptr->func && ZEND_USER_CODE(ptr->func->common.type)) { - zend_type_error("Argument %d passed to %s%s%s() must %s%s%s, %s%s given, called in %s on line %d", - arg_num, fclass, fsep, fname, need_msg, need_kind, need_or_null, given_msg, given_kind, - ZSTR_VAL(ptr->func->op_array.filename), ptr->opline->lineno); + if (value) { + zend_verify_type_error_common( + zf, arg_info, ce, value, + &fname, &fsep, &fclass, &need_msg, &need_kind, &need_or_null, &given_msg, &given_kind); + + if (zf->common.type == ZEND_USER_FUNCTION) { + if (ptr && ptr->func && ZEND_USER_CODE(ptr->func->common.type)) { + zend_type_error("Argument %d passed to %s%s%s() must %s%s%s, %s%s given, called in %s on line %d", + arg_num, fclass, fsep, fname, need_msg, need_kind, need_or_null, given_msg, given_kind, + ZSTR_VAL(ptr->func->op_array.filename), ptr->opline->lineno); + } else { + zend_type_error("Argument %d passed to %s%s%s() must %s%s%s, %s%s given", arg_num, fclass, fsep, fname, need_msg, need_kind, need_or_null, given_msg, given_kind); + } } else { zend_type_error("Argument %d passed to %s%s%s() must %s%s%s, %s%s given", arg_num, fclass, fsep, fname, need_msg, need_kind, need_or_null, given_msg, given_kind); } } else { - zend_type_error("Argument %d passed to %s%s%s() must %s%s%s, %s%s given", arg_num, fclass, fsep, fname, need_msg, need_kind, need_or_null, given_msg, given_kind); + zend_missing_arg_error(ptr); } } @@ -955,7 +959,7 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_missing_arg_error(zend_execute_data * zend_execute_data *ptr = EX(prev_execute_data); if (ptr && ptr->func && ZEND_USER_CODE(ptr->func->common.type)) { - zend_throw_error(NULL, "Too few arguments to function %s%s%s(), %d passed in %s on line %d and %s %d expected", + zend_throw_error(zend_ce_argument_count_error, "Too few arguments to function %s%s%s(), %d passed in %s on line %d and %s %d expected", EX(func)->common.scope ? ZSTR_VAL(EX(func)->common.scope->name) : "", EX(func)->common.scope ? "::" : "", ZSTR_VAL(EX(func)->common.function_name), @@ -965,7 +969,7 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_missing_arg_error(zend_execute_data * EX(func)->common.required_num_args == EX(func)->common.num_args ? "exactly" : "at least", EX(func)->common.required_num_args); } else { - zend_throw_error(NULL, "Too few arguments to function %s%s%s(), %d passed and %s %d expected", + zend_throw_error(zend_ce_argument_count_error, "Too few arguments to function %s%s%s(), %d passed and %s %d expected", EX(func)->common.scope ? ZSTR_VAL(EX(func)->common.scope->name) : "", EX(func)->common.scope ? "::" : "", ZSTR_VAL(EX(func)->common.function_name), diff --git a/ext/reflection/tests/ReflectionMethod_invokeArgs_error1.phpt b/ext/reflection/tests/ReflectionMethod_invokeArgs_error1.phpt index c9d1e6379a..eec5a3e618 100644 --- a/ext/reflection/tests/ReflectionMethod_invokeArgs_error1.phpt +++ b/ext/reflection/tests/ReflectionMethod_invokeArgs_error1.phpt @@ -25,7 +25,7 @@ var_dump($methodWithArgs->invokeArgs($testClassInstance, array())); --EXPECTF-- Method with args: -Fatal error: Uncaught Error: Too few arguments to function TestClass::methodWithArgs(), 0 passed and exactly 2 expected in %sReflectionMethod_invokeArgs_error1.php:5 +Fatal error: Uncaught ArgumentCountError: Too few arguments to function TestClass::methodWithArgs(), 0 passed and exactly 2 expected in %sReflectionMethod_invokeArgs_error1.php:5 Stack trace: #0 [internal function]: TestClass->methodWithArgs() #1 %sReflectionMethod_invokeArgs_error1.php(19): ReflectionMethod->invokeArgs(Object(TestClass), Array) diff --git a/ext/reflection/tests/ReflectionMethod_invoke_error2.phpt b/ext/reflection/tests/ReflectionMethod_invoke_error2.phpt index 60a9ebae97..5dba208beb 100644 --- a/ext/reflection/tests/ReflectionMethod_invoke_error2.phpt +++ b/ext/reflection/tests/ReflectionMethod_invoke_error2.phpt @@ -21,7 +21,7 @@ var_dump($methodWithArgs->invoke($testClassInstance)); --EXPECTF-- Method with args: -Fatal error: Uncaught Error: Too few arguments to function TestClass::methodWithArgs(), 0 passed and exactly 2 expected in %sReflectionMethod_invoke_error2.php:5 +Fatal error: Uncaught ArgumentCountError: Too few arguments to function TestClass::methodWithArgs(), 0 passed and exactly 2 expected in %sReflectionMethod_invoke_error2.php:5 Stack trace: #0 [internal function]: TestClass->methodWithArgs() #1 %sReflectionMethod_invoke_error2.php(15): ReflectionMethod->invoke(Object(TestClass)) diff --git a/ext/standard/tests/assert/assert_error2.phpt b/ext/standard/tests/assert/assert_error2.phpt index 7861d435c8..f9018db05b 100644 --- a/ext/standard/tests/assert/assert_error2.phpt +++ b/ext/standard/tests/assert/assert_error2.phpt @@ -24,7 +24,7 @@ int(0) Warning: assert(): Assertion "0 != 0" failed in %s on line 9 -Fatal error: Uncaught Error: Too few arguments to function f1(), 3 passed and exactly 4 expected in %sassert_error2.php:2 +Fatal error: Uncaught ArgumentCountError: Too few arguments to function f1(), 3 passed and exactly 4 expected in %sassert_error2.php:2 Stack trace: #0 [internal function]: f1('%s', 9, '0 != 0') #1 %sassert_error2.php(9): assert('0 != 0') diff --git a/ext/standard/tests/file/bug38450_3.phpt b/ext/standard/tests/file/bug38450_3.phpt index 07c5958ab4..a72a00310d 100644 --- a/ext/standard/tests/file/bug38450_3.phpt +++ b/ext/standard/tests/file/bug38450_3.phpt @@ -104,7 +104,7 @@ echo "Done\n"; --EXPECTF-- Warning: fopen(var://myvar): failed to open stream: "VariableStream::stream_open" call failed in %sbug38450_3.php on line %d -Fatal error: Uncaught Error: Too few arguments to function VariableStream::__construct(), 0 passed and exactly 1 expected in %sbug38450_3.php:7 +Fatal error: Uncaught ArgumentCountError: Too few arguments to function VariableStream::__construct(), 0 passed and exactly 1 expected in %sbug38450_3.php:7 Stack trace: #0 [internal function]: VariableStream->__construct() #1 %s(%d): fopen('var://myvar', 'r+') diff --git a/tests/classes/interfaces_003.phpt b/tests/classes/interfaces_003.phpt index e66a86491c..28680096c5 100644 --- a/tests/classes/interfaces_003.phpt +++ b/tests/classes/interfaces_003.phpt @@ -23,7 +23,7 @@ $obj = new MyTestClass; ===DONE=== --EXPECTF-- -Fatal error: Uncaught Error: Too few arguments to function MyTestClass::__construct(), 0 passed in %sinterfaces_003.php on line 17 and exactly 1 expected in %sinterfaces_003.php:12 +Fatal error: Uncaught ArgumentCountError: Too few arguments to function MyTestClass::__construct(), 0 passed in %sinterfaces_003.php on line 17 and exactly 1 expected in %sinterfaces_003.php:12 Stack trace: #0 %s(%d): MyTestClass->__construct() #1 {main} -- 2.40.0