Table of Contents

PHP RFC: Add persistent curl share handles

Introduction

PHP, while generally stateless by default, occasionally provides forms of “persistence” for connections, e.g. PDO::ATTR_PERSISTENT for persistent PDO connections.

Persistence allows PHP scripts to eliminate the overhead of establishing a connection on subsequent requests, which can improve performance and reliability.

curl, a popular URL transfer library made available as a core extension in PHP, provides the ability to share data between curl handles via a “share” interface. The PHP extension supports this functionality in curl_share_init and related functions.

The PHP extension does not, however, support persistent curl share handles. Connections (and DNS lookups, SSL session IDs, etc.) are only shared between handles within a single SAPI request.

Proposal

This RFC proposes to add a new function, curl_share_init_persistent($id, $share_options), that will construct a persistent curl share handle.

When called, the function will first check the global memory within the SAPI worker for an existing curl share handle. If found, the function will return immediately.

If a curl share handle does not already exist, the function will construct a new one, apply the given share options, store it in global memory, and return it.

Why not add persistence to curl_share_init?

I had originally attempted to add a single new optional $persistent_id parameter to curl_share_init, and then to call curl_share_setopt on the handle to set share options separately. Unfortunately I ran into https://github.com/curl/curl/pull/14696, where it seems that curl was re-initializing some of the share options in a way that broke functionality.

This issue meant that I needed to set the share options only once in userland, which is difficult or impossible to do. I decided to introduce a new function where the PHP extension could safely know if it needed to apply the share options or not.

At the time of writing the RFC I have come up with a new alternative: we could change the signature of curl_share_init to curl_share_init(array|null $share_options, string|null $persistent_id). I don't have a strong opinion on either.

Backward Incompatible Changes

None expected.

Proposed PHP Version(s)

Next PHP 8.x release.

RFC Impact

To SAPIs

SAPIs will consume more memory proportional to the number of persistent curl share handles.

To Existing Extensions

ext/curl will have a new function.

To Opcache

None.

New Constants

None.

php.ini Defaults

None.

Open Issues

Persistence Implementation

My first attempt at a pull request used the EG(persistent_list) global variable, which uses “internal” (i.e. not directly exposed to userland) resources. I received feedback from @cmb69 that this was deprecated, but https://wiki.php.net/rfc/resource_to_object_conversion does not directly address internal resources. These are currently still used in places like PDO and streams, even when they return objects to userland.

Fortunately I was able to come up with an alternative implementation using ZEND_BEGIN_MODULE_GLOBALS instead, but it's unclear whether this is a better approach. I don't have a strong opinion on which method of persistence I use, only that I'm able to implement persistence at all.

curl_share_close Behavior

From @kocsismate:

I'm wondering if it would make sense to explicitly close persistent shares with curl_share_close? It's a no-op for regular shares, but it may be useful for persistent ones?

Future Scope

Proposed Voting Choices

This vote would require a ⅔ majority:

Add curl share persistence in the next PHP 8.x

This vote would require a simple majority:

Method signature
curl_share_init_persistent(string $id, array $share_options) curl_share_init(?array $share_options, ?string $persistent_id)

Patches and Tests

Implementation

References

Rejected Features