[RFC][DISCUSSION] Object-oriented curl API v2

php.internals

Eric Norris

1 year ago
Hello Internals, I'd like to formally propose a restart of the original object-oriented curl API RFC (https://wiki.php.net/rfc/curl-oop): https://wiki.php.net/rfc/curl_oop_v2 The prior RFC seemed to get positive feedback, with a small consensus around wanting enum(s) for curl options. I've taken that feedback and incorporated it into a new RFC, as I am not the original author, but I am interested in making another potential improvement to the curl extension. In a nutshell, this version of the RFC: - uses enumerations for curl options and other curl constants - introduces a new Curl namespace I have not yet created an implementation PR. I realize that is somewhat discouraged, but I believe that this should be relatively straightforward to implement (there's also the previous RFC's PR to build on top of). The implementation of this RFC as it is now will likely be tedious, however, so I'd like to get feedback on the enumeration idea before committing to the work. I've outlined one open question in the RFC, which relates to the above: - Should we organize the curl option enumerations by value type? Or have a single enumeration for all curl_setopt options and another for all curl_multi_setopt options? If others (including the original RFC author) are interested in working with me on this, I'm more than open to that, so please let me know. Thanks, Eric

Larry Garfield

1 year ago
On Thu, Jun 26, 2025, at 11:25 AM, Eric Norris wrote:
> Hello Internals, > > I'd like to formally propose a restart of the original object-oriented > curl API RFC (https://wiki.php.net/rfc/curl-oop): > > https://wiki.php.net/rfc/curl_oop_v2 > > The prior RFC seemed to get positive feedback, with a small consensus > around wanting enum(s) for curl options. I've taken that feedback and > incorporated it into a new RFC, as I am not the original author, but I > am interested in making another potential improvement to the curl > extension. > > In a nutshell, this version of the RFC: > > - uses enumerations for curl options and other curl constants > - introduces a new Curl namespace > > I have not yet created an implementation PR. I realize that is > somewhat discouraged, but I believe that this should be relatively > straightforward to implement (there's also the previous RFC's PR to > build on top of). The implementation of this RFC as it is now will > likely be tedious, however, so I'd like to get feedback on the > enumeration idea before committing to the work. > > I've outlined one open question in the RFC, which relates to the above: > > - Should we organize the curl option enumerations by value type? Or > have a single enumeration for all curl_setopt options and another for > all curl_multi_setopt options? > > If others (including the original RFC author) are interested in > working with me on this, I'm more than open to that, so please let me > know. > > Thanks, > Eric
I still support this effort. 1. I don't think the Curl\Option namespace is necessary. They can just be in the main Curl namespace. 2. Please don't name the exception "Exception". It needs some slightly more useful name, to avoid confusion in a file that also uses \Exception. 3. I realize `Handle` is the name from the procedural API, but it's not very self-descriptive. Without knowing Curl, it's non-obvious that it's a self-executing request object. Is there a better name we could find while we're at it? 4. Love the use of aviz. :-) 5. Now here's the big one: Using enums rather than a bunch of constants is a good change. However, I feel like it doesn't go far enough. For instance, $ch = new Curl\Handle("https://example.com") ->setOptionInt(Curl\Option\IntOpt::ConnectTimeout, 30) ->setOptionBool(Curl\Option\BoolOpt::FollowLocation, true); Would be 10x easier to use were it: $ch = new Curl\Handle("https://example.com") ->setConnectionTimeout(30) ->setFollowLocation((true); Or for that matter, properties would now allow for those to even just be set directly on typed properties. (Though it wouldn't be chainable.) I realize that would be considerably more work to define all those methods (I don't even know how many Curl has, as I rarely use it directly). But it would result in a vastly easier to use API than "set some random integer-based field(EnumName, 30)". The latter is highly non-obvious. Especially when getting into POST requests with different body formats (something the RFC should include examples of), IMO, good ergonomics is more important than looking like the old, horribly obtuse API. As a worst case, perhaps the top-20 options or so could be converted to methods/properties, and the rest left to be ugly flags? --Larry Garfield

Eric Norris

1 year ago
Thanks Larry!
> 1. I don't think the Curl\Option namespace is necessary. They can just be in the main Curl namespace.
I don't feel strongly here, but I thought it would be nice to group the enums (if we go the multiple enum route) for discoverability. Thoughts?
> 2. Please don't name the exception "Exception". It needs some slightly more useful name, to avoid confusion in a file that also uses \Exception.
Fair point! I could use the previous RFC's HandleException class name, barring your next point...
> 3. I realize `Handle` is the name from the procedural API, but it's not very self-descriptive. Without knowing Curl, it's non-obvious that it's a self-executing request object. Is there a better name we could find while we're at it?
I'm open to this, but I don't have a suggestion myself.
> 4. Love the use of aviz. :-)
Thanks :) I was happy to be able to use it here.
> 5. Now here's the big one: Using enums rather than a bunch of constants is a good change. However, I feel like it doesn't go far enough. > ... > As a worst case, perhaps the top-20 options or so could be converted to methods/properties, and the rest left to be ugly flags?
I think my hesitation here is related to Ben's sibling response: I want to thread the needle between making small improvements to the low-level API while translating them to object-oriented equivalents, and making a high-level API. The latter, I think, would invite a lot more discussion, and would be potentially hard to get right. That said, maybe your suggestion does thread that needle; having a method / property for the N most-used options is still relatively low-level since it's not expressing an opinion on how they should be used. I'm not sure.

Rowan Tommins [IMSoP]

1 year ago
On 26/06/2025 17:53, Larry Garfield wrote:
> Now here's the big one: Using enums rather than a bunch of constants is a good change. However, I feel like it doesn't go far enough.
100% this. Writing "$ch->setOptionInt(Curl\Option\IntOpt::ConnectTimeout, 30);" instead of "curl_setopt(CURLOPT_CONNECTTIMEOUT, 30);" is mostly rearranging the punctuation deck-chairs on the ugly code Titanic. Particularly when you can *also* write "$ch->setOptionInt(Curl\Option\IntOpt::ConnectTimeoutMs, 30_000);" with the same effect.
> I realize that would be considerably more work to define all those methods (I don't even know how many Curl has, as I rarely use it directly).
I believe there are 272 "CURLOPT_" constants currently documented in the PHP manual: https://www.php.net/manual/en/curl.constants.php So, I totally agree that we need a "set raw option" method to support some of the more niche features. But that long list is also exactly why we badly need helpers for common use cases - the manual page for curl_setopt has been at the top of the charts for number of user comments for years, because nobody wants to read the descriptions for two hundred options they'll never need. On 26/06/2025 18:21, Eric Norris wrote:
> I know that in the prior discussion, Rowan Tommins had a vision for a > high-level API (https://externals.io/message/122371#122424)
I think calling it a "vision for a high-level API" is making it sound far more grandiose than what I suggested. What I suggested, and would still like to see, is a small number of additional methods, for setting really common options in a more user-friendly way. Looking at my earlier message, my finger-in-the-air number was even smaller than Larry's - a set of 10 methods, each covering a handful of overlapping or closely related options. A single "setHttpMethod" method would bring immediate value, instead of choosing between CURLOPT_HTTPGET, CURLOPT_POST, CURLOPT_PUT, CURLOPT_NOBODY (for HEAD) and CURLOPT_CUSTOMREQUEST. Adding more helpers in later versions is entirely trivial, but we could set the precedent with a first batch on day one. The only other "high-level" API I see discussed in the previous thread is splitting the execute() method, for exactly the same reason as splitting setOpt(): type safety. public function executeAndReturn(): string public function executeAndOutput(): void public function executeToFile(Stream $fileHandle): void public function executeWithCallback(callable $wrIteFunction): void The CURLOPT_RETURNTRANSFER, CURLOPT_FILE, and CURLOPT_WRITEFUNCTION would then not exist in the option enum(s), because there would be no way to make use of them. Unlike the helper methods, that's one we have to decide in advance - it would be a mess to have those *as well as* a universal "execute(): ?string".
-- Rowan Tommins [IMSoP]

Deleu

1 year ago
> > On 26 Jun 2025, at 18:07, Rowan Tommins [IMSoP] <imsop.php@rwec.co.uk> wrote: > > On 26/06/2025 17:53, Larry Garfield wrote: > >> Now here's the big one: Using enums rather than a bunch of constants is a good change. However, I feel like it doesn't go far enough. > > > 100% this. > > Writing "$ch->setOptionInt(Curl\Option\IntOpt::ConnectTimeout, 30);" instead of "curl_setopt(CURLOPT_CONNECTTIMEOUT, 30);" is mostly rearranging the punctuation deck-chairs on the ugly code Titanic. > > Particularly when you can *also* write "$ch->setOptionInt(Curl\Option\IntOpt::ConnectTimeoutMs, 30_000);" with the same effect. > > > >> I realize that would be considerably more work to define all those methods (I don't even know how many Curl has, as I rarely use it directly). > > > I believe there are 272 "CURLOPT_" constants currently documented in the PHP manual: https://www.php.net/manual/en/curl.constants.php > > So, I totally agree that we need a "set raw option" method to support some of the more niche features. > > But that long list is also exactly why we badly need helpers for common use cases - the manual page for curl_setopt has been at the top of the charts for number of user comments for years, because nobody wants to read the descriptions for two hundred options they'll never need. > > > >> On 26/06/2025 18:21, Eric Norris wrote: >> I know that in the prior discussion, Rowan Tommins had a vision for a >> high-level API (https://externals.io/message/122371#122424) > > > I think calling it a "vision for a high-level API" is making it sound far more grandiose than what I suggested. What I suggested, and would still like to see, is a small number of additional methods, for setting really common options in a more user-friendly way. > > Looking at my earlier message, my finger-in-the-air number was even smaller than Larry's - a set of 10 methods, each covering a handful of overlapping or closely related options. > > A single "setHttpMethod" method would bring immediate value, instead of choosing between CURLOPT_HTTPGET, CURLOPT_POST, CURLOPT_PUT, CURLOPT_NOBODY (for HEAD) and CURLOPT_CUSTOMREQUEST. > > Adding more helpers in later versions is entirely trivial, but we could set the precedent with a first batch on day one. > > > The only other "high-level" API I see discussed in the previous thread is splitting the execute() method, for exactly the same reason as splitting setOpt(): type safety. > > public function executeAndReturn(): string > public function executeAndOutput(): void > public function executeToFile(Stream $fileHandle): void > public function executeWithCallback(callable $wrIteFunction): void > > The CURLOPT_RETURNTRANSFER, CURLOPT_FILE, and CURLOPT_WRITEFUNCTION would then not exist in the option enum(s), because there would be no way to make use of them. > > Unlike the helper methods, that's one we have to decide in advance - it would be a mess to have those *as well as* a universal "execute(): ?string". > > > -- > Rowan Tommins > [IMSoP]
I’m excited at just the discussion of a possibility for PHP to be able to perform basic HTTP requests in a friendly way. Last month I worked on a solution that involved an SQS Worker that do some work and then sends the output back to the origin via a HTTP request that is passed as part of the message; basically a callback over the wire. However, running it on Serverless as a plugin that makes no assumption about the project state, I couldn’t use Guzzle or any composer library for that matter. I had to stick with what’s available on Amazon Linux and Bref, which cURL is, but it’s such an unpleasant experience to have to write HTTP requests like it’s 2003. I really hope some minor helpers can be added to this OOP version of cURL and I agree that it doesn’t need to be hashed out, perfect or even cover 270 cases. Just a simple GET/POST/PUT/PATCH/DELETE with a string body and some headers manipulation would go 99% of the way already.

Eric Norris

1 year ago
Thanks Rowan!
> I think calling it a "vision for a high-level API" is making it sound > far more grandiose than what I suggested. What I suggested, and would > still like to see, is a small number of additional methods, for setting > really common options in a more user-friendly way.
I apologize for misrepresenting your suggestion. I was mainly responding to your "the eventual aim should be that users don't need a userland wrapper" comment, which I worry sounds closer to what Ben was (I believe) objecting to - a higher-level wrapper. Upon re-reading though, I think that's potentially an unfair take - you did go on to say "...just to make a simple request in a readable way".
> Looking at my earlier message, my finger-in-the-air number was even > smaller than Larry's - a set of 10 methods, each covering a handful of > overlapping or closely related options. > > A single "setHttpMethod" method would bring immediate value, instead of > choosing between CURLOPT_HTTPGET, CURLOPT_POST, CURLOPT_PUT, > CURLOPT_NOBODY (for HEAD) and CURLOPT_CUSTOMREQUEST. > > Adding more helpers in later versions is entirely trivial, but we could > set the precedent with a first batch on day one.
I'm not opposed to this, but I am - as previously stated - nervous about how and where we draw this line, since I expect there may be a lot of opinions here. That said, if the general consensus is that we want direct methods or properties for the N most common use-cases, I'm happy to make that change to the RFC. I can try to take a look at the curl options and do some github searches to see if I can identify common patterns. I agree that setting the HTTP method and timeout are good contenders. If someone else wants to propose a list as well, feel free!
> The only other "high-level" API I see discussed in the previous thread > is splitting the execute() method, for exactly the same reason as > splitting setOpt(): type safety. > > public function executeAndReturn(): string > public function executeAndOutput(): void > public function executeToFile(Stream $fileHandle): void > public function executeWithCallback(callable $wrIteFunction): void > > The CURLOPT_RETURNTRANSFER, CURLOPT_FILE, and CURLOPT_WRITEFUNCTION > would then not exist in the option enum(s), because there would be no > way to make use of them. > > Unlike the helper methods, that's one we have to decide in advance - it > would be a mess to have those *as well as* a universal "execute(): ?string".
If we were to go this route, I would suggest: public function fetch(): string public function execute(resource|callable $out): void that is, one method to just return the contents of the URL, and another to either write output to a file (including STDOUT, if the user desires), or to send output to a write callback.

Larry Garfield

1 year ago
On Thu, Jun 26, 2025, at 10:51 PM, Eric Norris wrote:
>> Adding more helpers in later versions is entirely trivial, but we could >> set the precedent with a first batch on day one. > > I'm not opposed to this, but I am - as previously stated - nervous > about how and where we draw this line, since I expect there may be a > lot of opinions here. That said, if the general consensus is that we > want direct methods or properties for the N most common use-cases, I'm > happy to make that change to the RFC. > > I can try to take a look at the curl options and do some github > searches to see if I can identify common patterns. I agree that > setting the HTTP method and timeout are good contenders. If someone > else wants to propose a list as well, feel free!
My gut sense is that the following use cases would cover the 80% case: GET http://www.example.com/foo?bar=baz (Send a GET request with a complex URL. Probably needs both transparent redirecting and not options.) POST http://www.example.com/foo with a JSON body (This means setting a body string/array, and a content-type header.) POST http://www.example.com/foo with a multipart/form-data body (This means making it easy to set the body, and corresponding content-type header.) And those should also allow setting an Accept header. Which means probably any header should be easy to set, with maybe one or two extra-promoted ones. (Like, when setting the body you can also set the content type?) I don't know if specifying an HTTP version is relevant/useful. I have never done so myself, but that proves little. On the return side, I almost always check the status code, at least. That's probably the only non-body thing I check. :-) So making that trivial is also important. Whether that's via a mini-response object instead of a string or something else is open for discussion, I think. Other questions: * We have these shiny new URL/URI objects. Should those be supported directly? --Larry Garfield

Rowan Tommins [IMSoP]

1 year ago
On 27/06/2025 04:51, Eric Norris wrote:
> I can try to take a look at the curl options and do some github > searches to see if I can identify common patterns. I agree that > setting the HTTP method and timeout are good contenders. If someone > else wants to propose a list as well, feel free!
For what it's worth, I grepped my work code base for "CURLOPT_", and grouped the results into the categories below. Some of these are definitely more "advanced" than others, and a lot could just be one helper covering the whole category. Really basic (already in the proposed constructor): CURLOPT_URL Setting HTTP method: CURLOPT_HTTPGET CURLOPT_POST CURLOPT_CUSTOMREQUEST Request body (despite name, handles both form data and raw string bodies): CURLOPT_POSTFIELDS Request headers: CURLOPT_HTTPHEADER CURLOPT_USERAGENT CURLOPT_ENCODING (deprecated in favour of CURLOPT_ACCEPT_ENCODING) Response body handling: CURLOPT_FILE CURLOPT_RETURNTRANSFER Response header handling (extremely fiddly; it would be AMAZING to have something like getLastResponseHeaders() returning an array): CURLOPT_HEADER CURLOPT_HEADERFUNCTION Auth: CURLOPT_HTTPAUTH CURLOPT_USERPWD CURLOPT_SSLCERT (there's also a CURLOPT_SSLCERT_BLOB) CURLOPT_SSLKEY Error and redirect handling: CURLOPT_FOLLOWLOCATION CURLOPT_FAILONERROR Timeouts: CURLOPT_CONNECTTIMEOUT CURLOPT_TIMEOUT CURLOPT_TIMEOUT_MS Cookie handling: CURLOPT_COOKIE CURLOPT_COOKIEFILE CURLOPT_COOKIEJAR Connection parameter tuning: CURLOPT_HTTP_VERSION CURLOPT_SSLVERSION CURLOPT_SSL_VERIFYPEER (common, but shouldn't be!) Debug output (like response headers, this is very unintuitive for PHP users; $ch->enableVerboseLogs() and $ch->getVerboseLogs() would be very handy): CURLOPT_VERBOSE CURLOPT_CAINFO CURLOPT_STDERR
> If we were to go this route, I would suggest: > > public function fetch(): string > public function execute(resource|callable $out): void > > that is, one method to just return the contents of the URL, and > another to either write output to a file (including STDOUT, if the > user desires), or to send output to a write callback.
That makes a lot of sense! I've never been very good at keeping names and sentences short :)
-- Rowan Tommins [IMSoP]

Paul M. Jones

1 year ago
Hi all,
> On 26/06/2025 18:21, Eric Norris wrote: >> I know that in the prior discussion, Rowan Tommins had a vision for a >> high-level API (https://externals.io/message/122371#122424) > > > I think calling it a "vision for a high-level API" is making it sound far more grandiose than what I suggested. What I suggested, and would still like to see, is a small number of additional methods, for setting really common options in a more user-friendly way.
To avoid drifting too much from existing expectations about how such a cURL interface *ought* to look (as vs what happened with the URL RFC) it would be wise to examine existing userland work earlier rather than later. A brief search at https://packagist.org/?query=curl reveals https://packagist.org/packages/php-curl-class/php-curl-class and https://packagist.org/packages/curl/curl right away, each with millions of downloads already. These and other userland offerings should help inform the first steps, in any case. -- pmj

Tim Düsterhus

1 year ago
Hi Am 2025-06-26 18:53, schrieb Larry Garfield:
> 2. Please don't name the exception "Exception". It needs some slightly > more useful name, to avoid confusion in a file that also uses > \Exception.
More specifically, since it does introduce an entirely new namespace it should be considered a “new extension” and must therefore follow the Exception policy outlined in: https://github.com/php/policies/blob/main/coding-standards-and-naming.rst#throwables Best regards Tim Düsterhus

Eric Norris

1 year ago
> More specifically, since it does introduce an entirely new namespace it > should be considered a “new extension” and must therefore follow the > Exception policy outlined in: > https://github.com/php/policies/blob/main/coding-standards-and-naming.rst#throwables
Embarrassingly, I had read your RFC adding that section - it's kind of what got me thinking about adding a curl namespace in the first place! - but I guess I didn't put it into long-term memory. Thanks for the catch, I'll update that when I can.

Ben Ramsey

1 year ago
On Thu, Jun 26, 2025 at 11:27 Eric Norris <eric.t.norris@gmail.com> wrote:
> Hello Internals, > > I'd like to formally propose a restart of the original object-oriented > curl API RFC (https://wiki.php.net/rfc/curl-oop): > > https://wiki.php.net/rfc/curl_oop_v2 > > The prior RFC seemed to get positive feedback, with a small consensus > around wanting enum(s) for curl options. I've taken that feedback and > incorporated it into a new RFC, as I am not the original author, but I > am interested in making another potential improvement to the curl > extension. > > In a nutshell, this version of the RFC: > > - uses enumerations for curl options and other curl constants > - introduces a new Curl namespace > > I have not yet created an implementation PR. I realize that is > somewhat discouraged, but I believe that this should be relatively > straightforward to implement (there's also the previous RFC's PR to > build on top of). The implementation of this RFC as it is now will > likely be tedious, however, so I'd like to get feedback on the > enumeration idea before committing to the work. > > I've outlined one open question in the RFC, which relates to the above: > > - Should we organize the curl option enumerations by value type? Or > have a single enumeration for all curl_setopt options and another for > all curl_multi_setopt options? > > If others (including the original RFC author) are interested in > working with me on this, I'm more than open to that, so please let me > know. > > Thanks, > Eric
IMO, this sounds like something that would be great to start as a userland OOP wrapper for cURL, where it can be iterated on and the interface can be tested and changed much quicker. Then, maybe proceed to an external extension that can be migrated into core later, once its interface is stable. cURL is massive, and there are a lot of moving parts. I wouldn’t expect to get the API correct on the first try. :-) Cheers, Ben

Eric Norris

1 year ago
> IMO, this sounds like something that would be great to start as a userland OOP wrapper for cURL, where it can be iterated on and the interface can be tested and changed much quicker. Then, maybe proceed to an external extension that can be migrated into core later, once its interface is stable. > > cURL is massive, and there are a lot of moving parts. I wouldn’t expect to get the API correct on the first try. :-) > > Cheers, > Ben
(Apologies for the double-post Ben, I'm a little rusty and forgot to reply-all) I see, thanks for your feedback! To clarify, I am not aiming to produce a high-level API for curl. I would expect that most users would still reach for libraries like Guzzle, etc. I know that in the prior discussion, Rowan Tommins had a vision for a high-level API (https://externals.io/message/122371#122424), but I share your sentiment that this would be difficult to get right in core. I'd prefer to aim for a (mostly) direct translation of the low-level API, which I think still has benefits on its own.

Unnamed Person

1 year ago
> Ben Ramsey <ramsey@php.net> hat am 26.06.2025 18:54 CEST geschrieben: > > > On Thu, Jun 26, 2025 at 11:27 Eric Norris <eric.t.norris@gmail.com mailto:eric.t.norris@gmail.com> wrote: > > > Hello Internals, > > > > I'd like to formally propose a restart of the original object-oriented > > curl API RFC (https://wiki.php.net/rfc/curl-oop): > > > > https://wiki.php.net/rfc/curl_oop_v2 > > > > The prior RFC seemed to get positive feedback, with a small consensus > > around wanting enum(s) for curl options. I've taken that feedback and > > incorporated it into a new RFC, as I am not the original author, but I > > am interested in making another potential improvement to the curl > > extension. > > > > In a nutshell, this version of the RFC: > > > > - uses enumerations for curl options and other curl constants > > - introduces a new Curl namespace > > > > I have not yet created an implementation PR. I realize that is > > somewhat discouraged, but I believe that this should be relatively > > straightforward to implement (there's also the previous RFC's PR to > > build on top of). The implementation of this RFC as it is now will > > likely be tedious, however, so I'd like to get feedback on the > > enumeration idea before committing to the work. > > > > I've outlined one open question in the RFC, which relates to the above: > > > > - Should we organize the curl option enumerations by value type? Or > > have a single enumeration for all curl_setopt options and another for > > all curl_multi_setopt options? > > > > If others (including the original RFC author) are interested in > > working with me on this, I'm more than open to that, so please let me > > know. > > > > Thanks, > > Eric > > > > > IMO, this sounds like something that would be great to start as a userland OOP wrapper for cURL, where it can be iterated on and the interface can be tested and changed much quicker. Then, maybe proceed to an external extension that can be migrated into core later, once its interface is stable. > > cURL is massive, and there are a lot of moving parts. I wouldn’t expect to get the API correct on the first try. :-) > > Cheers, > Ben >
see: https://github.com/phpcurl/curlwrapper

Jordi Boggiano

1 year ago
On 26.06.2025 18:25, Eric Norris wrote:
> - uses enumerations for curl options and other curl constants
Overall I think the RFC is a good opportunity to clean up a few legacy oddities in the curl API, but I need to throw in my 2c about enum usage here, as someone that has actually implemented some complexish curl-based client [1]. Currently the API is:     curl_setopt($h, CURLOPT_SMTH, 3); Now moving this into multiple enums to me brings one major issue, that I first have to think about which type the option has to then know on which enum I find it. I understand this brings type safety on the value side if you have multiple setOptionInt etc, but that does not seem worth the trade-off to me. Type safety can already be done in static analyzers as they can see which option you pass in, they know which value should be allowed. Then on top of that, assuming we'd put all options in one enum.. I am still wondering what the added value is compared to simply having the global constants (they could be namespaced if anything...). It's longer to type, and does not provide any better autocompletion. \Curl\Option::ConnectTimeout vs CURLOPT_CONNECT_TIMEOUT sounds ok to me if people feel strongly pro-enum, but I do really hope it is then a single enum + setOption() call. Best, Jordi [1] https://github.com/composer/composer/blob/main/src/Composer/Util/Http/CurlDownloader.php Jordi Boggiano @seldaek - https://seld.be

Deleu

1 year ago
On Fri, Jun 27, 2025 at 9:24 AM Jordi Boggiano <j.boggiano@seld.be> wrote:
> On 26.06.2025 18:25, Eric Norris wrote: > > - uses enumerations for curl options and other curl constants > > Overall I think the RFC is a good opportunity to clean up a few legacy > oddities in the curl API, but I need to throw in my 2c about enum usage > here, as someone that has actually implemented some complexish > curl-based client [1]. > > Currently the API is: > > curl_setopt($h, CURLOPT_SMTH, 3); > > Now moving this into multiple enums to me brings one major issue, that I > first have to think about which type the option has to then know on > which enum I find it. > > I understand this brings type safety on the value side if you have > multiple setOptionInt etc, but that does not seem worth the trade-off to > me. Type safety can already be done in static analyzers as they can see > which option you pass in, they know which value should be allowed. > > Then on top of that, assuming we'd put all options in one enum.. I am > still wondering what the added value is compared to simply having the > global constants (they could be namespaced if anything...). It's longer > to type, and does not provide any better autocompletion. > \Curl\Option::ConnectTimeout vs CURLOPT_CONNECT_TIMEOUT sounds ok to me > if people feel strongly pro-enum, but I do really hope it is then a > single enum + setOption() call. > > Best, > Jordi > > [1] > > https://github.com/composer/composer/blob/main/src/Composer/Util/Http/CurlDownloader.php > > Jordi Boggiano > @seldaek - https://seld.be >
Reading this I can't help but feel like there's some cognitive bias *because* you have written a Curl class yourself. The author of a PHP Class that wraps Curl needs to know about every option and how to translate them back-and-forth, which is really the insight I take from your message. As a PHP developer making HTTP requests, I would never have guessed 270 options for Curl configurations and having them split into multiple Enums gives me smaller "boxes" that are easier to mentally parse individually. With that said, splitting enumerations by type rather than context does weaken the argument of split enums. I wouldn't be instinctively looking for "what enum do I need that is an int?" or "what enum do I need that is a string?" unless I already know the implementation details by heart. The Info and Pause enumerations seem more useful in that regard as they reduce the scope in which I need to understand, process and decide. With that said, for me this also threads into the bikeshedding area that could spiral into a failed RFC. Be it a single Enum for everything, constants, context-based enums or type-based enums, I would much rather have this RFC than not have it. PHP is one of the most important Web applications in the world and it severely lacks the ability to simplify Http. We could take inspiration from Python Requests [1] or Node Fetch [2] as a really simple and straightforward API that covers the vast majority of cases. I take the point that we don't need to go all the way and invent a RequestClient library in PHP and this RFC is threading on the small step of converting Curl procedural API into OOP, which is where Larry and Rowans recommendations about some minor helper methods go a really really long way compared to where we are today. [1] https://www.w3schools.com/PYTHON/ref_requests_post.asp [2] https://nodejs.org/en/learn/getting-started/fetch#basic-post-usage
-- Marco Deleu

Larry Garfield

1 year ago
On Fri, Jun 27, 2025, at 8:01 AM, Deleu wrote:
> On Fri, Jun 27, 2025 at 9:24 AM Jordi Boggiano <j.boggiano@seld.be> wrote: >> On 26.06.2025 18:25, Eric Norris wrote: >> > - uses enumerations for curl options and other curl constants >> >> Overall I think the RFC is a good opportunity to clean up a few legacy >> oddities in the curl API, but I need to throw in my 2c about enum usage >> here, as someone that has actually implemented some complexish >> curl-based client [1]. >> >> Currently the API is: >> >> curl_setopt($h, CURLOPT_SMTH, 3); >> >> Now moving this into multiple enums to me brings one major issue, that I >> first have to think about which type the option has to then know on >> which enum I find it. >> >> I understand this brings type safety on the value side if you have >> multiple setOptionInt etc, but that does not seem worth the trade-off to >> me. Type safety can already be done in static analyzers as they can see >> which option you pass in, they know which value should be allowed. >> >> Then on top of that, assuming we'd put all options in one enum.. I am >> still wondering what the added value is compared to simply having the >> global constants (they could be namespaced if anything...). It's longer >> to type, and does not provide any better autocompletion. >> \Curl\Option::ConnectTimeout vs CURLOPT_CONNECT_TIMEOUT sounds ok to me >> if people feel strongly pro-enum, but I do really hope it is then a >> single enum + setOption() call. >> >> Best, >> Jordi >> >> [1] >> https://github.com/composer/composer/blob/main/src/Composer/Util/Http/CurlDownloader.php >> >> Jordi Boggiano >> @seldaek - https://seld.be > > Reading this I can't help but feel like there's some cognitive bias > *because* you have written a Curl class yourself. The author of a PHP > Class that wraps Curl needs to know about every option and how to > translate them back-and-forth, which is really the insight I take from > your message. As a PHP developer making HTTP requests, I would never > have guessed 270 options for Curl configurations and having them split > into multiple Enums gives me smaller "boxes" that are easier to > mentally parse individually. With that said, splitting enumerations by > type rather than context does weaken the argument of split enums. I > wouldn't be instinctively looking for "what enum do I need that is an > int?" or "what enum do I need that is a string?" unless I already know > the implementation details by heart. The Info and Pause enumerations > seem more useful in that regard as they reduce the scope in which I > need to understand, process and decide.
I will agree here. Splitting enums by type doesn't add much value. Splitting them by topic might, if the topics are sufficiently distinct that a separate method makes sense. I don't know Curl's API well enough to make specific recommendations there. --Larry Garfield

Ben Ramsey

1 year ago
On 6/27/25 08:01, Deleu wrote:
> With that said, for me this also threads into the bikeshedding area > that could spiral into a failed RFC. Be it a single Enum for > everything, constants, context-based enums or type-based enums, I > would much rather have this RFC than not have it. PHP is one of the > most important Web applications in the world and it severely lacks > the ability to simplify Http. We could take inspiration from Python > Requests [1] or Node Fetch [2] as a really simple and > straightforward API that covers the vast majority of cases.
Python Requests and Node Fetch are simple and straightforward for users *because* they're not simple and straightforward to develop. A lot of care and detailed decisions have gone into those APIs to make them feel simple and straightforward when used. Python Requests[^1] is a massive third-party library that users install separately from Python. It also depends on urllib3[^2], another massive third-party library that serves as its underlying HTTP client. Node Fetch uses the WHATWG Fetch Living Standard[^3], which, again, is neither simple nor straightforward. It just feels that way when using it because they did a damn good job defining it. As I said earlier,[^4] this level of detail should live in userland. Arguably, as in the case of Fetch, something like this *could* live in core. There was an RFC over 10 years ago that proposed moving pecl_http into core.[^5] However, if we decide to go that route, I think it needs to be a much bigger undertaking, perhaps with a working group formed to hash out the details and design the API. I think it's better to let userland handle something like this, so core can focus on optimizations that reduce the "if it's in C, it'll be faster" arguments.
> I take the point that we don't need to go all the way and invent a > RequestClient library in PHP and this RFC is threading on the small > step of converting Curl procedural API into OOP, which is where > Larry and Rowans recommendations about some minor helper methods go > a really really long way compared to where we are today.
I'm fully on board with making the curl extension API easier to use. Let's clearly state the problem and use-case we're attempting to solve for and focus on a solution targeting that and nothing more (without limiting ourselves for future expansion, of course). Maybe after stating the problem clearly, we'll find it easier to build consensus on a solution. The RFC hints at type safety and converting the curl procedural API into OOP as motivating factors. I don't think these clearly state the problem we're trying to solve, so if they continue to be the motivating factors, this discussion is bound to continue into bikeshedding territory. Here are some of the more concrete things I've seen mentioned that hint at the problem: From Rowan:
> But that long list is also exactly why we badly need helpers for > common use cases - the manual page for curl_setopt has been at the > top of the charts for number of user comments for years, because > nobody wants to read the descriptions for two hundred options > they'll never need.
From Marco:
> perform basic HTTP requests in a friendly way
These are great starts. Solving for the documentation problem might not even require changes to the extension. We probably need to further define what is meant by "friendly," though. Otherwise, we'll find ourselves back at the bike shed. So, what's the problem (from a user's perspective) this RFC solves? Cheers, Ben [^1]: https://github.com/psf/requests [^2]: https://github.com/urllib3/urllib3 [^3]: https://fetch.spec.whatwg.org [^4]: https://news-web.php.net/php.internals/127760 [^5]: https://wiki.php.net/rfc/pecl_http

Juris Evertovskis

1 year ago
-----Original Message----- From: Eric Norris <eric.t.norris@gmail.com> Sent: Thursday, June 26, 2025 7:25 PM To: PHP internals <internals@lists.php.net> Subject: [PHP-DEV] [RFC][DISCUSSION] Object-oriented curl API v2
> I'd like to formally propose a restart of the original object-oriented curl API RFC
Cool. Calling functions with object as an argument to modify it's state feels very C-ish and wildly different from how contemporary PHP is usually written. So even a 1:1 translation into a more familiar API is welcome. It still feels a bit unfamiliar to me that part of the response (the body) is returned from `execute()` while the other stuff (like the status code) is stored in the state of the Handle instance. Is this statefulness suggested by libcurl and reflects it's object? Or is it a choice on the PHP side? I'm just wondering, this is probably not something that should be changed on the Handle class but maybe on some new layer. The enums that you propose are backed. It seems appropriate in the sense of continuity, but is there a need for that? I'd argue that option names like AbstractUnixSocket or AutoReferer are values per se and there is no usable meaning for those integer values behind them. Maybe the translation to numeric constants (assuming it's necessary) can be done internally (in the Handle) via a `match` or `switch` statement and let's have pure enums? I see that the option setters return ` \Curl\Handle`, but it is a bit unclear whether it will actually return `static`, `self` or `$this`. I assume the latter but it would be nice to document that we're mutating the same object.
> Should we organize the curl option enumerations by value type? Or have a single enumeration for all curl_setopt options and another for all curl_multi_setopt options?
In fact I would expect a single `->setOption()` instead of the type specific ones. Having to specify the argument type in the setter name and/or the enum name doesn't sound very enjoyable to me. BR, Juris

Ayesh - PHP.Watch

1 year ago
> Hello Internals, > > I'd like to formally propose a restart of the original object-oriented > curl API RFC (https://wiki.php.net/rfc/curl-oop): > > https://wiki.php.net/rfc/curl_oop_v2 > > The prior RFC seemed to get positive feedback, with a small consensus > around wanting enum(s) for curl options. I've taken that feedback and > incorporated it into a new RFC, as I am not the original author, but I > am interested in making another potential improvement to the curl > extension. > > In a nutshell, this version of the RFC: > > - uses enumerations for curl options and other curl constants > - introduces a new Curl namespace > > I have not yet created an implementation PR. I realize that is > somewhat discouraged, but I believe that this should be relatively > straightforward to implement (there's also the previous RFC's PR to > build on top of). The implementation of this RFC as it is now will > likely be tedious, however, so I'd like to get feedback on the > enumeration idea before committing to the work. > > I've outlined one open question in the RFC, which relates to the above: > > - Should we organize the curl option enumerations by value type? Or > have a single enumeration for all curl_setopt options and another for > all curl_multi_setopt options? > > If others (including the original RFC author) are interested in > working with me on this, I'm more than open to that, so please let me > know. > > Thanks, > Eric
Thank you for taking the initiative to work on this. It's long overdue, and the pattern we have now — that a `CurlHandle` object is passed to functions — is not as intuitive as calling a method on that object. However, I softly oppose this RFC in its current state and the way it seems to be going. I have pushed Curl and libcurl to some uncommon cases such as HTTP/3, DoH, the new debug callback (which I authored the PR for), IMAP, and a few other obscure tweaks. For all of them, the current `curl_setopt` worked, and the more I used it, the more I understood that having just a few Curl functions and a sea of Curl options is the least "presumptive way", regardless of the protocol and the options Curl provides. The extension is named `Curl`, because it's supposed to provide Curl functionality into PHP. It provides low-level functionality, but we should leave it to the PHP users to build the libraries that have fluent APIs. This way, we can have excellent purpose-built HTTP clients, IMAP clients, Tor proxies, etc, all built using the low-level functionality the extension offers.The HTTP client authors know the Curl options really well to build a secure and fast HTTP client, and someone else building an IMAP client can provide an intuitive API but still use the same underlying Curl functionality. I understand that your RFC does not propose a high-level API, and I agree with you that a high-level API will need a lot of discussion. There's a ton of Curl constants, and you are right that it could really use some organizing. The upstream Curl project has not done it, most likely because the options behave differently depending on the protocol, and simply because it's a lot of work and BC trouble to do so. I don’t think we can realistically have a meaningful discourse on how to semantically group the constants into meaningful Enums. I'd also argue that if libcurl is OK with having a sea of Curl options, we should not be the one to group them. Grouping them by the expected value type is one way to do it, but as mentioned elsewhere in replies, now, the consumers of the API will have to figure out whether that one Curl option they always used belongs to `IntOpt` or a `BoolOpt`. It will help with `CURLOPT_SSL_VERIFYHOST` (which should be set to `2`, not `true`), but I don't think this level of type safety is all that useful for the trouble. To bring some numbers, we currently have: - 271 CURLOPT_* consts (https://php.watch/codex?search=CURLOPT_) - 78 CURLINFO_* consts (https://php.watch/codex?search=CURLINFO_) - 71 CURLE_* consts (https://php.watch/codex?search=CURLE_) + I sent a PR to add 41 missing consts (https://github.com/php/php-src/pull/13340/files) - 150+ constants for options such as protocols, HTTP versions, URL follow rules, etc. I think a more light-weight approach would be to: - Move all of them to the `\Curl` namespace. - Rename Curl options to `\Curl\Option` namespace, and rename them, so that `CURLOPT_SSL_VERIFYHOST` becomes `Curl\Option\SSL_VERIFYHOST` - Rename Curl error codes to similar `\Curl\Error` constants. - Have the `CurlHandle` object accept options, e.g. `$ch->setOption(Curl\Option\SSL_VERIFYHOST, 2)`. libcurl Easy handlers do not have a way to retrieve the option once it's set, so there will be no `getOption` either. - Make Curl throw exceptions, and never `false` on `\Curl\execute()`, with the Exception's error code and message mapped to the Curl error code and message. We will not need to bring over `curl_error` or `curl_errno` functions. Realistically, I don't think we can deprecate and remove the `\curl_*` functions any time soon, so this will actually add more maintenance work for php-src at the end too. Thank you. Ayesh.

Nicolas Grekas

1 year ago
Le sam. 28 juin 2025 à 00:01, Ayesh Karunaratne <ayesh@php.watch> a écrit :
> > Hello Internals, > > > > I'd like to formally propose a restart of the original object-oriented > > curl API RFC (https://wiki.php.net/rfc/curl-oop): > > > > https://wiki.php.net/rfc/curl_oop_v2 > > > > The prior RFC seemed to get positive feedback, with a small consensus > > around wanting enum(s) for curl options. I've taken that feedback and > > incorporated it into a new RFC, as I am not the original author, but I > > am interested in making another potential improvement to the curl > > extension. > > > > In a nutshell, this version of the RFC: > > > > - uses enumerations for curl options and other curl constants > > - introduces a new Curl namespace > > > > I have not yet created an implementation PR. I realize that is > > somewhat discouraged, but I believe that this should be relatively > > straightforward to implement (there's also the previous RFC's PR to > > build on top of). The implementation of this RFC as it is now will > > likely be tedious, however, so I'd like to get feedback on the > > enumeration idea before committing to the work. > > > > I've outlined one open question in the RFC, which relates to the above: > > > > - Should we organize the curl option enumerations by value type? Or > > have a single enumeration for all curl_setopt options and another for > > all curl_multi_setopt options? > > > > If others (including the original RFC author) are interested in > > working with me on this, I'm more than open to that, so please let me > > know. > > > > Thanks, > > Eric > > Thank you for taking the initiative to work on this. It's long > overdue, and the pattern we have now — that a `CurlHandle` object is > passed to functions — is not as intuitive as calling a method on that > object. > > However, I softly oppose this RFC in its current state and the way it > seems to be going. > > I have pushed Curl and libcurl to some uncommon cases such as HTTP/3, > DoH, the new debug callback (which I authored the PR for), IMAP, and a > few other obscure tweaks. For all of them, the current `curl_setopt` > worked, and the more I used it, the more I understood that having just > a few Curl functions and a sea of Curl options is the least > "presumptive way", regardless of the protocol and the options Curl > provides. > > The extension is named `Curl`, because it's supposed to provide Curl > functionality into PHP. It provides low-level functionality, but we > should leave it to the PHP users to build the libraries that have > fluent APIs. > > This way, we can have excellent purpose-built HTTP clients, IMAP > clients, Tor proxies, etc, all built using the low-level functionality > the extension offers.The HTTP client authors know the Curl options > really well to build a secure and fast HTTP client, and someone else > building an IMAP client can provide an intuitive API but still use the > same underlying Curl functionality. I understand that your RFC does > not propose a high-level API, and I agree with you that a high-level > API will need a lot of discussion. > > There's a ton of Curl constants, and you are right that it could > really use some organizing. The upstream Curl project has not done it, > most likely because the options behave differently depending on the > protocol, and simply because it's a lot of work and BC trouble to do > so. I don’t think we can realistically have a meaningful discourse on > how to semantically group the constants into meaningful Enums. I'd > also argue that if libcurl is OK with having a sea of Curl options, we > should not be the one to group them. > > Grouping them by the expected value type is one way to do it, but as > mentioned elsewhere in replies, now, the consumers of the API will > have to figure out whether that one Curl option they always used > belongs to `IntOpt` or a `BoolOpt`. It will help with > `CURLOPT_SSL_VERIFYHOST` (which should be set to `2`, not `true`), but > I don't think this level of type safety is all that useful for the > trouble. > > To bring some numbers, we currently have: > > - 271 CURLOPT_* consts (https://php.watch/codex?search=CURLOPT_) > - 78 CURLINFO_* consts (https://php.watch/codex?search=CURLINFO_) > - 71 CURLE_* consts (https://php.watch/codex?search=CURLE_) + I sent > a PR to add 41 missing consts > (https://github.com/php/php-src/pull/13340/files) > - 150+ constants for options such as protocols, HTTP versions, URL > follow rules, etc. > > I think a more light-weight approach would be to: > > - Move all of them to the `\Curl` namespace. > - Rename Curl options to `\Curl\Option` namespace, and rename them, > so that `CURLOPT_SSL_VERIFYHOST` becomes `Curl\Option\SSL_VERIFYHOST` > - Rename Curl error codes to similar `\Curl\Error` constants. > - Have the `CurlHandle` object accept options, e.g. > `$ch->setOption(Curl\Option\SSL_VERIFYHOST, 2)`. libcurl Easy handlers > do not have a way to retrieve the option once it's set, so there will > be no `getOption` either. > - Make Curl throw exceptions, and never `false` on `\Curl\execute()`, > with the Exception's error code and message mapped to the Curl error > code and message. We will not need to bring over `curl_error` or > `curl_errno` functions. > > Realistically, I don't think we can deprecate and remove the `\curl_*` > functions any time soon, so this will actually add more maintenance > work for php-src at the end too. > > Thank you. > Ayesh. >
I'm not even sure it's a good idea to add those namespaced options: using CURLOPT_SSL_VERIFYHOST is perfect to find the corresponding curl documentation with your favorite search engine. php's doc is awesome, but it cannot compete with the details provided by curl's doc on the topic. Nicolas

Ayesh - PHP.Watch

1 year ago
> I'm not even sure it's a good idea to add those namespaced options: using CURLOPT_SSL_VERIFYHOST is perfect to find the corresponding curl documentation with your favorite search engine. php's doc is awesome, but it cannot compete with the details provided by curl's doc on the topic. > > Nicolas
Hi Nicolas, You are right, if we were to rename those constants, we would lose the "grep-ability" in both libcurl source/docs and many years of existing open source projects and discussions. So while keeping the existing option consts, info consts, we do not have a lot of room to improve it. Perhaps the `CurlHandle` objects can accept options similar to how we have `date_*` functions alongside `DateTime` methods. I personally continue to use the functions, but I won't mind having an OOP API. We can leave it to the library authors (such as you, Nicolas 💟, Symfony HTTP client is just awesome) to design more intuitive APIs. Ayesh.

Eric Norris

1 year ago
> I'm not even sure it's a good idea to add those namespaced options: using CURLOPT_SSL_VERIFYHOST is perfect to find the corresponding curl documentation with your favorite search engine. php's doc is awesome, but it cannot compete with the details provided by curl's doc on the topic.
That's a good point, but I do feel like there is value in having these under a namespace; a part of the reason I am interested in this proposal is that I'd like to see more of PHP core living under namespaces, since I think it will present a more consistent vision of the "standard library". I wonder if there is a way we could preserve the link, at least? In my proposal, the enum values are equivalent to their curl constant equivalents, which I thought would help with discoverability in the documentation. For the record - and I'll say this elsewhere - based on the discussion so far I am planning on withdrawing the proposal for separate enums. I'm still considering using a single enum to group all of these options, however, instead of constants.

Larry Garfield

1 year ago
On Fri, Jun 27, 2025, at 4:58 PM, Ayesh Karunaratne wrote:
> However, I softly oppose this RFC in its current state and the way it > seems to be going.
So I think we've identified a key disagreement about not just the goal, but the intent. To what extent should PHP core ship with a usable HTTP client? Right now it ships with Curl, which... in its current form is not usable. It's a low-level tool with an inscrutable API we inherited from C. It's not viable as a user-facing tool. It's a tool that's only useful to people writing client libraries like Guzzle or CurlClass or Symfony HTTP or such. On the one hand, Marco is correct that for a web-centric language to not ship with a non-sucky way to send web requests is... kinda embarrassing. Even if the use cases where you can't install a 3rd party library are few, they are non-zero. And that also doesn't help new users figure out what to use. (Eg, the person who wrote most of the code for our main application at work, learning PHP as he went, is sending lots of requests using... an ungodly mess of curl that can't even understand. Because he didn't know that things like Guzzle even existed.) On the other hand, Ben is correct that an HTTP client is a not-small task, with a very deep rabbit hole. So there's two closely related but distinct asks here: 1. Make working with curl suck less (giving it an OOP interface is part of that but not all) 2. Ship a useful first-party HTTP client that can handle the 80% case, even if it's not full featured. Beefing up Curl's interface until it fulfills part 2 is one approach, but not the only. At one extreme would be the "do nothing, status quo is fine" position. Ayesh seems to be close to that position, maybe with a little polish for funsies. The other extreme would essentially be "Guzzle in core," which I don't think anyone is advocating. Where between those extremes we should land is debatable. Personally I'm of the mind that a simple, basic-features HTTP client in core would be a good thing; that's central enough that it should not be left to userland. It doesn't need to offer every possible feature; no need for async multiplexing, for example. But sending GET and POST requests with straightforward bodies should be table-stakes for a web language, and right now, that's a second class citizen. If it's written in such a way that it can be extended easily in user-space, so much the better. Whether that basic-features client is Curl itself or a bundled wrapper that uses Curl, I have no strong preference. The challenge of making it separate from Curl is, shocker, that it's bikeshed bait. Does that imply using the new URL/URI classes? Does it imply we need request/response objects? The rabbit hole indeed gets deep fast. So the first question, I think, is what is the consensus between these three coarse-grained positions: 1. Status quo is fine. PHP core not having a user-friendly way to send HTTP requests is acceptable. Maybe make Curl a little nicer, but only to make life easier for Guzzle et al. 2. We should develop the Curl API until it's usable for basic HTTP behavior, but no further. 3. We should bundle an HTTP client that wraps Curl (with or without minor improvements to Curl), exact scope TBD. Personally, I'm open to either 2 or 3. 3 is more bikesheddable, but possibly the better end result. Where does everyone else stand? --Larry Garfield

Ben Ramsey

1 year ago
> On Jun 28, 2025, at 00:01, Larry Garfield <larry@garfieldtech.com> wrote: > > On Fri, Jun 27, 2025, at 4:58 PM, Ayesh Karunaratne wrote: > >> However, I softly oppose this RFC in its current state and the way it >> seems to be going. > > So I think we've identified a key disagreement about not just the goal, but the intent. To what extent should PHP core ship with a usable HTTP client? > > Right now it ships with Curl, which... in its current form is not usable. It's a low-level tool with an inscrutable API we inherited from C. It's not viable as a user-facing tool. It's a tool that's only useful to people writing client libraries like Guzzle or CurlClass or Symfony HTTP or such. > > On the one hand, Marco is correct that for a web-centric language to not ship with a non-sucky way to send web requests is... kinda embarrassing. Even if the use cases where you can't install a 3rd party library are few, they are non-zero. And that also doesn't help new users figure out what to use. (Eg, the person who wrote most of the code for our main application at work, learning PHP as he went, is sending lots of requests using... an ungodly mess of curl that can't even understand. Because he didn't know that things like Guzzle even existed.) > > On the other hand, Ben is correct that an HTTP client is a not-small task, with a very deep rabbit hole. > > So there's two closely related but distinct asks here: > > 1. Make working with curl suck less (giving it an OOP interface is part of that but not all) > 2. Ship a useful first-party HTTP client that can handle the 80% case, even if it's not full featured. > > Beefing up Curl's interface until it fulfills part 2 is one approach, but not the only. > > At one extreme would be the "do nothing, status quo is fine" position. Ayesh seems to be close to that position, maybe with a little polish for funsies. The other extreme would essentially be "Guzzle in core," which I don't think anyone is advocating. Where between those extremes we should land is debatable. > > Personally I'm of the mind that a simple, basic-features HTTP client in core would be a good thing; that's central enough that it should not be left to userland. It doesn't need to offer every possible feature; no need for async multiplexing, for example. But sending GET and POST requests with straightforward bodies should be table-stakes for a web language, and right now, that's a second class citizen. If it's written in such a way that it can be extended easily in user-space, so much the better. > > Whether that basic-features client is Curl itself or a bundled wrapper that uses Curl, I have no strong preference. The challenge of making it separate from Curl is, shocker, that it's bikeshed bait. Does that imply using the new URL/URI classes? Does it imply we need request/response objects? The rabbit hole indeed gets deep fast. > > So the first question, I think, is what is the consensus between these three coarse-grained positions: > > 1. Status quo is fine. PHP core not having a user-friendly way to send HTTP requests is acceptable. Maybe make Curl a little nicer, but only to make life easier for Guzzle et al. > 2. We should develop the Curl API until it's usable for basic HTTP behavior, but no further. > 3. We should bundle an HTTP client that wraps Curl (with or without minor improvements to Curl), exact scope TBD. > > Personally, I'm open to either 2 or 3. 3 is more bikesheddable, but possibly the better end result. > > Where does everyone else stand? > > --Larry Garfield
I’m also open to 2 or 3, but 3 sounds more like something that I think should live in userland, so I lean much more towards 2. Cheers, Ben

Arvids Godjuks

1 year ago
On Sat, 28 Jun 2025 at 08:03, Larry Garfield <larry@garfieldtech.com> wrote:
> On Fri, Jun 27, 2025, at 4:58 PM, Ayesh Karunaratne wrote: > > > However, I softly oppose this RFC in its current state and the way it > > seems to be going. > > So I think we've identified a key disagreement about not just the goal, > but the intent. To what extent should PHP core ship with a usable HTTP > client? > > Right now it ships with Curl, which... in its current form is not usable. > It's a low-level tool with an inscrutable API we inherited from C. It's > not viable as a user-facing tool. It's a tool that's only useful to people > writing client libraries like Guzzle or CurlClass or Symfony HTTP or such. > > On the one hand, Marco is correct that for a web-centric language to not > ship with a non-sucky way to send web requests is... kinda embarrassing. > Even if the use cases where you can't install a 3rd party library are few, > they are non-zero. And that also doesn't help new users figure out what to > use. (Eg, the person who wrote most of the code for our main application > at work, learning PHP as he went, is sending lots of requests using... an > ungodly mess of curl that can't even understand. Because he didn't know > that things like Guzzle even existed.) > > On the other hand, Ben is correct that an HTTP client is a not-small task, > with a very deep rabbit hole. > > So there's two closely related but distinct asks here: > > 1. Make working with curl suck less (giving it an OOP interface is part of > that but not all) > 2. Ship a useful first-party HTTP client that can handle the 80% case, > even if it's not full featured. > > Beefing up Curl's interface until it fulfills part 2 is one approach, but > not the only. > > At one extreme would be the "do nothing, status quo is fine" position. > Ayesh seems to be close to that position, maybe with a little polish for > funsies. The other extreme would essentially be "Guzzle in core," which I > don't think anyone is advocating. Where between those extremes we should > land is debatable. > > Personally I'm of the mind that a simple, basic-features HTTP client in > core would be a good thing; that's central enough that it should not be > left to userland. It doesn't need to offer every possible feature; no need > for async multiplexing, for example. But sending GET and POST requests > with straightforward bodies should be table-stakes for a web language, and > right now, that's a second class citizen. If it's written in such a way > that it can be extended easily in user-space, so much the better. > > Whether that basic-features client is Curl itself or a bundled wrapper > that uses Curl, I have no strong preference. The challenge of making it > separate from Curl is, shocker, that it's bikeshed bait. Does that imply > using the new URL/URI classes? Does it imply we need request/response > objects? The rabbit hole indeed gets deep fast. > > So the first question, I think, is what is the consensus between these > three coarse-grained positions: > > 1. Status quo is fine. PHP core not having a user-friendly way to send > HTTP requests is acceptable. Maybe make Curl a little nicer, but only to > make life easier for Guzzle et al. > 2. We should develop the Curl API until it's usable for basic HTTP > behavior, but no further. > 3. We should bundle an HTTP client that wraps Curl (with or without minor > improvements to Curl), exact scope TBD. > > Personally, I'm open to either 2 or 3. 3 is more bikesheddable, but > possibly the better end result. > > Where does everyone else stand? > > --Larry Garfield >
I think #2 is the way to go. I personally just use Symfony's HTTP Client 99.9% of the time - there is one exception in recent years where I had to go low-level cURL and craft an extremely specific HTTP request. Yes, it is a SOAP service for a government system, because of course it is. I'm not even sure it's a good idea to add those namespaced options: using
> CURLOPT_SSL_VERIFYHOST is perfect to find the corresponding curl > documentation with your favorite search engine. php's doc is awesome, but > it cannot compete with the details provided by curl's doc on the topic.
Valid. This cannot be avoided if any kind of RFC is to be accepted, so I think the next best solution is to put effort into documentation and ensure that things are referenced (like the new Enum options having very obvious links to the original constants and to the curl documentation), making discoverability easy. The good thing is that OOP API is purely new, so there is not going to be tons of old content about it to make things messy.
-- Arvīds Godjuks +371 26 851 664 arvids.godjuks@gmail.com Telegram: @psihius https://t.me/psihius

Eric Norris

1 year ago
Thanks for your thoughtful response, Larry! I agree with your summary.
> 1. Status quo is fine. PHP core not having a user-friendly way to send HTTP requests is acceptable. Maybe make Curl a little nicer, but only to make life easier for Guzzle et al. > 2. We should develop the Curl API until it's usable for basic HTTP behavior, but no further. > 3. We should bundle an HTTP client that wraps Curl (with or without minor improvements to Curl), exact scope TBD. > > Personally, I'm open to either 2 or 3. 3 is more bikesheddable, but possibly the better end result. > > Where does everyone else stand?
Based on the feedback so far (I do plan on waiting for more responses to your email), and on my own preferences, I wonder if there is a hybrid option I could propose. Perhaps the RFC could offer both a \Curl\Handle (tentative name) to address position 1, and a \Curl\BasicHttpHandle (also tentative name) that addresses position 2? If people were amenable, I'd even make the BasicHttpHandle a separate vote. I agree that 3 is both more bikesheddable and also possibly ideal, but I feel my above suggestion maybe strikes the right balance between the "status quo is fine, I don't want to see random HTTP-related methods on my low(est)-level curl object" and the "I'd like to do basic HTTP stuff with curl, without a library" crowds. Barring that, my preference would be 2, but I'd accept 1 just to have it pass - like I mentioned elsewhere, I think there is value in introducing namespaces and object-oriented APIs for "modernization" and language consistency reasons.

Eric Norris

1 year ago
> Based on the feedback so far (I do plan on waiting for more responses > to your email), and on my own preferences, I wonder if there is a > hybrid option I could propose. Perhaps the RFC could offer both a > \Curl\Handle (tentative name) to address position 1, and a > \Curl\BasicHttpHandle (also tentative name) that addresses position 2? > If people were amenable, I'd even make the BasicHttpHandle a separate > vote. > > I agree that 3 is both more bikesheddable and also possibly ideal, but > I feel my above suggestion maybe strikes the right balance between the > "status quo is fine, I don't want to see random HTTP-related methods > on my low(est)-level curl object" and the "I'd like to do basic HTTP > stuff with curl, without a library" crowds. > > Barring that, my preference would be 2, but I'd accept 1 just to have > it pass - like I mentioned elsewhere, I think there is value in > introducing namespaces and object-oriented APIs for "modernization" > and language consistency reasons.
Having thought about this some more, while I'm still feeling somewhat positive about my suggestion I'm just not sure it's the best way to proceed. I started to sketch what a BasicHttpHandle class would look like, and I'm stuck on how to get data about the response out of the class. Naively, we could have $response_status_code and $response_headers properties, and have the same fetch() and execute() methods I suggested elsewhere to get the response body. Alternatively, we could return a simple CurlHttpResponse object which contains all three properties in the fetch() and execute() implementations for the BasicHttpHandle class. Both of these are fine, but they would lock us out of being PSR7 compatible. I think that people would probably desire PSR7 compatibility, and I would feel uncomfortable with eliminating or tainting the possibility of achieving this. For example, if we had this BasicHttpHandle and then later introduced PSR7 response objects, we'd need to either break backwards compatibility for the class, or introduce a second class. We could also go straight to returning a PSR7 compatible response for the BasicHttpHandle class, but I think that likely deserves its own RFC. So in closing, if people felt generally okay with the limitation of not being PSR7 compatible, I'd probably still add some form of my BasicHttpHandle suggestion as a secondary vote. If people thought PSR7 was necessary, I'd drop it, and leave a PSR7-in-core RFC for the future. In that case, I'd go with Larry's option 1 for the RFC; I've currently updated the RFC to match that option for now.

Ben Ramsey

1 year ago
> On Jul 2, 2025, at 10:48, Eric Norris <eric.t.norris@gmail.com> wrote: > >> Based on the feedback so far (I do plan on waiting for more responses >> to your email), and on my own preferences, I wonder if there is a >> hybrid option I could propose. Perhaps the RFC could offer both a >> \Curl\Handle (tentative name) to address position 1, and a >> \Curl\BasicHttpHandle (also tentative name) that addresses position 2? >> If people were amenable, I'd even make the BasicHttpHandle a separate >> vote. >> >> I agree that 3 is both more bikesheddable and also possibly ideal, but >> I feel my above suggestion maybe strikes the right balance between the >> "status quo is fine, I don't want to see random HTTP-related methods >> on my low(est)-level curl object" and the "I'd like to do basic HTTP >> stuff with curl, without a library" crowds. >> >> Barring that, my preference would be 2, but I'd accept 1 just to have >> it pass - like I mentioned elsewhere, I think there is value in >> introducing namespaces and object-oriented APIs for "modernization" >> and language consistency reasons. > > Having thought about this some more, while I'm still feeling somewhat > positive about my suggestion I'm just not sure it's the best way to > proceed. I started to sketch what a BasicHttpHandle class would look > like, and I'm stuck on how to get data about the response out of the > class. > > Naively, we could have $response_status_code and $response_headers > properties, and have the same fetch() and execute() methods I > suggested elsewhere to get the response body. Alternatively, we could > return a simple CurlHttpResponse object which contains all three > properties in the fetch() and execute() implementations for the > BasicHttpHandle class. > > Both of these are fine, but they would lock us out of being PSR7 > compatible. I think that people would probably desire PSR7 > compatibility, and I would feel uncomfortable with eliminating or > tainting the possibility of achieving this. For example, if we had > this BasicHttpHandle and then later introduced PSR7 response objects, > we'd need to either break backwards compatibility for the class, or > introduce a second class. We could also go straight to returning a > PSR7 compatible response for the BasicHttpHandle class, but I think > that likely deserves its own RFC. > > So in closing, if people felt generally okay with the limitation of > not being PSR7 compatible, I'd probably still add some form of my > BasicHttpHandle suggestion as a secondary vote. If people thought PSR7 > was necessary, I'd drop it, and leave a PSR7-in-core RFC for the > future. In that case, I'd go with Larry's option 1 for the RFC; I've > currently updated the RFC to match that option for now.
I think it’s good to keep PSR-7 in mind when designing the interface, but I don’t think it’s necessary to strive for 100% compatibility. Userland will end up writing wrappers for it that implement PSR-7. IMO, the interface should attempt to more closely follow curl nomenclature and idioms, since it’s an interface for interacting with curl. Cheers, Ben

Larry Garfield

1 year ago
On Wed, Jul 2, 2025, at 10:48 AM, Eric Norris wrote:
>> Based on the feedback so far (I do plan on waiting for more responses >> to your email), and on my own preferences, I wonder if there is a >> hybrid option I could propose. Perhaps the RFC could offer both a >> \Curl\Handle (tentative name) to address position 1, and a >> \Curl\BasicHttpHandle (also tentative name) that addresses position 2? >> If people were amenable, I'd even make the BasicHttpHandle a separate >> vote. >> >> I agree that 3 is both more bikesheddable and also possibly ideal, but >> I feel my above suggestion maybe strikes the right balance between the >> "status quo is fine, I don't want to see random HTTP-related methods >> on my low(est)-level curl object" and the "I'd like to do basic HTTP >> stuff with curl, without a library" crowds. >> >> Barring that, my preference would be 2, but I'd accept 1 just to have >> it pass - like I mentioned elsewhere, I think there is value in >> introducing namespaces and object-oriented APIs for "modernization" >> and language consistency reasons. > > Having thought about this some more, while I'm still feeling somewhat > positive about my suggestion I'm just not sure it's the best way to > proceed. I started to sketch what a BasicHttpHandle class would look > like, and I'm stuck on how to get data about the response out of the > class. > > Naively, we could have $response_status_code and $response_headers > properties, and have the same fetch() and execute() methods I > suggested elsewhere to get the response body. Alternatively, we could > return a simple CurlHttpResponse object which contains all three > properties in the fetch() and execute() implementations for the > BasicHttpHandle class. > > Both of these are fine, but they would lock us out of being PSR7 > compatible. I think that people would probably desire PSR7 > compatibility, and I would feel uncomfortable with eliminating or > tainting the possibility of achieving this. For example, if we had > this BasicHttpHandle and then later introduced PSR7 response objects, > we'd need to either break backwards compatibility for the class, or > introduce a second class. We could also go straight to returning a > PSR7 compatible response for the BasicHttpHandle class, but I think > that likely deserves its own RFC. > > So in closing, if people felt generally okay with the limitation of > not being PSR7 compatible, I'd probably still add some form of my > BasicHttpHandle suggestion as a secondary vote. If people thought PSR7 > was necessary, I'd drop it, and leave a PSR7-in-core RFC for the > future. In that case, I'd go with Larry's option 1 for the RFC; I've > currently updated the RFC to match that option for now.
The question of PHP-native request/response objects has come up a couple of times, and even had an RFC that went to a vote (declined). My stance has been, and remains, that such objects do NOT need to match PSR-7... but they should be powerful enough to effectively replace/displace PSR-7. If it's just another backend that PSR-7 consumes, we've added very little to the ecosystem. If they're robust enough that they can replace PSR-7 and HttpFoundation in time, we've helped to standardize the ecosystem. (And FIG will be able to adapt, don't worry.) (Eg, I would strongly recommend leveraging properties instead of methods for any built-in objects, which didn't exist when PSR-7 was written but now so; we should absolutely use the new built-in URI/URL classes instead of user-space ones, etc.) Of course, as you can expect, "design and include request/response objects powerful enough to supplant PSR-7" is a non-small and highly bikesheddable topic, and PHP is notoriously structurally bad at being able to have those conversations. That's part of why it's never happened. --Larry Garfield

Paul M. Jones

1 year ago
Hi all,
> The question of PHP-native request/response objects has come up a couple of times, and even had an RFC that went to a vote (declined). My stance has been, and remains, that ... they should be powerful enough to effectively replace/displace PSR-7.
Where and when have you previously articulated that stance? Because I'd be thrilled to re-open yet another version (the 3rd) of that RFC. -- pmj

Larry Garfield

1 year ago
On Wed, Jul 2, 2025, at 12:34 PM, Paul M. Jones wrote:
> Hi all, > >> The question of PHP-native request/response objects has come up a couple of times, and even had an RFC that went to a vote (declined). My stance has been, and remains, that ... they should be powerful enough to effectively replace/displace PSR-7. > > Where and when have you previously articulated that stance? Because I'd > be thrilled to re-open yet another version (the 3rd) of that RFC. > > > -- pmj
I believe I stated it (perhaps phrased differently, it's been a while) in the discussion thread of your previous RFC. And voted against the RFC on the grounds that I didn't feel it was robust enough to effectively replace PSR-7 and HttpFoundation. --Larry Garfield

Paul M. Jones

1 year ago
Hi all,
> On Jul 2, 2025, at 12:41, Larry Garfield <larry@garfieldtech.com> wrote: > > On Wed, Jul 2, 2025, at 12:34 PM, Paul M. Jones wrote: >> Hi all, >> >>> The question of PHP-native request/response objects has come up a couple of times, and even had an RFC that went to a vote (declined). My stance has been, and remains, that ... they should be powerful enough to effectively replace/displace PSR-7. >> >> Where and when have you previously articulated that stance? Because I'd >> be thrilled to re-open yet another version (the 3rd) of that RFC. >> >> -- pmj > > I believe I stated it (perhaps phrased differently, it's been a while) in the discussion thread of your previous RFC.
You commented three times in that thread; the relevant one appears to be the second, and includes Symfony's HttpFoundation: - https://externals.io/message/108436#108591 - https://externals.io/message/108436#108838 "I would be very much in favor of a proposal that goes much further, with the aim that it can eventually deprecate PSR-7 and HttpFoundation, or at least large portions of them." - https://externals.io/message/108436#109007 I included that sentiment under "Disruptive to (or insufficiently unifying of) userland ecosystem" in the after-action on that RFC: <https://externals.io/message/109563>. To sum up: your position is that any HTTP-related offering here must be able to supplant both PSR-7 and HttpFoundation? Further: now that Symfony has its own HttpClient, should that be supplanted as well?
> And voted against the RFC on the grounds that I didn't feel it was robust enough to effectively replace PSR-7 and HttpFoundation.
You were not a voter at the time. Memories fade, I guess. -- pmj

Larry Garfield

1 year ago
On Wed, Jul 2, 2025, at 10:48 AM, Eric Norris wrote:
> Having thought about this some more, while I'm still feeling somewhat > positive about my suggestion I'm just not sure it's the best way to > proceed. I started to sketch what a BasicHttpHandle class would look > like, and I'm stuck on how to get data about the response out of the > class.
Another thing I just realized. IF we have an in-core HTTP client we intend for end-users to use (as opposed to just a less-sucky Curl that only Guzzle and Symfony to use), it needs to have a defined interface to go along with it so that people can mock it for testing purposes. I would consider this a hard requirement for any "user facing" HTTP client. --Larry Garfield

Eric Norris

1 year ago
On Wed, Jul 2, 2025 at 11:48 AM Eric Norris <eric.t.norris@gmail.com> wrote:
> > > Based on the feedback so far (I do plan on waiting for more responses > > to your email), and on my own preferences, I wonder if there is a > > hybrid option I could propose. Perhaps the RFC could offer both a > > \Curl\Handle (tentative name) to address position 1, and a > > \Curl\BasicHttpHandle (also tentative name) that addresses position 2? > > If people were amenable, I'd even make the BasicHttpHandle a separate > > vote. > > > > I agree that 3 is both more bikesheddable and also possibly ideal, but > > I feel my above suggestion maybe strikes the right balance between the > > "status quo is fine, I don't want to see random HTTP-related methods > > on my low(est)-level curl object" and the "I'd like to do basic HTTP > > stuff with curl, without a library" crowds. > > > > Barring that, my preference would be 2, but I'd accept 1 just to have > > it pass - like I mentioned elsewhere, I think there is value in > > introducing namespaces and object-oriented APIs for "modernization" > > and language consistency reasons. > > Having thought about this some more, while I'm still feeling somewhat > positive about my suggestion I'm just not sure it's the best way to > proceed. I started to sketch what a BasicHttpHandle class would look > like, and I'm stuck on how to get data about the response out of the > class. > > Naively, we could have $response_status_code and $response_headers > properties, and have the same fetch() and execute() methods I > suggested elsewhere to get the response body. Alternatively, we could > return a simple CurlHttpResponse object which contains all three > properties in the fetch() and execute() implementations for the > BasicHttpHandle class. > > Both of these are fine, but they would lock us out of being PSR7 > compatible. I think that people would probably desire PSR7 > compatibility, and I would feel uncomfortable with eliminating or > tainting the possibility of achieving this. For example, if we had > this BasicHttpHandle and then later introduced PSR7 response objects, > we'd need to either break backwards compatibility for the class, or > introduce a second class. We could also go straight to returning a > PSR7 compatible response for the BasicHttpHandle class, but I think > that likely deserves its own RFC. > > So in closing, if people felt generally okay with the limitation of > not being PSR7 compatible, I'd probably still add some form of my > BasicHttpHandle suggestion as a secondary vote. If people thought PSR7 > was necessary, I'd drop it, and leave a PSR7-in-core RFC for the > future. In that case, I'd go with Larry's option 1 for the RFC; I've > currently updated the RFC to match that option for now.
Thanks Ben, Larry, and Paul for your responses to my suggestion for a BasicHttpHandle class. After reflecting further, I have decided to move this to the Future Scope section, as it feels weighty enough to stand as its own RFC. I'd like to think about this a bit more, but I will note that having a Request and Response interface in core would greatly simplify the proposal for a simple curl-based HTTP client, so I'd likely support any effort on that front. I've also updated the Curl\MultiHandle class proposal to account for removing the CURLOPT_RETURNTRANSFER option. At this point I believe the RFC is in a semi-final state at this point, barring any additional discussion. Thanks all for the feedback so far!

Eric Norris

1 year ago
On Mon, Jul 7, 2025 at 12:53 PM Eric Norris <eric.t.norris@gmail.com> wrote:
> > On Wed, Jul 2, 2025 at 11:48 AM Eric Norris <eric.t.norris@gmail.com> wrote: > > > > > Based on the feedback so far (I do plan on waiting for more responses > > > to your email), and on my own preferences, I wonder if there is a > > > hybrid option I could propose. Perhaps the RFC could offer both a > > > \Curl\Handle (tentative name) to address position 1, and a > > > \Curl\BasicHttpHandle (also tentative name) that addresses position 2? > > > If people were amenable, I'd even make the BasicHttpHandle a separate > > > vote. > > > > > > I agree that 3 is both more bikesheddable and also possibly ideal, but > > > I feel my above suggestion maybe strikes the right balance between the > > > "status quo is fine, I don't want to see random HTTP-related methods > > > on my low(est)-level curl object" and the "I'd like to do basic HTTP > > > stuff with curl, without a library" crowds. > > > > > > Barring that, my preference would be 2, but I'd accept 1 just to have > > > it pass - like I mentioned elsewhere, I think there is value in > > > introducing namespaces and object-oriented APIs for "modernization" > > > and language consistency reasons. > > > > Having thought about this some more, while I'm still feeling somewhat > > positive about my suggestion I'm just not sure it's the best way to > > proceed. I started to sketch what a BasicHttpHandle class would look > > like, and I'm stuck on how to get data about the response out of the > > class. > > > > Naively, we could have $response_status_code and $response_headers > > properties, and have the same fetch() and execute() methods I > > suggested elsewhere to get the response body. Alternatively, we could > > return a simple CurlHttpResponse object which contains all three > > properties in the fetch() and execute() implementations for the > > BasicHttpHandle class. > > > > Both of these are fine, but they would lock us out of being PSR7 > > compatible. I think that people would probably desire PSR7 > > compatibility, and I would feel uncomfortable with eliminating or > > tainting the possibility of achieving this. For example, if we had > > this BasicHttpHandle and then later introduced PSR7 response objects, > > we'd need to either break backwards compatibility for the class, or > > introduce a second class. We could also go straight to returning a > > PSR7 compatible response for the BasicHttpHandle class, but I think > > that likely deserves its own RFC. > > > > So in closing, if people felt generally okay with the limitation of > > not being PSR7 compatible, I'd probably still add some form of my > > BasicHttpHandle suggestion as a secondary vote. If people thought PSR7 > > was necessary, I'd drop it, and leave a PSR7-in-core RFC for the > > future. In that case, I'd go with Larry's option 1 for the RFC; I've > > currently updated the RFC to match that option for now. > > Thanks Ben, Larry, and Paul for your responses to my suggestion for a > BasicHttpHandle class. After reflecting further, I have decided to > move this to the Future Scope section, as it feels weighty enough to > stand as its own RFC. I'd like to think about this a bit more, but I > will note that having a Request and Response interface in core would > greatly simplify the proposal for a simple curl-based HTTP client, so > I'd likely support any effort on that front. > > I've also updated the Curl\MultiHandle class proposal to account for > removing the CURLOPT_RETURNTRANSFER option. > > At this point I believe the RFC is in a semi-final state at this > point, barring any additional discussion. Thanks all for the feedback > so far!
I'd like to bring this to a vote since discussion has died down, but I feel that I should implement the proposal before doing so. As always this is the hard part, and since I'm back from an extended break at work I will have less time to focus on this. I've mentioned this before, but if anyone would like to collaborate on the implementation, please reach out! Otherwise, I'll update this thread with a link to the implementation at some point in the future, give it a little more time for discussion, and bring the proposal to a vote.

Eric Norris

1 year ago
On Mon, Jul 21, 2025 at 10:47 AM Eric Norris <eric.t.norris@gmail.com> wrote:
> > On Mon, Jul 7, 2025 at 12:53 PM Eric Norris <eric.t.norris@gmail.com> wrote: > > > > On Wed, Jul 2, 2025 at 11:48 AM Eric Norris <eric.t.norris@gmail.com> wrote: > > > > > > > Based on the feedback so far (I do plan on waiting for more responses > > > > to your email), and on my own preferences, I wonder if there is a > > > > hybrid option I could propose. Perhaps the RFC could offer both a > > > > \Curl\Handle (tentative name) to address position 1, and a > > > > \Curl\BasicHttpHandle (also tentative name) that addresses position 2? > > > > If people were amenable, I'd even make the BasicHttpHandle a separate > > > > vote. > > > > > > > > I agree that 3 is both more bikesheddable and also possibly ideal, but > > > > I feel my above suggestion maybe strikes the right balance between the > > > > "status quo is fine, I don't want to see random HTTP-related methods > > > > on my low(est)-level curl object" and the "I'd like to do basic HTTP > > > > stuff with curl, without a library" crowds. > > > > > > > > Barring that, my preference would be 2, but I'd accept 1 just to have > > > > it pass - like I mentioned elsewhere, I think there is value in > > > > introducing namespaces and object-oriented APIs for "modernization" > > > > and language consistency reasons. > > > > > > Having thought about this some more, while I'm still feeling somewhat > > > positive about my suggestion I'm just not sure it's the best way to > > > proceed. I started to sketch what a BasicHttpHandle class would look > > > like, and I'm stuck on how to get data about the response out of the > > > class. > > > > > > Naively, we could have $response_status_code and $response_headers > > > properties, and have the same fetch() and execute() methods I > > > suggested elsewhere to get the response body. Alternatively, we could > > > return a simple CurlHttpResponse object which contains all three > > > properties in the fetch() and execute() implementations for the > > > BasicHttpHandle class. > > > > > > Both of these are fine, but they would lock us out of being PSR7 > > > compatible. I think that people would probably desire PSR7 > > > compatibility, and I would feel uncomfortable with eliminating or > > > tainting the possibility of achieving this. For example, if we had > > > this BasicHttpHandle and then later introduced PSR7 response objects, > > > we'd need to either break backwards compatibility for the class, or > > > introduce a second class. We could also go straight to returning a > > > PSR7 compatible response for the BasicHttpHandle class, but I think > > > that likely deserves its own RFC. > > > > > > So in closing, if people felt generally okay with the limitation of > > > not being PSR7 compatible, I'd probably still add some form of my > > > BasicHttpHandle suggestion as a secondary vote. If people thought PSR7 > > > was necessary, I'd drop it, and leave a PSR7-in-core RFC for the > > > future. In that case, I'd go with Larry's option 1 for the RFC; I've > > > currently updated the RFC to match that option for now. > > > > Thanks Ben, Larry, and Paul for your responses to my suggestion for a > > BasicHttpHandle class. After reflecting further, I have decided to > > move this to the Future Scope section, as it feels weighty enough to > > stand as its own RFC. I'd like to think about this a bit more, but I > > will note that having a Request and Response interface in core would > > greatly simplify the proposal for a simple curl-based HTTP client, so > > I'd likely support any effort on that front. > > > > I've also updated the Curl\MultiHandle class proposal to account for > > removing the CURLOPT_RETURNTRANSFER option. > > > > At this point I believe the RFC is in a semi-final state at this > > point, barring any additional discussion. Thanks all for the feedback > > so far! > > I'd like to bring this to a vote since discussion has died down, but I > feel that I should implement the proposal before doing so. As always > this is the hard part, and since I'm back from an extended break at > work I will have less time to focus on this. > > I've mentioned this before, but if anyone would like to collaborate on > the implementation, please reach out! Otherwise, I'll update this > thread with a link to the implementation at some point in the future, > give it a little more time for discussion, and bring the proposal to a > vote.
Apologies, quick clarification: I do not intend to target PHP 8.5, and will update the RFC to note this.

Eric Norris

1 year ago
Thanks for your response Ayesh! I hope to see this RFC on php.watch :)
> However, I softly oppose this RFC in its current state and the way it > seems to be going. > > I have pushed Curl and libcurl to some uncommon cases such as HTTP/3, > DoH, the new debug callback (which I authored the PR for), IMAP, and a > few other obscure tweaks. For all of them, the current `curl_setopt` > worked, and the more I used it, the more I understood that having just > a few Curl functions and a sea of Curl options is the least > "presumptive way", regardless of the protocol and the options Curl > provides. > > The extension is named `Curl`, because it's supposed to provide Curl > functionality into PHP. It provides low-level functionality, but we > should leave it to the PHP users to build the libraries that have > fluent APIs.
It would be helpful for me to understand what specifically you are objecting to in the current discussion, putting aside the suggested enumeration changes. Do you object to any HTTP-oriented methods at all, like something to set the HTTP method? Would you object to methods that apply to all, or nearly all, transport types, like a setTimeout() method?
> I think a more light-weight approach would be to: > > - Move all of them to the `\Curl` namespace. > - Rename Curl options to `\Curl\Option` namespace, and rename them, > so that `CURLOPT_SSL_VERIFYHOST` becomes `Curl\Option\SSL_VERIFYHOST` > - Rename Curl error codes to similar `\Curl\Error` constants. > - Have the `CurlHandle` object accept options, e.g. > `$ch->setOption(Curl\Option\SSL_VERIFYHOST, 2)`. libcurl Easy handlers > do not have a way to retrieve the option once it's set, so there will > be no `getOption` either. > - Make Curl throw exceptions, and never `false` on `\Curl\execute()`, > with the Exception's error code and message mapped to the Curl error > code and message. We will not need to bring over `curl_error` or > `curl_errno` functions.
Acknowledged, thank you. The RFC does propose what you're suggesting with never returning false and instead throwing exceptions, but it feels like it might still be useful to have properties on the actual object. Do you have opinions on that?
> Realistically, I don't think we can deprecate and remove the `\curl_*` > functions any time soon, so this will actually add more maintenance > work for php-src at the end too.
Agreed, I do not plan on suggesting this, not even under Future Scope.