Skip to content

Commit

Permalink
Merge branch 'PHP-8.0'
Browse files Browse the repository at this point in the history
* PHP-8.0:
  Fix default value handling of mysqli_fetch_object()
  • Loading branch information
nikic committed Oct 20, 2020
2 parents 11a2419 + d5f92ba commit d7a16bf
Show file tree
Hide file tree
Showing 10 changed files with 32 additions and 45 deletions.
18 changes: 7 additions & 11 deletions ext/mysqli/mysqli.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}

Expand All @@ -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)
);
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions ext/mysqli/mysqli.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,7 @@ public function fetch_assoc() {}
* @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
Expand Down Expand Up @@ -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 {}

Expand Down
6 changes: 3 additions & 3 deletions ext/mysqli/mysqli_arginfo.h
Original file line number Diff line number Diff line change
@@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion ext/mysqli/tests/mysqli_fetch_object.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -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!
2 changes: 1 addition & 1 deletion ext/mysqli/tests/mysqli_fetch_object_no_constructor.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -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!):

Expand Down
13 changes: 4 additions & 9 deletions ext/mysqli/tests/mysqli_fetch_object_oo.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down Expand Up @@ -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
Expand Down
8 changes: 4 additions & 4 deletions ext/pdo/pdo_dbh.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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();
}
Expand Down Expand Up @@ -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) {
Expand All @@ -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;
}
Expand Down
18 changes: 7 additions & 11 deletions ext/pgsql/pgsql.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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();
}
}

Expand All @@ -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)
);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion ext/pgsql/pgsql.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 {}
Expand Down
4 changes: 2 additions & 2 deletions ext/pgsql/pgsql_arginfo.h
Original file line number Diff line number Diff line change
@@ -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)
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit d7a16bf

Please sign in to comment.