|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[2021-05-26 23:24 UTC] corey dot taylor dot fl at gmail dot com
Description: ------------ At some point in php 8.1 development, PDOStatement::queryString became a typed property which throws an error when uninitialized. https://www.php.net/manual/en/class.pdostatement.php We were checking whether $queryString was truthy before using it, but now that access throws an error. https://3v4l.org/gHlc0/rfc#git.master The property is documented as "readonly string" which implies that it is always non-null. Can we make it nullable or initialize it when PDOStatement is created? The work around is using "isset($statement->queryString)" directly, but doesn't seem like it should be uninitialized. PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Sun Nov 30 15:00:01 2025 UTC |
So, the actual issue code generating the issue is not what I thought. We do create PDOStatement through prepare(), but it seems these failures are from a mock object. We assumed it was generating it for all queries. Your initial assessment is probably close to correct. $statement = $this->getMockBuilder('\PDOStatement') ->onlyMethods(['execute', 'rowCount', 'closeCursor', 'fetchAll']) ->getMock(); $driver->getConnection()->expects($this->once()) ->method('prepare') ->with('SELECT 1 FROM sqlite_master WHERE name = "sqlite_sequence"') ->will($this->returnValue($statement)); $statement->expects($this->once()) ->method('fetchAll') ->will($this->returnValue(['1'])); $statement->method('execute')->will($this->returnValue(true)); $table = new TableSchema('articles'); $result = $table->truncateSql($connection); $this->assertCount(2, $result); $this->assertSame('DELETE FROM sqlite_sequence WHERE name="articles"', $result[0]); $this->assertSame('DELETE FROM "articles"', $result[1]); It would be nice if we could somehow generate PDOStatement's in a mock scenario, but if that requires "isset()" because PDOStatement cannot initialize the property, then we can handle that.Thanks for the explanation -- this coming up in a mock scenario makes sense to me. Could it be that your original reason for the `if ($statement->queryString)` check was this mock scenerio as well? Because I don't think it would ever fail in other cases. I think that the best solution here would be to construct the mock with the property initialized: $queryString = 'SELECT 1 FROM sqlite_master WHERE name = "sqlite_sequence"'; $statement = $this->getMockBuilder('\PDOStatement') ->onlyMethods(['execute', 'rowCount', 'closeCursor', 'fetchAll']) ->getMock(); $statement->queryString = $queryString; $driver->getConnection()->expects($this->once()) ->method('prepare') ->with($queryString) ->will($this->returnValue($statement)); Because then, the code would see the same value it would see in a non-mock scenario. Unfortunately, this will currently result in: > Fatal error: Uncaught Error: Property queryString is read only However, I think we can relax this to allow an assignment as long as the property is still uninitialized. Nowadays our understanding of "read-only" is really "init-once", so that would be in line. Would this work for you?