Skip to content

Adding a close method or alternatives for persistent objects (i.e. PDO) #15749

Open

Description

@NattyNarwhal

Description

PHP has been moving towards using objects instead of resources. One change as a result of this is that the resource the object represents gets closed on the destructor, instead of calling extension_providing_resource_close methods. Normally, this is OK, as you can just remove all references to an object and have it clean up. However, with persistent resources, the extension holds a reference onto the object that it provides to you, preventing you from being able to destroy the object. This use case might exist for i.e. cleaning up a persistent database connection that has gotten itself into a wedged state that the extension can't handle (i.e. ODBC liveness checks aren't perfect), or closing something to finalize something done over multiple requests.

The easiest option may be to add a close method to the object, similar to what i.e. SQLite3 does. Some extensions like curl already have close methods, but they might have been converted to nops in the resource to object conversion. However, this adds issues with having an object that represents i.e. a connection in a closed state. (However, since one of the cases is say, closing a database connection, we already might have to deal with live objects that represent a resource that's been closed.)

Another option might be to expose a list of currently used persistent resources. get_resources can be abused for this, but contains massive footguns and only works with legacy resources. Perhaps this can be done for persistent objects in general in a safer manner, or have a persistent object list provided by the extension. Persistent object issues can be hard to debug, so this might be generally useful.

See: #15603 (comment) - there might be other conversations on this

Activity

  1. cmb69 commented on Sep 6, 2024

    @cmb69
    Member

    I think there are generally two styles of implementing objects which represent external resources (in the broadest sense): (a) connect/open in the constructor, disconnect/close in the destructor, and (b) have explicit connect/open and disconnect/close methods, and do "nothing" in the constructor and destructor. I'm more in favor of (b), because that is nice for dependency injection (you can just create the object, and pass it around, without having to fear that the creation alone causes some actions, possibly even takes a considerable time). And for languages with garbage collection, doing "nothing" in the destructor is almost mandatory (since you never know when the destructor is called).

    Of course, we cannot easily change existing objects to require an additional call to a connect/open method, but adding a disconnect/close method appears to be sensible, even though that requires to internally track the state (is_open/is_initialized) what is somewhat cumbersome, but not rocket-science. And it is probably a good idea to change existing disconnect/close functions which were converted to no-ops during resource to object conversion to actually disconnect/close (e.g. curl_close() is a good example).

    I wouldn't not want to expose a list of connected/open resources, or a list of persistent resources, other than maybe via reflection. If users want to keep track of that, they can do it manually.

  2. gzhegow1991 commented on Sep 8, 2024

    @gzhegow1991

    Resources also has no handy typehint, always needed to call resource info methods to check is open, is writable, is readable, is curl, is file, is socket or connection.

    So "php has been moving"... Its not a "new way", its "both way required".

    Why not just setting NULL to property that holds connection?
    If you cannot close connection (because you didnt open it right here) - you set connection, then unset connection. If you open it - you close it. Seems logical.

    Any globalization stuff is good on application level, not programming language level (for me).
    So creating any API that can return "all resources under process control" as debug thing - is good. It will help to debug existing application with unknown/undocumented code.

    But wrapping it into separate api/library? Is it really necceseary?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions