PHP's resource to object transformation

Published On22 Nov 2020

PHP resource to object migration

resource is a special type in PHP that holds a reference to an external resource, hence its name. One of the long-term goals of PHP development is to phase out the use of resource in favor of standard class objects, that are more familiar with PHP users, supports typing in parameters, return types, and properties, and has a unified approach in handling in PHP internals.

Problems with Resources

Resources lead several back into the history, to PHP 4 era, where classes were not very commonly used, and exceptions were not often used either.

The resource type is not a type that you can coerce/cast to, or even a type that can be enforced with standard PHP parameter/return/property types. This is the case for all PHP versions, including PHP 8. With PHP 8 supporting scalar types and internal functions with type error support, the lack of resource type holds back some of the resource-related functionality to effectively add stricter types.

Internally, it brings challenges to PHP source code to maintain several resource types with its internal state, memory handling, reference counting, and other features which could use standard PHP classes.

Resource to Object Migration

One of the long-term efforts of PHP project is to migrate all resource objects to standard class objects.

Given the long-running history of PHP resource objects, they are often used extensively in PHP applications. A migration to class objects needs to be as least disruptive as possible.

Maintain Parameter and Return Type consistency

PHP resource objects do not provide an object-oriented interface, that it contains methods to call. All operations are done using functions.

A function that opens a resource (such as curl_init) will continue to return a value, but after the migration, it will return a resource class object instead.

All functions that previously accepted a resource are then modified to accept the new class object instead.

This approach maintains the majority of backwards-compatibility, because it requires zero modifications on the user's code; the internal code is different, but the API remains consistent.

Restrict Resource Class Objects

The newly migrated resource class objects can be created with the same functions that previously created the resource objects.

In PHP's resource to object migration plan, the classes are heavily restricted at this stage.

  • The classes are declared final, preventing from being extended.
  • The classes cannot be instantiated with new CurlHandle pattern. Users must use the same functions to instantiate them.

Resource Closing

Traditional resource objects required a resource-specific function to close a resource.

For example, a curl resource opened by curl_initfunction is closed with curl_close function. PHP tries to close the resource automatically when there are no references to the object, but it is a good practice to explicitly close the resources to avoid potential memory leaks.

In resource to object migration, the resource-closing functions are not removed, as it would cause a backwards-compatibility break. They are either deprecated, or turned into no-op functions that do not make any changes to the object.

Caveats When Migrating

is_resource() function returns false for resources that are closed, and the use of is_resource to validate a resource when it is accepted as a parameter, or right after creating a resource is quite common in many PHP applications.

After the migration, is_resource calls will return false, and can cause problems.

For the compatibility with all PHP versions, it might be necessary to check against the new class objects too:

- is_resource($curl_handle)
+ is_resource($curl_handle) || $curl_handle instanceof \CurlHandle

This is still an anti-pattern, because a failed resource creation function returns false instead of a resource (prior to migration) or a class object (after migration). A check against not false still more readable, accurate, and compatible across all PHP versions.

- is_resource($curl_handle)
+ $curl_handle !== false

Future Scope

When a traditional resource type is migrated to standard PHP classes, the functions that handle resource operations can be incorporated to class methods (e.g. curl_setopt to CurlHandle::setOpt).

This can simplify the code and improve developer experience, while removing several functions that were once scattered.

As of now, the new resource class objects are restricted from being extended, or let alone being instantiated with the new Foo() construct. This ensures that once PHP improves the class objects, there will be no further backwards-compatibility issues.

In PHP 8.0

In PHP 8.0, some of the most used extensions changes moves away from the traditional resource objects to standard PHP classes.

In PHP 8.0, they are work as value-objects as opposed to fully-featured classes with methods in them. Majority of these classes do not allow instantiating with the new Foo() construct either, and must be instantiated with the existing functions that returned resource objects in prior versions.

PHP 8.0's resource to object migration is quite seamless, as in all functions return and accept the new objects, and behave by the same semantics of the previous resource objects.

Extension resource (PHP < 8.0) object (PHP >= 8.0)
Curl Curl CurlHandle
Curl curl_multi CurlMultiHandle
Curl curl_share CurlShareHandle
GD gd GdImage
Sockets Socket Socket
Sockets AddressInfo AddressInfo
OpenSSL OpenSSL key OpenSSLAsymmetricKey
OpenSSL OpenSSL X.509 OpenSSLCertificate
OpenSSL OpenSSL X.509 CSR OpenSSLCertificateSigningRequest
XMLWriter xmlwriter XMLWriter
XML xml XMLParser

In PHP 8.1

PHP continues the migration in PHP 8.1 as well. With the Namespaces in bundled PHP extensions RFC passed for PHP 8.1, new classes declared on bundled extensions use namespaces.

Extension resource (PHP < 8.1) object (PHP >= 8.1)
GD gd font (integer) GdFont
FTP ftp FTP\Connection
IMAP imap IMAP\Connection
finfo file_info finfo
PSpell pspell (int) PSpell\Dictionary
PSpell pspell config (int) PSpell\Config
LDAP ldap link LDAP\Connection
LDAP ldap result LDAP\Result
LDAP ldap result entry LDAP\ResultEntry
PgSQL pgsql link \PgSql\Connection
PgSQL pgsql result \PgSql\Result
PgSQL pgsql large object \PgSql\Lob

Recent Articles on PHP.Watch

All ArticlesFeed 
How to fix PHP Curl HTTPS Certificate Authority issues on Windows

How to fix PHP Curl HTTPS Certificate Authority issues on Windows

On Windows, HTTPS requests made with the Curl extension can fail because Curl has no root certificate list to validate the server certificates. This article discusses the secure and effective solutions, and highlights bad advice that can leave PHP applications insecure.
AEGIS Encryption with PHP Sodium Extension

AEGIS Encryption with PHP Sodium Extension

The Sodium extension in PHP 8.4 now supports AEGIS-128L and AEGIS256 Authenticated Encryption ciphers. They are significantly faster than AES-GCM and CHACHA20-POLY1305. This article benchmarks them and explains how to securely encrypt and decrypt data using AEGIS-128L and AEGIS256 on PHP.
How to Install/Upgrade PHP 8.3 on MacOS with Homebrew

How to Install/Upgrade PHP 8.3 on MacOS with Homebrew

Install PHP 8.3 and PHP extensions on MacOS with Homebrew.
Subscribe to PHP.Watch newsletter for monthly updates

You will receive an email on last Wednesday of every month and on major PHP releases with new articles related to PHP, upcoming changes, new features and what's changing in the language. No marketing emails, no selling of your contacts, no click-tracking, and one-click instant unsubscribe from any email you receive.