From 3f8b4a955d7caf9bb3dde32c3c5ec90058b81f5e Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Wed, 26 Nov 2025 11:43:34 +0000 Subject: [PATCH 1/3] Fix GH-20553: PDO::FETCH_CLASSTYPE ignores $constructorArgs in PHP 8.5.0 --- ext/pdo/pdo_stmt.c | 3 +- ext/pdo/tests/gh20553.phpt | 94 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 ext/pdo/tests/gh20553.phpt diff --git a/ext/pdo/pdo_stmt.c b/ext/pdo/pdo_stmt.c index 697940d94260d..5d8b4089ca04f 100644 --- a/ext/pdo/pdo_stmt.c +++ b/ext/pdo/pdo_stmt.c @@ -771,9 +771,10 @@ static bool do_fetch(pdo_stmt_t *stmt, zval *return_value, enum pdo_fetch_type h pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "No fetch class specified"); goto in_fetch_error; } - ctor_arguments = stmt->fetch.cls.ctor_args; } ZEND_ASSERT(ce != NULL); + + ctor_arguments = stmt->fetch.cls.ctor_args; if (flags & PDO_FETCH_SERIALIZE) { if (!ce->unserialize) { /* As this option is deprecated we do not bother to mention the class name. */ diff --git a/ext/pdo/tests/gh20553.phpt b/ext/pdo/tests/gh20553.phpt new file mode 100644 index 0000000000000..e71eff79970cd --- /dev/null +++ b/ext/pdo/tests/gh20553.phpt @@ -0,0 +1,94 @@ +--TEST-- +GH-20553: PHP 8.5.0 regression: PDO::FETCH_CLASSTYPE ignores $constructorArgs +--EXTENSIONS-- +pdo +--SKIPIF-- + +--FILE-- + PDO::FETCH_CLASS, + 'PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE' + => PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, + 'PDO::FETCH_CLASS | PDO::FETCH_CLASSTYPE' + => PDO::FETCH_CLASS | PDO::FETCH_CLASSTYPE, + 'PDO::FETCH_CLASS | PDO::FETCH_CLASSTYPE | PDO::FETCH_PROPS_LATE' + => PDO::FETCH_CLASS | PDO::FETCH_CLASSTYPE | PDO::FETCH_PROPS_LATE, +]; + +foreach ($fetchModes as $combinedModes => $fetchMode) { + echo '## ' . $combinedModes . PHP_EOL; + $db->query($sql)->fetchAll( + $fetchMode, + 'dumpy', + ['constructor argument #1'] + ); + echo PHP_EOL; +} +?> +--EXPECT-- +## PDO::FETCH_CLASS +'pdo_fetch_class_type_class' = 'dummy' +'foo' = 'bar' +'abc' = 'dfg' +constructor called, + my class is 'dumpy' + input parameters: array ( + 0 => 'constructor argument #1', +) + +## PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE +constructor called, + my class is 'dumpy' + input parameters: array ( + 0 => 'constructor argument #1', +) +'pdo_fetch_class_type_class' = 'dummy' +'foo' = 'bar' +'abc' = 'dfg' + +## PDO::FETCH_CLASS | PDO::FETCH_CLASSTYPE +'foo' = 'bar' +'abc' = 'dfg' +constructor called, + my class is 'dummy' + input parameters: array ( + 0 => 'constructor argument #1', +) + +## PDO::FETCH_CLASS | PDO::FETCH_CLASSTYPE | PDO::FETCH_PROPS_LATE +constructor called, + my class is 'dummy' + input parameters: array ( + 0 => 'constructor argument #1', +) +'foo' = 'bar' +'abc' = 'dfg' From 3153ea3c5ad0b8bd8f4ad0d82fe06bdb7d06bed8 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Fri, 28 Nov 2025 18:39:44 +0000 Subject: [PATCH 2/3] attempt to use standard compliant SQL --- ext/pdo/tests/gh20553.phpt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ext/pdo/tests/gh20553.phpt b/ext/pdo/tests/gh20553.phpt index e71eff79970cd..a661d8bc77002 100644 --- a/ext/pdo/tests/gh20553.phpt +++ b/ext/pdo/tests/gh20553.phpt @@ -32,6 +32,14 @@ class dummy extends dumpy { } $sql = "SELECT 'dummy' pdo_fetch_class_type_class, 'bar' foo, 'dfg' abc;"; +$sql = "SELECT pdo_fetch_class_type_class, foo, abc FROM (VALUES ('dummy', 'bar' , 'dfg'))"; +$sql = "VALUES ('dummy', 'bar' , 'dfg') t(pdo_fetch_class_type_class, foo, abc)"; +/* SQL Compliant SELECT without FROM: + * - https://modern-sql.com/use-case/select-without-from + * - https://modern-sql.com/feature/values + * - https://modern-sql.com/feature/table-column-aliases + */ +$sql = "WITH dummy_table (pdo_fetch_class_type_class, foo, abc) AS (VALUES ('dummy', 'bar' , 'dfg')) SELECT * FROM dummy_table"; $fetchModes = [ 'PDO::FETCH_CLASS' From 91c809fa334968da5c3a19c5fae6d4d75187cf62 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Fri, 28 Nov 2025 19:27:04 +0000 Subject: [PATCH 3/3] Just skip firebird --- ext/pdo/tests/gh20553.phpt | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/ext/pdo/tests/gh20553.phpt b/ext/pdo/tests/gh20553.phpt index a661d8bc77002..fe0b84c27ebb0 100644 --- a/ext/pdo/tests/gh20553.phpt +++ b/ext/pdo/tests/gh20553.phpt @@ -6,6 +6,9 @@ pdo @@ -31,15 +34,7 @@ class dumpy { class dummy extends dumpy { } -$sql = "SELECT 'dummy' pdo_fetch_class_type_class, 'bar' foo, 'dfg' abc;"; -$sql = "SELECT pdo_fetch_class_type_class, foo, abc FROM (VALUES ('dummy', 'bar' , 'dfg'))"; -$sql = "VALUES ('dummy', 'bar' , 'dfg') t(pdo_fetch_class_type_class, foo, abc)"; -/* SQL Compliant SELECT without FROM: - * - https://modern-sql.com/use-case/select-without-from - * - https://modern-sql.com/feature/values - * - https://modern-sql.com/feature/table-column-aliases - */ -$sql = "WITH dummy_table (pdo_fetch_class_type_class, foo, abc) AS (VALUES ('dummy', 'bar' , 'dfg')) SELECT * FROM dummy_table"; +$sql = "SELECT 'dummy' pdo_fetch_class_type_class, 'bar' foo, 'dfg' abc"; $fetchModes = [ 'PDO::FETCH_CLASS'