Hello all,
I am announcing discussion phase of RFC "Add PDO disconnect() and
isConnected()". As the title suggests, this proposes to add a PHP interface
to disconnect a PDO client, an alternative to the object destructor.
Thank you in advance for your consideration and guidance.
https://wiki.php.net/rfc/pdo_disconnect
-Robert Wolf
I find this proposal to be a backwards step in the age when we are
moving away from resources and their explicit closure. We have
disabled this in PHP 8.0 for curl_close()
, imagedestroy(),
openssl_pkey_free()
, shmop_close() and xml_parser_free()
. Sure,
mysqli_close()
still works, but the whole extension is mostly a
historical artefact and a bunch of bad design choices due to what that
extension is (quick replacement of mysql_* API). PDO was designed much
better and it deliberately avoided the foot gun that is explicit
connection closure. I really wish we would not introduce bad design
choices into the language, and because of this, I wish this proposal
were unsuccessful.
I find this proposal to be a backwards step in the age when we are
moving away from resources and their explicit closure. We have
disabled this in PHP 8.0 forcurl_close()
, imagedestroy(),
openssl_pkey_free()
, shmop_close() andxml_parser_free()
. Sure,
mysqli_close()
still works, but the whole extension is mostly a
historical artefact and a bunch of bad design choices due to what that
extension is (quick replacement of mysql_* API). PDO was designed much
better and it deliberately avoided the foot gun that is explicit
connection closure. I really wish we would not introduce bad design
choices into the language, and because of this, I wish this proposal
were unsuccessful.
All of the foot gun examples you listed are such because that historic
design pattern required explicit resource frees, and they are foot guns
because it is easy to forget doing that.
Also, mysqli_close()
is the only one that handles a stateful network
connection and not a local resource, which is a good reason why it still
works.
There are legitimate use cases where you may want to explicitly and
immediately close a network connection, even if PHP would do it eventually.
Cheers,
Andrey.
I find this proposal to be a backwards step in the age when we are
moving away from resources and their explicit closure. We have
disabled this in PHP 8.0 forcurl_close()
, imagedestroy(),
openssl_pkey_free()
, shmop_close() andxml_parser_free()
. Sure,
mysqli_close()
still works, but the whole extension is mostly a
historical artefact and a bunch of bad design choices due to what that
extension is (quick replacement of mysql_* API). PDO was designed much
better and it deliberately avoided the foot gun that is explicit
connection closure. I really wish we would not introduce bad design
choices into the language, and because of this, I wish this proposal
were unsuccessful.All of the foot gun examples you listed are such because that historic design pattern required explicit resource frees, and they are foot guns because it is easy to forget doing that.
Also,mysqli_close()
is the only one that handles a stateful network connection and not a local resource, which is a good reason why it still works.There are legitimate use cases where you may want to explicitly and immediately close a network connection, even if PHP would do it eventually.
Cheers,
Andrey.
By foot gun, I meant that when such a method exists, the developer can
never be sure that the PDO object is in a consistent state. As long as
the PDO object is accessible, closing it in one place in the code
means that there exists another place in the code where the object is
accessible but unusable. This is what gets so many mysqli users.
Another issue is that if you call disconnect on PDO object, but you
still have PDOStatement with unfetched data, you silently lose the
data or get an exception. This situation is more difficult to
accidentally arrive at, but still possible. You also lose the ability
to call methods such as PDOStatement::execute(). This is not possible
today, but by adding disconnect method we introduce a way in which
this is possible.
PDO isn't a new extension. It has done well without such a function
for many years. Maybe there are legitimate use cases for this, but
there are also alternatives. Pretty much every time I hear the
argument that it would be nice if PDO had it, I can reply with: you
can just design your code in a way that doesn't need it.
The disconnect method isn't needed for long-running scripts. PHP will
disconnect automatically when it determines that the connection is no
longer needed, and only then. It's the responsibility of the developer
to ensure that they don't keep variables around that aren't necessary
anymore.
I find this proposal to be a backwards step in the age when we are
moving away from resources and their explicit closure. We have
disabled this in PHP 8.0 forcurl_close()
, imagedestroy(),
openssl_pkey_free()
, shmop_close() andxml_parser_free()
.
Thank you for providing these recent examples of resource-to-object
conversions. As you well know, PDO is an object which also optionally uses
PHP persistent resources to facilitate connection re-use across PHP
requests, a feature which I don't believe has a parallel in object space.
Perhaps therein lies a feature request, i.e. to allow an object to be made
persistent in the same way a resource can.
However, as there is no present path for PDO's conversion away from PHP
persistent resources, the prior examples you highlight seem to support an
explicit close interface in PDO, in that so long as PHP resources are
involved, a close method is warranted.
PDO was designed much
better and it deliberately avoided the foot gun that is explicit
connection closure.
I'll push back on the notion that disconnect() is likely to be a foot gun.
In general, a held PDO object does not guarantee an active connection to a
database. Remote connection closures do occur. Networks falter and fail. A
robust application necessarily accounts for connectivity failure states,
and in the case of PDO, is likely validating the success of every database
interaction and reacting accordingly.
Considering, an implementation which unwittingly invokes disconnect() and
permits continued use of the same PDO for database interactions will at
least not error in novel ways. The recommendation for avoiding such
mistakes in implementation would be the same which the community has long
advocated for - decorate your PDOs.
Maybe there are legitimate use cases for this, but
there are also alternatives.
I listed a couple use cases in the RFC, which I'll quote below for some
added context.
- Efficient management of database resources across periods of application
idleness, opening and closing connection as needed. - Interoperability with database environment imposing timeout or other
session constraints, necessitating multiple connections during script
execution. - Abnormal termination procedure in which database closure is highly
prioritized, e.g. security violation. - Testing purposes, e.g. simulation of remote connection failure.
Pretty much every time I hear the
argument that it would be nice if PDO had it, I can reply with: you
can just design your code in a way that doesn't need it.
I tried responding to this in the RFC, also quoted below.
PHP makes the implementation of a decorator simple enough through magic
methods like __call and __get, but this is complicated in PDO by the PDO
statement object, which holds reference to a PDO object, and so must also
be reference-managed. A leak-proof decorator should thus override
PDO::prepare() and PDO::query() to also prevent the leak of the PDO
statement object, likely requiring additional interfaces to otherwise
interact with prepared PDO statements, to e.g. bind parameters and execute
them, and queried PDO statements, to e.g. fetch one row, N rows, one
column, etc. This prescribed implementation pattern is burdensome.
For persistent PDO objects, the user has no native capacity to close a
connection, given that the database handle is inaccessible and registered
as a PHP persistent resource, which remains until the PHP process
terminates. To ensure database connectivity across subsequent PHP requests,
each new PDO object includes a liveness check on the persistent connection,
possibly prompting a new connection. This has meant the burden of defining
a viable database connection resides within the database driver's liveness
check, and that an outcome differing with actual viability as it concerns a
given application results in a non-viable database connection for all
subsequent PHP requests. The proposed disconnect() thus grants the user the
capacity to declare a connection as no-longer viable.
By foot gun, I meant that when such a method exists, the developer can
never be sure that the PDO object is in a consistent state. As long as
the PDO object is accessible, closing it in one place in the code
means that there exists another place in the code where the object is
accessible but unusable. This is what gets so many mysqli users.Another issue is that if you call disconnect on PDO object, but you
still have PDOStatement with unfetched data, you silently lose the
data or get an exception. This situation is more difficult to
accidentally arrive at, but still possible. You also lose the ability
to call methods such as PDOStatement::execute(). This is not possible
today, but by adding disconnect method we introduce a way in which
this is possible.PDO isn't a new extension. It has done well without such a function
for many years. Maybe there are legitimate use cases for this, but
there are also alternatives. Pretty much every time I hear the
argument that it would be nice if PDO had it, I can reply with: you
can just design your code in a way that doesn't need it.The disconnect method isn't needed for long-running scripts. PHP will
disconnect automatically when it determines that the connection is no
longer needed, and only then. It's the responsibility of the developer
to ensure that they don't keep variables around that aren't necessary
anymore.
I generally agree that there's little value to a disconnect() action; unset($pdo) is already sufficient.
What would be valuable is easier RE-connection logic. Either PHP or MySQL may terminate an idle connection, which is a concern in long-running processes (Queue workers, ReactPHP, Franken, etc.). Tools like Doctrine have built their own refresh logic in, although they're not always consistent with each other or obvious to use. Having some kind of reconnection logic built into PDO that "just works" would be very valuable.
What that would look like, I'm not sure. Just spitballing:
// After X seconds, drop and reopen the connection the next time it's used.
$pdo->reconnectAfter($seconds);
--Larry Garfield
Le 30 sept. 2025 à 17:40, Larry Garfield larry@garfieldtech.com a écrit :
What would be valuable is easier RE-connection logic. Either PHP or MySQL may terminate an idle connection, which is a concern in long-running processes (Queue workers, ReactPHP, Franken, etc.). Tools like Doctrine have built their own refresh logic in, although they're not always consistent with each other or obvious to use. Having some kind of reconnection logic built into PDO that "just works" would be very valuable.
What that would look like, I'm not sure. Just spitballing:
// After X seconds, drop and reopen the connection the next time it's used.
$pdo->reconnectAfter($seconds);--Larry Garfield
Auto-reconnection is dangerous, because database engines are stateful. For example, disaster will happen if disconnection had occurred in the middle of a transaction...
—Claude
Le 30 sept. 2025 à 17:40, Larry Garfield larry@garfieldtech.com a écrit :
What would be valuable is easier RE-connection logic. Either PHP or MySQL may terminate an idle connection, which is a concern in long-running processes (Queue workers, ReactPHP, Franken, etc.). Tools like Doctrine have built their own refresh logic in, although they're not always consistent with each other or obvious to use. Having some kind of reconnection logic built into PDO that "just works" would be very valuable.
What that would look like, I'm not sure. Just spitballing:
// After X seconds, drop and reopen the connection the next time it's used.
$pdo->reconnectAfter($seconds);--Larry Garfield
Auto-reconnection is dangerous, because database engines are stateful.
For example, disaster will happen if disconnection had occurred in the
middle of a transaction...—Claude
All the more reason that the logic should be implemented once in PDO and then shared, rather than everyone having to figure it out in user space themselves.
I'm not suggesting that PDO actively try to disconnect all the time. But if the connection is "stale," it should be able to restart it without making the user faff about to do so. (Whether that's via detecting that it's gone away, a timer, or whatever else, I'm very flexible.)
--Larry Garfield
Le 30 sept. 2025 à 23:07, Larry Garfield larry@garfieldtech.com a écrit :
Le 30 sept. 2025 à 17:40, Larry Garfield larry@garfieldtech.com a écrit :
What would be valuable is easier RE-connection logic. Either PHP or MySQL may terminate an idle connection, which is a concern in long-running processes (Queue workers, ReactPHP, Franken, etc.). Tools like Doctrine have built their own refresh logic in, although they're not always consistent with each other or obvious to use. Having some kind of reconnection logic built into PDO that "just works" would be very valuable.
What that would look like, I'm not sure. Just spitballing:
// After X seconds, drop and reopen the connection the next time it's used.
$pdo->reconnectAfter($seconds);--Larry Garfield
Auto-reconnection is dangerous, because database engines are stateful.
For example, disaster will happen if disconnection had occurred in the
middle of a transaction...—Claude
All the more reason that the logic should be implemented once in PDO and then shared, rather than everyone having to figure it out in user space themselves.
I'm not suggesting that PDO actively try to disconnect all the time. But if the connection is "stale," it should be able to restart it without making the user faff about to do so. (Whether that's via detecting that it's gone away, a timer, or whatever else, I'm very flexible.)
--Larry Garfield
Database connections are full of state (apart from transactions, there are also sql variables, temporary tables, and probably other stuff I am not aware of), thus auto-reconnection cannot be transparent in the general case. In specific scenarios, this is ok, but I doubt that it is best managed by a generic extension like pdo.
—Claude
Database connections are full of state (apart from transactions, there are also
sql variables, temporary tables, and probably other stuff I am not aware of),
thus auto-reconnection cannot be transparent in the general case. In specific
scenarios, this is ok, but I doubt that it is best managed by a generic extension
like pdo.
This is exactly why the ability to manually close the connection is badly needed. Just because a connection hasn't been lost doesn't mean it's in a usable state. PDO will happily hand you a reused connection that is not, in fact, still usable. The only way around this issue is to encapsulate PDO such that you can replace the useless instance with a new one, since you cannot currently close a connection that is in an error state.
-Jeff
I don't really see how it would be a bad thing.
This is very useful when you have scripts that are running for a very
long time (eg. daemons).
Le 30 sept. 2025 à 14:49, Robert Wolf rposky@gmail.com a écrit :
Hello all,
I am announcing discussion phase of RFC "Add PDO disconnect() and isConnected()". As the title suggests, this proposes to add a PHP interface to disconnect a PDO client, an alternative to the object destructor.
Thank you in advance for your consideration and guidance.
https://wiki.php.net/rfc/pdo_disconnect
-Robert Wolf
Hi,
I’ve reviewed my uses of mysqli->close() in the wrapper class around mysqli I wrote several years ago. All of them were useless, and I have just deleted them after having carefully checked the documentation. Here is the most obvious case (yes, this is real code):
public function __destruct() {
if ($this->link !== null) {
@ $this->link->close();
$this->link = null;
}
}
I wished that mysqli->close() were never implemented...
Methods like mysqli->close() are innocuous by themselves. The issue is that users are tempted, even incited, to do manual operations that are very well done automatically (in this case, by the garbage collector). They are also driven to ask themselves questions that they don’t need to bother (“what if disconnection fails?”).
If you still have good reasons to add such a method in pdo. I recommend to use a name that deters users from using it in normal operations, e.g. pdo->debug_manual_disconnect().
—Claude
I generally agree that there's little value to a disconnect() action;
unset($pdo) is already sufficient.
See the point again about persistent connections. The user has no means to
disconnect in that case.
I recommend to use a name that deters users from using it in normal
operations, e.g. pdo->debug_manual_disconnect().
Considering the above as well, a possible stance to take could be to
introduce it as persistent_disconnect(). We could then decide whether it
should function on "regular" connections as well.
I generally agree that there's little value to a disconnect() action; unset($pdo) is already sufficient.
See the point again about persistent connections. The user has no means to disconnect in that case.
I recommend to use a name that deters users from using it in normal operations, e.g. pdo->debug_manual_disconnect().
Considering the above as well, a possible stance to take could be to introduce it as persistent_disconnect(). We could then decide whether it should function on "regular" connections as well.
This sounds better, but I would argue that if it's a PERSISTENT
connection, then it should be impossible for the user to close it. The
idea is that the connection should remain open after being established
and should only close when the server restarts. What scenario would
necessitate the user to close a connection that should never close?
This sounds better, but I would argue that if it's a PERSISTENT
connection, then it should be impossible for the user to close it. The
idea is that the connection should remain open after being established
and should only close when the server restarts. What scenario would
necessitate the user to close a connection that should never close?
As I understand it, at least in the case of MySQL, the state of
persistent connections is not managed by MySQL, but by the client (PHP).
This means that it's (at least theoretically) possible for a connection
to end up in an undesirable state, in which case there should be a way
to close it so it's not reused.
I think a disconnect method should be provided, with the proviso that
there should be prominent warnings regarding state management on the
documentation.
I've seen developers getting into trouble after attempting to implement
automatic reconnection in their code with the existing PDO capabilities,
so this already happens anyway.
If something is primarily a footgun, I can see that as reasoning for not
providing it. But a kitchen knife is equally apt at cutting food and
fingers. The latter is not a good reason to not have one in the kitchen
- people can learn to use them safely with adequate instruction.
As an aside, the manual is unclear on how much management of persistent
connections PDO does. I have an open issue on this:
https://github.com/php/doc-en/issues/4540
(I did have a brief look again and based on some further investigation I
did based (initially) on the answer thecotne gave in the above linked
issue, believe that answer may not be accurate, at least in its
reasoning, and thus their conclusion is circumspect. Looking at this
again is somewhere on my todo list, I think)
As I understand it, at least in the case of MySQL, the state of
persistent connections is not managed by MySQL, but by the client (PHP).
This means that it's (at least theoretically) possible for a connection
to end up in an undesirable state, in which case there should be a way
to close it so it's not reused.
You are correct, and I can see this as a justification for adding a
dangerous function; however, the circumstances you describe are very
vague. What is this undesirable state, and how would someone be able
to determine in code that the connection is in an undesirable state?
More importantly, why would they need to close the connection when it
happens instead of restoring it to a working state? The most common
way I can imagine is if you acquire a lock on a table and then PHP
script gets aborted due to an unhandled exception from something else
(e.g. HTTP network request which failed due to outside reasons). But
in that case, the persistent connection should be cleaned up by the
custom error handler on the script's termination. Currently, there is
no way to do that other than manually trying to release all
locks/transactions/tables. A disconnect method would solve that, but
so would a method to trigger COM_CHANGE_USER, which is still a worse
solution than a simple function to reset the connection.
If borked persistent connections are a real problem that needs
solving, then I support adding a function to PDO to reset persistent
connections. In MySQL, it would trigger COM_RESET_CONNECTION, and in
other drivers an analogous solution would need to be found. This
avoids the problem of having the PDO instance in a borked state.
What I am trying to say is that there should be no need to ever close
a persistent connection. If it ever gets messed up, it should be
restored to the working state rather than being closed.
This sounds better, but I would argue that if it's a PERSISTENT
connection, then it should be impossible for the user to close it. The
idea is that the connection should remain open after being established
and should only close when the server restarts.
I think this reads too much into the "persistent" language, which does not
derive from PDO but rather PHP resources. PDO cannot guarantee a connection
always be open, nor should it be defining what connection viability is -
it's an application-level concern, and an overreach.
What scenario would necessitate the user to close a connection that
should never close?
I provided some examples in the thread as to why a user could want to close
a connection, maybe unconvincingly.
What I am trying to say is that there should be no need to ever close
a persistent connection. If it ever gets messed up, it should be
restored to the working state rather than being closed.
Thinking along these lines, what could meet this objective and satisfy some
of the concerns outlined here, would be an interface to declare the
persistent connection as defunct, such that upon subsequent PDO creation, a
new connection will be formed, and the former will be closed. This is
distinct from a disconnect or reconnect procedure, and similar to failing a
"liveness" check upon persistent PDO creation. Users could then effectively
replace their persistent PDO in the same manner they would do so for a
"regular" PDO.
Difficulties in unset($pdo) to force a disconnect are still present though
perhaps can be mitigated with the refactoring efforts outlined in "Future
Scope" to break apart the mutual PDO and PDO statement references.
As an aside, the manual is unclear on how much management of
persistent connections PDO does. I have an open issue on this:
https://github.com/php/doc-en/issues/4540(I did have a brief look again and based on some further investigation
I did based (initially) on the answer thecotne gave in the above
linked issue, believe that answer may not be accurate, at least in its
reasoning, and thus their conclusion is circumspect. Looking at this
again is somewhere on my todo list, I think)
An update: Based on testing, PDO (MySQL) does not perform cleanup of
state of persistent connections - this means transactions, temporary
tables, locks and other stateful changes may remain, causing the
connection to be in an unexpected state.
For details of my test see
https://github.com/php/doc-en/issues/4540#issuecomment-3368381887
In my opinion, this makes a method of forcing a (persistent) connection
closed explicitly useful.
I generally agree that there's little value to a disconnect() action; unset($pdo) is already sufficient.
See the point again about persistent connections. The user has no means to disconnect in that case.
I recommend to use a name that deters users from using it in normal operations, e.g. pdo->debug_manual_disconnect().
Considering the above as well, a possible stance to take could be to introduce it as persistent_disconnect(). We could then decide whether it should function on "regular" connections as well.
This sounds better, but I would argue that if it's a PERSISTENT
connection, then it should be impossible for the user to close it. The
idea is that the connection should remain open after being established
and should only close when the server restarts. What scenario would
necessitate the user to close a connection that should never close?
Off the top of my head (and it depends on the actual database on the other end of the pipe):
- After grant/role revocation, password rotation, or a switch from read/write replicas. Existing sessions usually keep there their privileges in a lot of databases. So, you could argue this is a security issue for long-lived applications.
- Perhaps you want to free any and all advisory locks?
- Sometimes the handle is alive, but the network connection is dead (this is argued elsewhere though).
- I've had some fun bugs in the past with prepared statements crashing a db server (putting it in maintenance mode and serving no traffic) being shared between requests. If I could have slapped a "just close it until we figure out what is going on" statement in there, I would have.
- Replica promotion, primary failover, blue/green cutovers, firewall changes ... all these need new connections.
Right now, you have to jump through a number of hoops to do these types of operations.
— Rob
Hi,
Il 01/10/2025 20:07, Rob Landers ha scritto:
This sounds better, but I would argue that if it's a PERSISTENT
connection, then it should be impossible for the user to close it. The
idea is that the connection should remain open after being established
and should only close when the server restarts. What scenario would
necessitate the user to close a connection that should never close?Off the top of my head (and it depends on the actual database on the
<snip>
other end of the pipe):Right now, you have to jump through a number of hoops to do these types
of operations.
During the years I've seen so many horror stories related to usage of
persistent connections. I would argue we should discourage their use
(deprecation is my dream!) rather than encouraging it by adding new
features.
My 2c.
Cheers
Matteo Beccati
I would argue we should discourage their use
(deprecation is my dream!)
I am with you on the deprecation of persistent connections, as the
implementation is awkward, but not without addressing the use case.
As you well know, PDO is an object which also optionally uses PHP
persistent resources to facilitate connection re-use across PHP requests, a
feature which I don't believe has a parallel in object space. Perhaps > >
therein lies a feature request, i.e. to allow an object to be made
persistent in the same way a resource can.
I floated the above idea. Any inclination that would be worth pursuing?
... would be an interface to declare the persistent connection as
defunct, such that upon subsequent PDO creation, a new connection will be
formed, and the former will be closed. This is distinct from a disconnect
or > reconnect procedure, and similar to failing a "liveness" check upon
persistent PDO creation. Users could then effectively replace their
persistent PDO in the same manner they would do so for a "regular" PDO.
This idea is growing on me, to address the issue of a defunct persistent
connection, rather than the disconnect() interface. Any thoughts on
introducing a new attribute to the PDO constructor to prompt the
reconnection: PDO::ATTR_PERSISTENT_RECONNECT.
-Robert