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'