Library / SDK
php-curl-class/php-curl-class avatar
php-curl-class/php-curl-class

php-curl-class: error is a method and a truthy property

PHP Curl Class makes it easy to send HTTP requests and integrate with web APIs

3,296 stars802 forksPHPUnlicense

At a glance

What is it?
php-curl-class wraps the PHP curl extension in a single object with magic properties, a parallel multi-request client and a generated method list. Its first example reads error as a property that the same page documents as a method, three of its eight sections are links to other files, and a Python version pin sits in the root of a PHP library.
Who is it for?
php-curl-class fits a PHP codebase that has outgrown hand-written curl option arrays and wants one object with readable properties plus a parallel client for fan-out requests. Verify four things before you adopt it.
Can I use it commercially?
Yes. Unlicense is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 4 days ago.
What is it written in?
Mainly PHP, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • php-curl-class/php-curl-class3,296 ★ · -2
Star history
Repository2026-09-242026-11-14
php-curl-class/php-curl-class3.3k3.3k

-2 Stars in the last 51 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

error is documented as a method and read as a truthy property

The very first example branches on a property called error and prints a sibling property called errorMessage, calling a diagnose method in the failure branch. The method reference further down the same page lists an entry called error that takes a callback. So one identifier is a method in the reference and a value in every example, and the object also implements magic property access, which is how the sibling message and the response body resolve. Nothing in the file explains how the two coexist, and it matters more than it looks: the object exposes a request, a response, request headers, response headers, an error flag and an error message as properties, so any code that treats it as an array or reflects over it has to know which of those names are values and which are callables. The method list itself stops partway through, ending on an entry with no signature at all.

Three of eight sections are links, and six anchors hang off an emoji

Security, troubleshooting and testing are one sentence each, each pointing at a file in the repository. That is a defensible way to keep a front page short, and those three files do exist at the root. What is more fragile is the contents list. Eight entries link to headings, and the targets were generated from headings that begin with an emoji followed by a space. Two of the eight anchors are percent-encoded, which is what a generator produces when it encodes the emoji bytes. The other six are plain slugs that happen to begin with a hyphen, because the emoji was stripped and the space after it was not. So most of the front page's navigation is derived from decorative characters at the start of six headings, and removing one emoji silently breaks six links while leaving the other two working.

The parallel client example stops mid-parameter, and downloads open four connections

The multi-request example registers three callbacks, one for success, one for error and one for completion, and the block ends partway through the third callback's parameter list. That is the section a reader most wants in full, since parallel fan-out is a different failure mode from a single request: each instance carries its own URL, response, error code and error message, and the completion callback is what tells you the whole batch finished. It is cut off before you can see that signature. Elsewhere in the method list there is a download helper that takes a connection count defaulting to four, so file transfers are parallelised by default rather than one stream at a time, and there is a partial-read example alongside it. A retry method and before and after send callbacks complete the hook surface, none of them documented with a policy.

A Python version file sits in the root of a PHP library

The repository root contains eighteen entries and one of them is a Python version pin, in a project whose only build tool is a PHP dependency manager and whose language is PHP. Everything else in the root is coherent: an editor config, a git attributes file, three documentation files that the front page links to, a changelog, a licence, the composer manifest, and five directories for the source, tests, examples, scripts and documentation. But there is no PHP style or static-analysis configuration at the root at all, no formatter manifest and no analyser manifest, and the testing information is a markdown file rather than a runner configuration. So for a library whose whole appeal is a carefully specified option surface, the engineering constraints on contributions are less discoverable than the API.

Six PHP versions with a hard floor, and a route that installs a moving commit

The requirements section names six PHP versions, newest first, from the current release down to 8.0 as a floor. There is no provision for anything older, so the library has made a clean break with the versions before it. Installation has two commands and the second one is worth reading carefully: besides the normal require line there is a variant that pins the dependency to the development constraint, which installs the latest commit rather than a tagged release. Given the release list shows a numbered major from April and the last push is more recent than that, the two routes can hand you different code, and the front page does not say which one to use in production or what the compatibility story is for the moving one.

Headers readable under any casing, and two ways to upload a file

One short example exists to demonstrate that response headers are case-insensitive, and it prints the same header twice under two different spellings:

php
// Case-insensitive access to headers.
$curl = new Curl();
$curl->download('https://www.example.com/image.png', '/tmp/myimage.png');
echo $curl->responseHeaders['Content-Type'] . "\n"; // image/png
echo $curl->responseHeaders['CoNTeNT-TyPE'] . "\n"; // image/png

That is a deliberate convenience and it has a consequence worth knowing: you cannot recover the casing a server actually sent, and two headers differing only in case would collapse. Two other details from the examples. A file upload appears twice, once as a path string with a leading at-sign and once as an explicit file object, so both styles are first-class. And the option for enabling compression is written with a space before the comma, which is harmless and tells you the examples were typed by hand.

The example set is mostly about inspecting curl, and one sets a browser user-agent

The examples directory is weighted towards looking at what the extension did rather than towards making requests. Of the twenty-five entries visible, five are diagnostics or option display, two are download variants, two are progress reporting, and three each target a crypto exchange and a photo service, the latter including a class written for it. Two more are worth naming. One example posts a literal username and password as form fields to a login endpoint, which is the shape most people are copying, and one reaches past the wrapper to set a user-agent string describing an old browser on an old Windows. That last one exists because default agents get blocked, and publishing it is a reasonable thing for an HTTP library to do, but it is also the clearest statement in the examples about what the tool is for.

Editorial conclusion

php-curl-class fits a PHP codebase that has outgrown hand-written curl option arrays and wants one object with readable properties plus a parallel client for fan-out requests. Verify four things before you adopt it. Check that the name collision on the error property does not bite you, because the same identifier is a method in the reference list and a truthy value in the examples, so anything reflecting over the object has to know which it is reading. Read the security document, which the front page delegates entirely. Accept that redirect following is off until you turn it on, and that timeouts are on until you disable them, which are opposite defaults. And note that retry is a single method with no documented policy, so if you need bounded exponential backoff you will be writing it yourself.

Frequently asked questions

What is php-curl-class/php-curl-class?

A PHP wrapper around the curl extension that exposes requests, responses, headers and error state as readable properties rather than option arrays. It covers the usual verbs, cookies, headers, referrer and user-agent setters, basic authentication, redirect following, downloads, uploads, a retry method, before and after send callbacks, and a parallel multi-request client with success, error and completion callbacks.

Which PHP versions does php-curl-class support?

Six, from 8.0 as a hard floor up to the current release. Installation is through the PHP dependency manager, with a second command available that installs the latest commit rather than a tagged release, and the page does not say which route to use in production.

How do I check for an error in php-curl-class?

Read a property called error and, when it is truthy, print a sibling property holding the message and call the diagnose method. The same page also lists error in its method reference as a function that takes a callback, so the identifier names both a value and a callable, which matters if you reflect over the object or treat it as an array.

Does php-curl-class follow redirects by default?

No, there is a setter for following redirects and a separate example turns it on before requesting a shortened link. Timeouts go the other way: there is a method to disable them, which implies they are on by default. The examples include a download that does follow redirects as well as one that does not.

Can php-curl-class make several requests at once?

Yes, through a parallel client class that takes three callbacks, one for success, one for error and one for completion, each receiving the individual request instance with its own URL, response, error code and error message. The example for it is cut off partway through the third callback's parameters, so the completion signature is not shown. File downloads are also parallelised, with a connection count defaulting to four.

Official sources

  1. License: Unlicense
  2. php-curl-class/php-curl-class on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/php-curl-class-php-curl-class.svg)](https://hysenlabs.com/projects/php-curl-class-php-curl-class)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/php-curl-class-php-curl-class.svg)](https://hysenlabs.com/projects/php-curl-class-php-curl-class)

Was this useful?