Commit a3454b80e6d for php.net
commit a3454b80e6d68a5ea6ebe9aef08eba1457f6718f
Author: Gina Peter Banyard <girgias@php.net>
Date: Wed Nov 26 11:43:34 2025 +0000
Fix GH-20553: PDO::FETCH_CLASSTYPE ignores $constructorArgs in PHP 8.5.0
We must assign the ctor_arguments regardless of modes.
This regression was introduced during the refactoring of PDO's internals
Closes GH-20595
diff --git a/NEWS b/NEWS
index 57ffb2b7ae5..947abfeaad5 100644
--- a/NEWS
+++ b/NEWS
@@ -62,6 +62,10 @@ PHP NEWS
. Fixed bug GH-20329 (opcache.file_cache broken with full interned string
buffer). (Arnaud)
+- PDO:
+ . Fixed bug GH-20553 (PDO::FETCH_CLASSTYPE ignores $constructorArgs in
+ PHP 8.5.0). (Girgias)
+
- Phar:
. Fixed bug GH-20442 (Phar does not respect case-insensitiveness of
__halt_compiler() when reading stub). (ndossche, TimWolla)
diff --git a/ext/pdo/pdo_stmt.c b/ext/pdo/pdo_stmt.c
index 697940d9426..5d8b4089ca0 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 00000000000..fe0b84c27eb
--- /dev/null
+++ b/ext/pdo/tests/gh20553.phpt
@@ -0,0 +1,97 @@
+--TEST--
+GH-20553: PHP 8.5.0 regression: PDO::FETCH_CLASSTYPE ignores $constructorArgs
+--EXTENSIONS--
+pdo
+--SKIPIF--
+<?php
+$dir = getenv('REDIR_TEST_DIR');
+if (false == $dir) die('skip no driver');
+if (str_starts_with(getenv('PDOTEST_DSN'), "firebird")) {
+ die("skip firebird doesn't support non-standard SQL without FROM syntax");
+}
+require_once $dir . 'pdo_test.inc';
+PDOTest::skip();
+?>
+--FILE--
+<?php
+
+if (getenv('REDIR_TEST_DIR') === false) putenv('REDIR_TEST_DIR='.__DIR__ . '/../../pdo/tests/');
+require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc';
+$db = PDOTest::factory();
+
+class dumpy {
+ function __construct() {
+ echo 'constructor called,' . PHP_EOL . ' my class is ' .
+ var_export(get_class($this), true) . PHP_EOL .
+ ' input parameters: ' .
+ var_export(func_get_args(), true) . PHP_EOL;
+ }
+ function __set($name, $value) {
+ echo var_export($name, true) . ' = ' . var_export($value, true) .
+ PHP_EOL;
+ }
+}
+class dummy extends dumpy {
+}
+
+$sql = "SELECT 'dummy' pdo_fetch_class_type_class, 'bar' foo, 'dfg' abc";
+
+$fetchModes = [
+ 'PDO::FETCH_CLASS'
+ => 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'