File tree 3 files changed +70
-4
lines changed
tests/Functional/Driver/Mysqli
3 files changed +70
-4
lines changed Original file line number Diff line number Diff line change @@ -20,6 +20,15 @@ final class Result implements ResultInterface
20
20
{
21
21
private mysqli_stmt $ statement ;
22
22
23
+ /**
24
+ * Maintains a reference to the Statement that generated this result. This ensures that the lifetime of the
25
+ * Statement is managed in conjunction with its associated results, so they are destroyed together
26
+ * at the appropriate time {@see Statement::__destruct()).
27
+ *
28
+ * @phpstan-ignore property.onlyWritten
29
+ */
30
+ private ?Statement $ statementReference = null ;
31
+
23
32
/**
24
33
* Whether the statement result has columns. The property should be used only after the result metadata
25
34
* has been fetched ({@see $metadataFetched}). Otherwise, the property value is undetermined.
@@ -42,9 +51,12 @@ final class Result implements ResultInterface
42
51
*
43
52
* @throws Exception
44
53
*/
45
- public function __construct (mysqli_stmt $ statement )
46
- {
47
- $ this ->statement = $ statement ;
54
+ public function __construct (
55
+ mysqli_stmt $ statement ,
56
+ ?Statement $ statementReference = null
57
+ ) {
58
+ $ this ->statement = $ statement ;
59
+ $ this ->statementReference = $ statementReference ;
48
60
49
61
$ meta = $ statement ->result_metadata ();
50
62
Original file line number Diff line number Diff line change @@ -61,6 +61,11 @@ public function __construct(mysqli_stmt $stmt)
61
61
$ this ->boundValues = array_fill (1 , $ paramCount , null );
62
62
}
63
63
64
+ public function __destruct ()
65
+ {
66
+ @$ this ->stmt ->close ();
67
+ }
68
+
64
69
/**
65
70
* @deprecated Use {@see bindValue()} instead.
66
71
*
@@ -159,7 +164,7 @@ public function execute($params = null): ResultInterface
159
164
throw StatementError::new ($ this ->stmt );
160
165
}
161
166
162
- return new Result ($ this ->stmt );
167
+ return new Result ($ this ->stmt , $ this );
163
168
}
164
169
165
170
/**
Original file line number Diff line number Diff line change
1
+ <?php
2
+
3
+ declare (strict_types=1 );
4
+
5
+ namespace Doctrine \DBAL \Tests \Functional \Driver \Mysqli ;
6
+
7
+ use Doctrine \DBAL \Driver \Mysqli \Statement ;
8
+ use Doctrine \DBAL \Statement as WrapperStatement ;
9
+ use Doctrine \DBAL \Tests \FunctionalTestCase ;
10
+ use Doctrine \DBAL \Tests \TestUtil ;
11
+ use Error ;
12
+ use ReflectionProperty ;
13
+
14
+ /** @requires extension mysqli */
15
+ class StatementTest extends FunctionalTestCase
16
+ {
17
+ protected function setUp (): void
18
+ {
19
+ parent ::setUp ();
20
+
21
+ if (TestUtil::isDriverOneOf ('mysqli ' )) {
22
+ return ;
23
+ }
24
+
25
+ self ::markTestSkipped ('This test requires the mysqli driver. ' );
26
+ }
27
+
28
+ public function testStatementsAreDeallocatedProperly (): void
29
+ {
30
+ $ statement = $ this ->connection ->prepare ('SELECT 1 ' );
31
+
32
+ $ property = new ReflectionProperty (WrapperStatement::class, 'stmt ' );
33
+ $ property ->setAccessible (true );
34
+
35
+ $ driverStatement = $ property ->getValue ($ statement );
36
+
37
+ $ mysqliProperty = new ReflectionProperty (Statement::class, 'stmt ' );
38
+ $ mysqliProperty ->setAccessible (true );
39
+
40
+ $ mysqliStatement = $ mysqliProperty ->getValue ($ driverStatement );
41
+
42
+ unset($ statement , $ driverStatement );
43
+
44
+ $ this ->expectException (Error::class);
45
+ $ this ->expectExceptionMessage ('mysqli_stmt object is already closed ' );
46
+
47
+ $ mysqliStatement ->execute ();
48
+ }
49
+ }
You can’t perform that action at this time.
0 commit comments