Problem/Motivation
When calling fetchObject with a class name but without supplying constructor arguments, we get this warning:
Warning: PDOStatement::fetchObject() expects parameter 2 to be array, null given in Drupal\Core\Database\StatementWrapper->fetchObject()
This is because StatementWrapper defaults this to NULL, but PDOStatement expects an empty array if the argument is supplied.
Steps to reproduce
final class MyDatabaseObjectClass {
}
$queryResult = \Drupal::database()
->select('key_value', 'kv')
->fields('kv', ['name'])
->condition('collection', 'system.schema')
->condition('name', 'node')->execute();
$resultRowAsObject = $queryResult->fetchObject(MyDatabaseObjectClass::class);
Expected: An instance of MyDatabaseObjectClass
Actual: FALSE, plus a PHP Warning
Proposed resolution
Either the method signature of StatementWrapper::fetchObject should be changed to more closely align with PDOStatement::fetchObject, or a NULL guard should be added when passing $constructor_arguments to ensure an empty array is passed instead of NULL.
Release notes snippet
Any contrib database driver projects that implement StatementInterface::fetchObject will need to adjust their signature accordingly to prevent similar fatal errors.
| Comment | File | Size | Author |
|---|---|---|---|
| #10 | 3259740-10.patch | 4.91 KB | acbramley |
| #7 | 3259740-7--test-only.patch | 1.21 KB | acbramley |
Comments
Comment #2
pstewart commentedFor anyone else encountering this bug it can be worked around by passing an empty array explicitly, i.e.
$resultRowAsObject = $queryResult->fetchObject(MyDatabaseObjectClass::class, [])Comment #3
pstewart commentedForgot to mention the problem was encountered with Drupal 9.3.3 and PHP 7.4.
Comment #6
acbramley commentedTriaged as part of BSI, bug still exists in 11.x
Comment #7
acbramley commentedComment #8
acbramley commentedI feel like the correct solution is
array $constructor_arguments = [], but that may require a BC dance which it looks like these classes have already been through.Comment #9
kim.pepperI think it would be better to update fetchObject() to default to an empty array and trigger a deprecation warning if NULL is passed.
Comment #10
acbramley commentedI agree (see #8), let's see what others think.
Comment #12
smustgrave commentedThink #9 would be the safest. A trigger_error if null is passed in.
Comment #13
acbramley commentedExplicitly passing NULL produces a similar error, therefore does not need a deprecation because it never worked in the first place.
Comment #14
smustgrave commentedOh thanks for that @acbramley!
Comment #16
larowlanGoing to ping daffie for a review
Comment #17
daffie commentedI think we need to add a deprecation warning when the second parameter is explicitly set to NULL and add testing for that.
Comment #18
daffie commentedI did the review, therefor I should have removed the tag.
Comment #19
acbramley commentedSee #13 you can't explicitly pass NULL to the function, that fails with the same type error because the parameter is typed as an array.
Comment #20
mondrakeShouldn’t we fully align to the signature since we’re at it?
public PDOStatement::fetchObject(?string $class = "stdClass", array $constructorArgs = []): object|falseMaybe without the return typehint for now.
Not sure where we are with BC here - the interface is not typehinted yet, but concrete classes are and contrib extending from them would fail.
Comment #21
daffie commentedAfter talking to @acbramley and @larowlan on Slack, do I get their point. The parent method from PHP PDO also does not work when the second parameter is set to NULL. Therefor that is not a BC break.
Yes this would be a BC break. We have 2 contrib database drivers (MySQLi and MS SQL Server). The first one is being integrated in Drupal core and the second one does not override the method. I do not know of any other contrib overrides for the method and http://grep.xnddx.ru is no longer working. I do not know of any other alternatives.
If there are any overrides it will be very few instances. For me it is an exceptable risk. I leave it up to committer to make up his/her own mind and make the final decession. Back to RTBC.
Comment #24
larowlanCommitted to 11.x
Created and published a change record