rfc:curl-oop

PHP RFC: Add OOP methods to Curl objects

Introduction

As part of the Resource to object conversion project, the cURL resource types were converted to objects with the release of PHP 8.0 . Currently, those objects are still opaque types for holding and managing the underlying libcurl types, and do not offer any APIs for use by script authors.

Proposal

This RFC aims to add OOP interfaces to the cURL extension, primarily by aliasing free functions to matching methods in the `CurlHandle`, `CurlMultiHandle`, and `CurlShareHandle` classes. Additionally, this RFC aims to make a handful of changes to the behaviors and return values of some methods in the interest of presenting a more objects-style API.

Exceptions

Four new exceptions will be introduced. A top level `CurlException` to cover all cURL exception types, plus three specific exceptions as children of `CurlException`: `CurlHandleException`, `CurlMultiException`, and `CurlShareException`.

CurlHandle

The `CurlHandle` class will be expanded as follows:

/**
 * @strict-properties
 * @not-serializable
 */
final class CurlHandle
{
        /**
         * Behaves similarly to `curl_init(?string $uri = null): \CurlHandle`,
         * however this constructor implicitly sets CURLOPT_RETURNTRANSFER == true.
         */
	public function __construct(?string $uri = null) {}

	/** @alias curl_errno */
	public function errno(): int {}

	/** @alias curl_error */
	public function error(): string {}

	/** @alias curl_strerror */
	static public function strerror(int $code): string {}

	/** @alias curl_escape */
	public function escape(string $str): string {}

	/** @alias curl_unescape */
	public function unescape(string $str): string {}

	/**
         * @throws CurlHandleException
         *
         * Similar to `curl_exec(\CurlHandle $ch): string|bool`,
         * but never returns False, since errors are promoted to exceptions.
         */
	public function exec(): string|true {}

	/** @alias curl_pause */
	public function pause(int $flags): int {}

	/** @alias curl_reset */
	public function reset(): void {}

	/** @alias curl_getinfo */
	public function getInfo(?int $option = null): mixed {}

#if LIBCURL_VERSION_NUM >= 0x073E00 /* Available since 7.62.0 */
	/** @alias curl_upkeep */
	public function upkeep(): bool {}
#endif

	/**
	 * Varies from curl_setopt() to allow fluent chaining.
	 * @throws CurlHandleException
	 */
	public function setOpt(int $option, mixed $value): \CurlHandle {}

	/**
	 * Returns self to match setOpt() behavior.
	 * @throws CurlHandleException
	 */
	public function setOptArray(array $option): \CurlHandle {}
}

CurlMultiHandle

The `CurlMultiHandle` class will be expanded as follows:

/**
 * @strict-properties
 * @not-serializable
 */
final class CurlMultiHandle
{
	/**
	 * Returns self for fluent calling.
	 * @throws CurlException.
	 */
	public function addHandle(\CurlHandle $handle): \CurlMultiHandle {}

	/**
	 * Returns self for fluent calling.
	 * @throws CurlException.
	 */
	public function removeHandle(\CurlHandle $handle): \CurlMultiHandle {}

	/**
	 * Returns self for fluent calling.
	 * @throws CurlException.
	 */
	public function setOpt(int $option, mixed $value): \CurlMultiHandle {}

	/** @alias curl_multi_errno */
	public function errno(): int {}

	/** @alias curl_multi_error */
	public function error(): ?string {}

	/** @alias curl_multi_strerror */
	public function strerror(int $error_code): ?string {}

	/**
	 * Returns TRUE if still running, FALSE otherwise.
	 * @param int $still_running
	 * @throws CurlException.
	 */
	public function exec(&$still_running): bool {}

	/** @alias curl_multi_getcontent */
	static public function getContent(\CurlHandle $handle): ?string {}

	/**
	 * @alias curl_multi_info_read
	 * @param int $queued_messages
	 * @return array<string, int|object>|false
	 * @refcount 1
	 */
	public function infoRead(&$queued_messages = null): array|false {}

	/** @alias curl_multi_select */
	public function select(float $timeout = 1.0): int {}
}

CurlShareHandle

The `CurlShareHandle` class will be expanded as follows:

/**
 * @strict-properties
 * @not-serializable
 */
final class CurlShareHandle
{

	/** @alias curl_share_errno */
	public function errno(): int {}

	/** @alias curl_share_error */
	public function error(): ?string {}

	/** @alias curl_share_strerror */
	static public function strerror(): ?string {}

	/**
	 * Returns self for fluent calling.
	 * @throws CurlException.
	 */
	public function setOpt(int $option, mixed $value): \CurlShareHandle {}
}

New Functions

To make the functional API more consistent (and provide functions for the OOP implementation to alias), the following two additional functions will be added (psuedo-implementation shown):

function curl_multi_error(CurlMultiHandle $multi_handle): ?string {
    $errno = curl_multi_errno($multi_handle);
    return $errno ? curl_multi_strerror($errno) ? NULL;
}

function curl_share_error(CurlShareHandle $share_handle): ?string {
    $errno = curl_share_errno($share_handle);
    return $errno ? curl_share_strerror($errno) ? NULL;
}

Backward Incompatible Changes

No breaking changes for script code. Extensions will note small changes in intialization performed by `object_init_ex(return_value, curl_ce);` as now `curl_easy_init()` and other initialization happens in `curl_object_create` rather than deferring to constructor/curl_init().

Proposed PHP Version(s)

8.4.0

Unaffected PHP Functionality

Script code written for the original cURL functional API will not be impacted.

Proposed Voting Choices

Straight yes/no.

Patches and Tests

Each existing unit test will be reviewed and duplicated as appropriate to cover the OOP version of the API.

* Work in progress: https://github.com/php/php-src/pull/13394 Note that as a work in progress this may not 100% match the proposal above until it is complete.

Implementation

TBD

References

TBD

Rejected Features

TBD

rfc/curl-oop.txt · Last modified: 2024/02/14 21:57 by pollita