PHP create resource

Even though PHP could really get rid of the “resource” type, because custom object storage allows to build a PHP representation of any abstract kind of data, that resource type still exists in the current version of PHP, and you may need to deal with it.

If you need to create resources, we really would like to push you not to, but instead use objects and their custom storage management. Objects is the PHP type that can embed anything of any type. However, for historical reasons, PHP still knows about that special type “Resource”, and still makes use of it in its heart or in some extensions. Let’s see that type together. Beware however, it is really cryptic and suffers from a long past history, so don’t be surprised about its design especially when reading the source code about it

What is the “Resource” type?

Easy enough you know about it. We are talking about this here:

$fp = fopen('/proc/cpuinfo', 'r');
var_dump($fp); /* resource(2) of type (stream) */

Internally, a resource is bound to the zend_resource structure type:

struct _zend_resource {
        zend_refcounted_h gc;
        int               handle;
        int               type;
        void             *ptr;
};

We find the traditional zend_refcounted_h header, meaning that resources are reference countable.

The handle is an integer that is used internally by the engine to locate the resource into an internal resource table. It is used as the key for such a table.

The type is used to regroup resources of the same type together. This is about the way resources get destroyed and how they are fetched back from their handle.

Finally, the ptr field in zend_resource is your abstract data. Remember resources are about storing an abstract data that cannot fit in any data type PHP can represent natively (but objects could, like we said earlier).

Resource types and resource destruction

Resources must register a destructor. When users use resources in PHP userland, they usually don’t bother cleaning those when they don’t make use of them anymore. For example, it is not uncommon to see an

struct _zend_resource {
        zend_refcounted_h gc;
        int               handle;
        int               type;
        void             *ptr;
};
1 call, and not see the matching
struct _zend_resource {
        zend_refcounted_h gc;
        int               handle;
        int               type;
        void             *ptr;
};
2 call. Using the C language, this would be at best a bad idea, at most a disaster. But using a high level language like PHP, you ease things.

You, as an internal developer, must be prepared to the fact that the user would create a lot of resources you’ll allow him to use, without properly cleaning them and releasing memory/OS resource. You hence must register a destructor that will be called anytime the engine is about to destroy a resource of that type.

Destructors are grouped by types, so are resources themselves. You won’t apply the destructor for a resource of type ‘database’ than for a resource of type ‘file’.

There also exists two kinds of resources, here again differentiated about their lifetime.

  • Classical resources, the most used ones, do not persist across several requests, their destructor is called at request shutdown.

  • Persistent resources will persist across several requests and will only get destroyed when the PHP process dies.

Note

You may be interested by the PHP lifecycle chapter that shows you the different steps occurring in PHP’s process life. Also, the Zend Memory Manager chapter may help in understanding concepts of persistent and request-bound memory allocations.

Playing with resources

The resources related API can be found in zend/zend_list.c. You may find some inconsistencies into it, like talking about “lists” for “resources”.

Creating resources

To create a resource, one must first register a destructor for it and associate it to a resource type name using

struct _zend_resource {
        zend_refcounted_h gc;
        int               handle;
        int               type;
        void             *ptr;
};
3. That call will return an integer that represents the type of resource you register. You must remember that integer because you will need it later-on to fetch back your resource from the user.

After that, you can register a new resource using

struct _zend_resource {
        zend_refcounted_h gc;
        int               handle;
        int               type;
        void             *ptr;
};
4. That one will return you a zend_resource. Let’s see together a simple use-case example:

#include 

int res_num;
FILE *fp;
zend_resource *my_res;
zval my_val;

static void my_res_dtor(zend_resource *rsrc)
{
    fclose((FILE *)rsrc->ptr);
}

/* module_number should be your PHP extension number here */
res_num = zend_register_list_destructors_ex(my_res_dtor, NULL, "my_res", module_number);
fp      = fopen("/proc/cpuinfo", "r");
my_res  = zend_register_resource((void *)fp, res_num);

ZVAL_RES(&my_val, my_res);

What we do in the code above, is that we open a file using libc’s

struct _zend_resource {
        zend_refcounted_h gc;
        int               handle;
        int               type;
        void             *ptr;
};
1, and store the returned pointer into a resource. Before that, we registered a destructor which when called will use libc’s
struct _zend_resource {
        zend_refcounted_h gc;
        int               handle;
        int               type;
        void             *ptr;
};
2 on the pointer. Then, we register the resource against the engine, and we pass the resource into a
struct _zend_resource {
        zend_refcounted_h gc;
        int               handle;
        int               type;
        void             *ptr;
};
8 container that could get returned to userland.

Note

Zvals chapter can be found .

What must be remembered is resource type. Here, we register a resource of type “my_res”. This is the type name. The engine does not really care about type name, but type identifier, the integer returned by

struct _zend_resource {
        zend_refcounted_h gc;
        int               handle;
        int               type;
        void             *ptr;
};
3. You should remember it somewhere, like we do in the
#include 

int res_num;
FILE *fp;
zend_resource *my_res;
zval my_val;

static void my_res_dtor(zend_resource *rsrc)
{
    fclose((FILE *)rsrc->ptr);
}

/* module_number should be your PHP extension number here */
res_num = zend_register_list_destructors_ex(my_res_dtor, NULL, "my_res", module_number);
fp      = fopen("/proc/cpuinfo", "r");
my_res  = zend_register_resource((void *)fp, res_num);

ZVAL_RES(&my_val, my_res);
0 variable.

Fetching back resources

Now that we registered a resource and put it in a

struct _zend_resource {
        zend_refcounted_h gc;
        int               handle;
        int               type;
        void             *ptr;
};
8 for an example, we should learn how to fetch back that resource from the userland. Remember, the resource is stored into the
struct _zend_resource {
        zend_refcounted_h gc;
        int               handle;
        int               type;
        void             *ptr;
};
8. Into the resource is stored the resource type number (on the type field). Thus, to be given back our resource from the user, we must extract the zend_resource from the
struct _zend_resource {
        zend_refcounted_h gc;
        int               handle;
        int               type;
        void             *ptr;
};
8, and call
#include 

int res_num;
FILE *fp;
zend_resource *my_res;
zval my_val;

static void my_res_dtor(zend_resource *rsrc)
{
    fclose((FILE *)rsrc->ptr);
}

/* module_number should be your PHP extension number here */
res_num = zend_register_list_destructors_ex(my_res_dtor, NULL, "my_res", module_number);
fp      = fopen("/proc/cpuinfo", "r");
my_res  = zend_register_resource((void *)fp, res_num);

ZVAL_RES(&my_val, my_res);
6 to get back our
#include 

int res_num;
FILE *fp;
zend_resource *my_res;
zval my_val;

static void my_res_dtor(zend_resource *rsrc)
{
    fclose((FILE *)rsrc->ptr);
}

/* module_number should be your PHP extension number here */
res_num = zend_register_list_destructors_ex(my_res_dtor, NULL, "my_res", module_number);
fp      = fopen("/proc/cpuinfo", "r");
my_res  = zend_register_resource((void *)fp, res_num);

ZVAL_RES(&my_val, my_res);
7 pointer:

/* ... later on ... */

zval *user_zval = /* fetch zval from userland, assume type IS_RESOURCE */

ZEND_ASSERT(Z_TYPE_P(user_zval) == IS_RESOURCE); /* just a check to be sure */

fp = (FILE *)zend_fetch_resource(Z_RESVAL_P(user_zval), "my_res", res_num);

Like we said : get back a zval from the user (of type

#include 

int res_num;
FILE *fp;
zend_resource *my_res;
zval my_val;

static void my_res_dtor(zend_resource *rsrc)
{
    fclose((FILE *)rsrc->ptr);
}

/* module_number should be your PHP extension number here */
res_num = zend_register_list_destructors_ex(my_res_dtor, NULL, "my_res", module_number);
fp      = fopen("/proc/cpuinfo", "r");
my_res  = zend_register_resource((void *)fp, res_num);

ZVAL_RES(&my_val, my_res);
8), and fetch the resource pointer back from it by calling
#include 

int res_num;
FILE *fp;
zend_resource *my_res;
zval my_val;

static void my_res_dtor(zend_resource *rsrc)
{
    fclose((FILE *)rsrc->ptr);
}

/* module_number should be your PHP extension number here */
res_num = zend_register_list_destructors_ex(my_res_dtor, NULL, "my_res", module_number);
fp      = fopen("/proc/cpuinfo", "r");
my_res  = zend_register_resource((void *)fp, res_num);

ZVAL_RES(&my_val, my_res);
6.

That function will check if the type of the resource is of the type you pass as third parameter (

#include 

int res_num;
FILE *fp;
zend_resource *my_res;
zval my_val;

static void my_res_dtor(zend_resource *rsrc)
{
    fclose((FILE *)rsrc->ptr);
}

/* module_number should be your PHP extension number here */
res_num = zend_register_list_destructors_ex(my_res_dtor, NULL, "my_res", module_number);
fp      = fopen("/proc/cpuinfo", "r");
my_res  = zend_register_resource((void *)fp, res_num);

ZVAL_RES(&my_val, my_res);
0 here). If yes, it extracts back the
/* ... later on ... */

zval *user_zval = /* fetch zval from userland, assume type IS_RESOURCE */

ZEND_ASSERT(Z_TYPE_P(user_zval) == IS_RESOURCE); /* just a check to be sure */

fp = (FILE *)zend_fetch_resource(Z_RESVAL_P(user_zval), "my_res", res_num);
1 resource pointer you need and we are done. If not, then it throws a warning like “supplied resource is not a valid {type name} resource”. This could happen if for example you expect a resource of type “my_res”, and you are given a zval with a resource of type “gzip”, like one returned by
/* ... later on ... */

zval *user_zval = /* fetch zval from userland, assume type IS_RESOURCE */

ZEND_ASSERT(Z_TYPE_P(user_zval) == IS_RESOURCE); /* just a check to be sure */

fp = (FILE *)zend_fetch_resource(Z_RESVAL_P(user_zval), "my_res", res_num);
2 PHP function.

Resource types are just a way for the engine to mix different kind of resources (of type “file”, “gzip” or even “mysql connection”) into the same resource table. Resource types have names, so that those can be used in error messages or in debug statement (like a

/* ... later on ... */

zval *user_zval = /* fetch zval from userland, assume type IS_RESOURCE */

ZEND_ASSERT(Z_TYPE_P(user_zval) == IS_RESOURCE); /* just a check to be sure */

fp = (FILE *)zend_fetch_resource(Z_RESVAL_P(user_zval), "my_res", res_num);
3), and they also are represented as an integer used internally to fetch back the resource pointer from it, and to register a destructor with the resource type.

Note

Like you can see, if we would have used objects, those represent types by themselves, and there wouldn’t have to happen that step of fetching back a resource from its identifier verifying its type. Objects are self-describing types. But resources are still a valid data type for the current PHP version.

Reference counting resources

Like many other types, zend_resource is reference counted. We can see its zend_refcounted_h header. Here is the API to play with reference counting, if you need it (you shouldn’t really need it on an average):

  • /* ... later on ... */
    
    zval *user_zval = /* fetch zval from userland, assume type IS_RESOURCE */
    
    ZEND_ASSERT(Z_TYPE_P(user_zval) == IS_RESOURCE); /* just a check to be sure */
    
    fp = (FILE *)zend_fetch_resource(Z_RESVAL_P(user_zval), "my_res", res_num);
    
    6 decrements refcount and destroys resource if drops to zero

  • /* ... later on ... */
    
    zval *user_zval = /* fetch zval from userland, assume type IS_RESOURCE */
    
    ZEND_ASSERT(Z_TYPE_P(user_zval) == IS_RESOURCE); /* just a check to be sure */
    
    fp = (FILE *)zend_fetch_resource(Z_RESVAL_P(user_zval), "my_res", res_num);
    
    7 checks if refcount is zero, and destroys the resource if true.

  • /* ... later on ... */
    
    zval *user_zval = /* fetch zval from userland, assume type IS_RESOURCE */
    
    ZEND_ASSERT(Z_TYPE_P(user_zval) == IS_RESOURCE); /* just a check to be sure */
    
    fp = (FILE *)zend_fetch_resource(Z_RESVAL_P(user_zval), "my_res", res_num);
    
    8 calls the resource destructor whatever the conditions

Persistent resources

Persistent resources don’t get destroyed at the end of the request. The classical use-case for that are persistent database connections. Those are connections that are recycled from request to request (with all the bullshit that will bring).

Traditionally, you should not be using persistent resources, as one request will be different from the other. Reusing the same resource should really be thoughtful before going this way.

To register a persistent resource, use a persistent destructor instead of a classical one. This is done in the call to

struct _zend_resource {
        zend_refcounted_h gc;
        int               handle;
        int               type;
        void             *ptr;
};
3, which API is like:

What is meant by resource in PHP?

Resources ¶ A resource is a special variable, holding a reference to an external resource. Resources are created and used by special functions. See the appendix for a listing of all these functions and the corresponding resource types. See also the get_resource_type() function.

What does get_resource_type mean in PHP?

The get_resource_type() function returns the type of a resource.

Is PHP a resource?

PHP is_resource() Function The is_resource() function checks whether a variable is a resource or not. Note: The is_resource() function will return FALSE if the resource has been closed. This function returns true (1) if the variable is a resource, otherwise it returns false/nothing.

Is resource a data type in PHP?

PHP Resource The special resource type is not an actual data type. It is the storing of a reference to functions and resources external to PHP. A common example of using the resource data type is a database call.