From d5f92baad00ce19e096f9936a4ffdcf5c3cd1383 Mon Sep 17 00:00:00 2001 From: =?utf8?q?M=C3=A1t=C3=A9=20Kocsis?= Date: Wed, 14 Oct 2020 00:12:51 +0200 Subject: [PATCH] Fix default value handling of mysqli_fetch_object() Make [] acceptable both for classes without constructors and classes with a constructor that takes no arguments. Closes GH-6336. --- ext/mysqli/mysqli.c | 18 +++++++----------- ext/mysqli/mysqli.stub.php | 4 ++-- ext/mysqli/mysqli_arginfo.h | 6 +++--- ext/mysqli/tests/mysqli_fetch_object.phpt | 2 +- .../mysqli_fetch_object_no_constructor.phpt | 2 +- ext/mysqli/tests/mysqli_fetch_object_oo.phpt | 13 ++++--------- ext/pdo/pdo_dbh.c | 8 ++++---- ext/pgsql/pgsql.c | 18 +++++++----------- ext/pgsql/pgsql.stub.php | 2 +- ext/pgsql/pgsql_arginfo.h | 4 ++-- 10 files changed, 32 insertions(+), 45 deletions(-) diff --git a/ext/mysqli/mysqli.c b/ext/mysqli/mysqli.c index 05ffffa926..48a544d0c7 100644 --- a/ext/mysqli/mysqli.c +++ b/ext/mysqli/mysqli.c @@ -1200,16 +1200,9 @@ void php_mysqli_fetch_into_hash(INTERNAL_FUNCTION_PARAMETERS, int override_flags fci.param_count = 0; fci.named_params = NULL; - if (ctor_params && Z_TYPE_P(ctor_params) != IS_NULL) { + if (ctor_params) { if (zend_fcall_info_args(&fci, ctor_params) == FAILURE) { - /* Two problems why we throw exceptions here: PHP is typeless - * and hence passing one argument that's not an array could be - * by mistake and the other way round is possible, too. The - * single value is an array. Also we'd have to make that one - * argument passed by reference. - */ - zend_argument_error(zend_ce_exception, 3, "must be of type array, %s given", zend_zval_type_name(ctor_params)); - RETURN_THROWS(); + ZEND_UNREACHABLE(); } } @@ -1223,8 +1216,11 @@ void php_mysqli_fetch_into_hash(INTERNAL_FUNCTION_PARAMETERS, int override_flags zval_ptr_dtor(&retval); } zend_fcall_info_args_clear(&fci, 1); - } else if (ctor_params) { - zend_throw_exception_ex(zend_ce_exception, 0, "Class %s does not have a constructor hence you cannot use ctor_params", ZSTR_VAL(ce->name)); + } else if (ctor_params && zend_hash_num_elements(Z_ARRVAL_P(ctor_params)) > 0) { + zend_argument_error(zend_ce_exception, ERROR_ARG_POS(3), + "must be empty when the specified class (%s) does not have a constructor", + ZSTR_VAL(ce->name) + ); } } } diff --git a/ext/mysqli/mysqli.stub.php b/ext/mysqli/mysqli.stub.php index 4870485774..c1059254fc 100644 --- a/ext/mysqli/mysqli.stub.php +++ b/ext/mysqli/mysqli.stub.php @@ -364,7 +364,7 @@ class mysqli_result implements IteratorAggregate * @return object|null * @alias mysqli_fetch_object */ - public function fetch_object(string $class = "stdClass", array $params = []) {} + public function fetch_object(string $class = "stdClass", array $constructor_args = []) {} /** * @return array|null @@ -581,7 +581,7 @@ function mysqli_fetch_array(mysqli_result $result, int $mode = MYSQLI_BOTH): arr function mysqli_fetch_assoc(mysqli_result $result): ?array {} -function mysqli_fetch_object(mysqli_result $result, string $class = "stdClass", array $params = []): ?object {} +function mysqli_fetch_object(mysqli_result $result, string $class = "stdClass", array $constructor_args = []): ?object {} function mysqli_fetch_row(mysqli_result $result): ?array {} diff --git a/ext/mysqli/mysqli_arginfo.h b/ext/mysqli/mysqli_arginfo.h index 73960d38eb..509840a7fc 100644 --- a/ext/mysqli/mysqli_arginfo.h +++ b/ext/mysqli/mysqli_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 88f90ff45ab8f9748968c39eae950d58e598b73f */ + * Stub hash: 480939b71e1dacbdbb4634dbabf375943e399b6f */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_mysqli_affected_rows, 0, 1, MAY_BE_LONG|MAY_BE_STRING) ZEND_ARG_OBJ_INFO(0, mysql, mysqli, 0) @@ -115,7 +115,7 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_mysqli_fetch_object, 0, 1, IS_OBJECT, 1) ZEND_ARG_OBJ_INFO(0, result, mysqli_result, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, class, IS_STRING, 0, "\"stdClass\"") - ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, params, IS_ARRAY, 0, "[]") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, constructor_args, IS_ARRAY, 0, "[]") ZEND_END_ARG_INFO() #define arginfo_mysqli_fetch_row arginfo_mysqli_fetch_assoc @@ -614,7 +614,7 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_class_mysqli_result_fetch_object, 0, 0, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, class, IS_STRING, 0, "\"stdClass\"") - ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, params, IS_ARRAY, 0, "[]") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, constructor_args, IS_ARRAY, 0, "[]") ZEND_END_ARG_INFO() #define arginfo_class_mysqli_result_fetch_row arginfo_class_mysqli_character_set_name diff --git a/ext/mysqli/tests/mysqli_fetch_object.phpt b/ext/mysqli/tests/mysqli_fetch_object.phpt index f5708ac558..8076311112 100644 --- a/ext/mysqli/tests/mysqli_fetch_object.phpt +++ b/ext/mysqli/tests/mysqli_fetch_object.phpt @@ -147,6 +147,6 @@ Exception: Too few arguments to function mysqli_fetch_object_construct::__constr NULL NULL mysqli_result object is already closed -[0] mysqli_fetch_object(): Argument #3 ($params) must be of type array, string given in %s on line %d +[0] mysqli_fetch_object(): Argument #3 ($constructor_args) must be of type array, string given in %s on line %d mysqli_fetch_object(): Argument #2 ($class) must be a valid class name, this_class_does_not_exist given done! diff --git a/ext/mysqli/tests/mysqli_fetch_object_no_constructor.phpt b/ext/mysqli/tests/mysqli_fetch_object_no_constructor.phpt index 979c523199..5d823648c7 100644 --- a/ext/mysqli/tests/mysqli_fetch_object_no_constructor.phpt +++ b/ext/mysqli/tests/mysqli_fetch_object_no_constructor.phpt @@ -57,7 +57,7 @@ object(mysqli_fetch_object_test)#%d (%d) { } Exception with mysqli. Note that at all other places we throws errors but no exceptions unless the error mode has been changed: -Exception: Class mysqli_fetch_object_test does not have a constructor hence you cannot use ctor_params +Exception: mysqli_fetch_object(): Argument #3 ($constructor_args) must be empty when the specified class (mysqli_fetch_object_test) does not have a constructor Fatal error with PHP (but no exception!): diff --git a/ext/mysqli/tests/mysqli_fetch_object_oo.phpt b/ext/mysqli/tests/mysqli_fetch_object_oo.phpt index f402db82d8..c541ad2d04 100644 --- a/ext/mysqli/tests/mysqli_fetch_object_oo.phpt +++ b/ext/mysqli/tests/mysqli_fetch_object_oo.phpt @@ -73,14 +73,9 @@ require_once('skipifconnectfailure.inc'); } try { - $obj = $res->fetch_object('mysqli_fetch_object_construct', null); - - if (($obj->ID !== "3") || ($obj->label !== "c") || ($obj->a !== NULL) || ($obj->b !== NULL) || (get_class($obj) != 'mysqli_fetch_object_construct')) { - printf("[009] Object seems wrong. [%d] %s\n", $mysqli->errno, $mysqli->error); - var_dump($obj); - } - } catch (Error $e) { - handle_catchable_fatal($e->getCode(), $e->getMessage(), $e->getFile(), $e->getLine()); + $res->fetch_object('mysqli_fetch_object_construct', null); + } catch (TypeError $exception) { + echo $exception->getMessage() . "\n"; mysqli_fetch_object($res); } @@ -134,7 +129,7 @@ require_once('skipifconnectfailure.inc'); mysqli object is not fully initialized [0] Object of class mysqli could not be converted to string in %s on line %d [0] mysqli_result::fetch_object() expects at most 2 arguments, 3 given in %s on line %d -[0] mysqli_result::fetch_object(): Argument #2 ($params) must be of type array, null given in %s on line %d +mysqli_result::fetch_object(): Argument #2 ($constructor_args) must be of type array, null given Exception: Too few arguments to function mysqli_fetch_object_construct::__construct(), 1 passed and exactly 2 expected NULL NULL diff --git a/ext/pdo/pdo_dbh.c b/ext/pdo/pdo_dbh.c index 2e81db2bbf..a0c2b74c33 100644 --- a/ext/pdo/pdo_dbh.c +++ b/ext/pdo/pdo_dbh.c @@ -517,7 +517,7 @@ PHP_METHOD(PDO, prepare) } if ((item = zend_hash_index_find(Z_ARRVAL_P(value), 0)) == NULL) { zend_value_error("PDO::ATTR_STATEMENT_CLASS value must be an array with the format " - "array(classname, array(ctor_args))"); + "array(classname, constructor_args)"); RETURN_THROWS(); } if (Z_TYPE_P(item) != IS_STRING || (pce = zend_lookup_class(Z_STR_P(item))) == NULL) { @@ -535,7 +535,7 @@ PHP_METHOD(PDO, prepare) } if ((item = zend_hash_index_find(Z_ARRVAL_P(value), 1)) != NULL) { if (Z_TYPE_P(item) != IS_ARRAY) { - zend_type_error("PDO::ATTR_STATEMENT_CLASS ctor_args must be of type ?array, %s given", + zend_type_error("PDO::ATTR_STATEMENT_CLASS constructor_args must be of type ?array, %s given", zend_zval_type_name(value)); RETURN_THROWS(); } @@ -765,7 +765,7 @@ static zend_result pdo_dbh_attribute_set(pdo_dbh_t *dbh, zend_long attr, zval *v } if ((item = zend_hash_index_find(Z_ARRVAL_P(value), 0)) == NULL) { zend_value_error("PDO::ATTR_STATEMENT_CLASS value must be an array with the format " - "array(classname, array(ctor_args))"); + "array(classname, constructor_args)"); return FAILURE; } if (Z_TYPE_P(item) != IS_STRING || (pce = zend_lookup_class(Z_STR_P(item))) == NULL) { @@ -787,7 +787,7 @@ static zend_result pdo_dbh_attribute_set(pdo_dbh_t *dbh, zend_long attr, zval *v } if ((item = zend_hash_index_find(Z_ARRVAL_P(value), 1)) != NULL) { if (Z_TYPE_P(item) != IS_ARRAY) { - zend_type_error("PDO::ATTR_STATEMENT_CLASS ctor_args must be of type ?array, %s given", + zend_type_error("PDO::ATTR_STATEMENT_CLASS constructor_args must be of type ?array, %s given", zend_zval_type_name(value)); return FAILURE; } diff --git a/ext/pgsql/pgsql.c b/ext/pgsql/pgsql.c index aac2afd493..4685c7cd74 100644 --- a/ext/pgsql/pgsql.c +++ b/ext/pgsql/pgsql.c @@ -1836,7 +1836,7 @@ static void php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, zend_long result_ zend_class_entry *ce = NULL; if (into_object) { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|l!Ca!", &result, &row, &row_is_null, &ce, &ctor_params) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|l!Ca", &result, &row, &row_is_null, &ce, &ctor_params) == FAILURE) { RETURN_THROWS(); } if (!ce) { @@ -1935,14 +1935,7 @@ static void php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, zend_long result_ if (ctor_params) { if (zend_fcall_info_args(&fci, ctor_params) == FAILURE) { - /* Two problems why we throw exceptions here: PHP is typeless - * and hence passing one argument that's not an array could be - * by mistake and the other way round is possible, too. The - * single value is an array. Also we'd have to make that one - * argument passed by reference. - */ - zend_throw_exception(zend_ce_exception, "Parameter ctor_params must be an array", 0); - RETURN_THROWS(); + ZEND_UNREACHABLE(); } } @@ -1958,8 +1951,11 @@ static void php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, zend_long result_ if (fci.params) { efree(fci.params); } - } else if (ctor_params) { - zend_throw_exception_ex(zend_ce_exception, 0, "Class %s does not have a constructor hence you cannot use ctor_params", ZSTR_VAL(ce->name)); + } else if (ctor_params && zend_hash_num_elements(Z_ARRVAL_P(ctor_params)) > 0) { + zend_argument_error(zend_ce_exception, 3, + "must be empty when the specified class (%s) does not have a constructor", + ZSTR_VAL(ce->name) + ); } } } diff --git a/ext/pgsql/pgsql.stub.php b/ext/pgsql/pgsql.stub.php index 8460fd26b6..aff847bbc4 100644 --- a/ext/pgsql/pgsql.stub.php +++ b/ext/pgsql/pgsql.stub.php @@ -190,7 +190,7 @@ function pg_fetch_assoc($result, ?int $row = null): array|false {} function pg_fetch_array($result, ?int $row = null, int $mode = PGSQL_BOTH): array|false {} /** @param resource $result */ -function pg_fetch_object($result, ?int $row = null, string $class = "stdClass", ?array $ctor_args = null): object|false {} +function pg_fetch_object($result, ?int $row = null, string $class = "stdClass", array $constructor_args = []): object|false {} /** @param resource $result */ function pg_fetch_all($result, int $mode = PGSQL_ASSOC): array {} diff --git a/ext/pgsql/pgsql_arginfo.h b/ext/pgsql/pgsql_arginfo.h index 5bdda3ea07..3d9a4f2d5d 100644 --- a/ext/pgsql/pgsql_arginfo.h +++ b/ext/pgsql/pgsql_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 26edbb4ade84f0faad592dd270756c17e396519b */ + * Stub hash: de1718d3e6e66dfade25462b8461983b914120ed */ ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_connect, 0, 0, 1) ZEND_ARG_TYPE_INFO(0, connection_string, IS_STRING, 0) @@ -152,7 +152,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_pg_fetch_object, 0, 1, MAY_BE_OB ZEND_ARG_INFO(0, result) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, row, IS_LONG, 1, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, class, IS_STRING, 0, "\"stdClass\"") - ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, ctor_args, IS_ARRAY, 1, "null") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, constructor_args, IS_ARRAY, 0, "[]") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_pg_fetch_all, 0, 1, IS_ARRAY, 0) -- 2.40.0