From 1cb166cbbbbdc6c292a96ea58603a32c253889fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Sun, 19 Oct 2025 14:13:54 +0200 Subject: [PATCH 1/2] pdo: Fix scope for PDO mixins in pdo_hash_methods() (#20200) From what I see the incorrect scope is not observable in any other way. The mixin methods are completely invisible to Reflection and a SQLite function referring to a private method is still properly called as before. Fixes php/php-src#20095. --- NEWS | 4 ++++ ext/pdo/pdo_dbh.c | 2 +- ext/pdo_sqlite/tests/gh20095.phpt | 25 +++++++++++++++++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 ext/pdo_sqlite/tests/gh20095.phpt diff --git a/NEWS b/NEWS index 353df7d7a8921..dab1c1158ae26 100644 --- a/NEWS +++ b/NEWS @@ -26,6 +26,10 @@ PHP NEWS . Fixed bug GH-19994 (openssl_get_cipher_methods inconsistent with fetching). (Jakub Zelenka) +- PDO: + . Fixed bug GH-20095 (Incorrect class name in deprecation message for PDO + mixins). (timwolla) + - Phar: . Fix potential buffer length truncation due to usage of type int instead of type size_t. (Girgias) diff --git a/ext/pdo/pdo_dbh.c b/ext/pdo/pdo_dbh.c index 1bdfcd935cfd1..08e398ea3682e 100644 --- a/ext/pdo/pdo_dbh.c +++ b/ext/pdo/pdo_dbh.c @@ -1394,7 +1394,7 @@ bool pdo_hash_methods(pdo_dbh_object_t *dbh_obj, int kind) func.type = ZEND_INTERNAL_FUNCTION; func.handler = funcs->handler; func.function_name = zend_string_init(funcs->fname, strlen(funcs->fname), dbh->is_persistent); - func.scope = dbh_obj->std.ce; + func.scope = pdo_dbh_ce; func.prototype = NULL; ZEND_MAP_PTR(func.run_time_cache) = rt_cache_size ? pecalloc(rt_cache_size, 1, dbh->is_persistent) : NULL; func.T = ZEND_OBSERVER_ENABLED; diff --git a/ext/pdo_sqlite/tests/gh20095.phpt b/ext/pdo_sqlite/tests/gh20095.phpt new file mode 100644 index 0000000000000..8d691f99ee2aa --- /dev/null +++ b/ext/pdo_sqlite/tests/gh20095.phpt @@ -0,0 +1,25 @@ +--TEST-- +GH-20095: Incorrect class name in deprecation message for PDO mixins +--EXTENSIONS-- +pdo_sqlite +--FILE-- +sqliteCreateFunction('my_test', [$this, "test"]); + } +} + +$pdo = new Foo('sqlite::memory:'); +$pdo->register(); +$pdo->query("SELECT my_test()"); + +?> +--EXPECTF-- +Deprecated: Method PDO::sqliteCreateFunction() is deprecated since 8.5, use Pdo\Sqlite::createFunction() instead in %s on line %d +foo From 7c9c39584c952063e5c05000cce7335a3ac65cdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Sun, 19 Oct 2025 17:37:38 +0200 Subject: [PATCH 2/2] zend_inheritance: Improve formatting of return-by-ref `&` in zend_get_function_declaration() (#20104) The space after `&` made it look like the `&` was not part of the signature, possibly leading to confusion why the two signatures are incompatible without carefully reading the message. --- Zend/tests/inheritance/argument_restriction_001.phpt | 2 +- Zend/tests/objects/objects_005.phpt | 2 +- Zend/tests/property_hooks/get_by_ref_implemented_by_val.phpt | 2 +- Zend/zend_inheritance.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Zend/tests/inheritance/argument_restriction_001.phpt b/Zend/tests/inheritance/argument_restriction_001.phpt index 2c54636a58178..6eb3ff8d27062 100644 --- a/Zend/tests/inheritance/argument_restriction_001.phpt +++ b/Zend/tests/inheritance/argument_restriction_001.phpt @@ -13,4 +13,4 @@ class Sub extends Base { } ?> --EXPECTF-- -Fatal error: Declaration of & Sub::test() must be compatible with & Base::test($foo, array $bar, $option = null, $extra = 'llllllllll...') in %s on line %d +Fatal error: Declaration of &Sub::test() must be compatible with &Base::test($foo, array $bar, $option = null, $extra = 'llllllllll...') in %s on line %d diff --git a/Zend/tests/objects/objects_005.phpt b/Zend/tests/objects/objects_005.phpt index 9b9a41465f95b..7749a39d986fb 100644 --- a/Zend/tests/objects/objects_005.phpt +++ b/Zend/tests/objects/objects_005.phpt @@ -19,4 +19,4 @@ class test3 extends test { ?> --EXPECTF-- -Fatal error: Declaration of test3::foo() must be compatible with & test::foo() in %s on line %d +Fatal error: Declaration of test3::foo() must be compatible with &test::foo() in %s on line %d diff --git a/Zend/tests/property_hooks/get_by_ref_implemented_by_val.phpt b/Zend/tests/property_hooks/get_by_ref_implemented_by_val.phpt index 84eb968263546..2c507d862be6f 100644 --- a/Zend/tests/property_hooks/get_by_ref_implemented_by_val.phpt +++ b/Zend/tests/property_hooks/get_by_ref_implemented_by_val.phpt @@ -15,4 +15,4 @@ class A implements I { ?> --EXPECTF-- -Fatal error: Declaration of A::$prop::get() must be compatible with & I::$prop::get() in %s on line %d +Fatal error: Declaration of A::$prop::get() must be compatible with &I::$prop::get() in %s on line %d diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index a2da64b62c0d5..1f128764bdd3d 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -916,7 +916,7 @@ static ZEND_COLD zend_string *zend_get_function_declaration( smart_str str = {0}; if (fptr->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { - smart_str_appends(&str, "& "); + smart_str_appendc(&str, '&'); } if (fptr->common.scope) {