Sommaire
Créer des variables
Présentation
Longs (Entiers)
Doubles (nombres à virgule flottante)
Chaînes de caractères
Booléens
Tableaux
Objets
Ressources
Les macros de création automatiques de variables globales
Creating Constants
|
7.11.8 Ressources
Les resources représentent un type de données spécial en PHP. Le terme de
resources ne fait référence à aucun type
de données en particulier, mais à une méthode d'abstraction, qui permet
de stocker n'importe quel type d'information. Les ressources sont conservées
dans une liste spéciale, à l'intérieur de Zend. Chaque entrée dans
cette liste a une définition de type correspondante. Zend gère
en interne toutes les références de ces ressources. L'accès aux ressources
est généralement impossible directement : uniquement en utilisant
une API fournie. Aussitôt que toutes les références sur une
ressource spécifique sont perdues, la fonction de destruction de
la ressource est appelée.
Par exemple, des ressources sont utilisées pour enregistrer des
liens avec uen base de données, ou un descripteur de fichier.
L'implémentation standard de facto peut être
lue dans le module MySQL, mais d'autres modules, comme celui d'oracle,
utilisent aussi les ressources.
Note |
En fait, une ressource peut être un pointeur vers n'importe quelles
informations dont vous auriez besoin (par exemple, un pointeur sur
une structure), et l'utilisateur doit simplement passer une ressource
uniques à toutes vos fonctions.
|
Pour créer une nouvelle ressource, vous devez enregistrer une fonction
de destruction de ressource. Comme vous pouvez enregistrer n'importe
quel type d'informations dans une ressource, Zend a besoin de savoir
comment libérer les ressources réservées, lorsque la ressource
ne sera plus utile. Cela se fait en enregistrant votre propre destructeur
de ressources, qui sera appelé par Zend lorsqu'il faudra détruire
vos données (manuellement, ou automatiquement). En enregistrant votre
destructeur de ressource, vous recevrez de Zend un
pointeur de type de ressource
pour cette ressource. Ce pointeur sera nécessaire à chaque fois
que vous voudrez accéder une ressource de ce type, et il est généralement
stocké dans une variable globale static, dans votre extension. Il n'y a pas
besoin de prendre en compte la sécurité thread, car vous n'aurez à
enregistrer votre destructeur de ressource qu'à l'initialisation
du module.
La fonction Zend d'enregistrement est la suivante :
ZEND_API int zend_register_list_destructors_ex(rsrc_dtor_func_t ld, rsrc_dtor_func_t pld, char *type_name, int module_number);
Il y a deux types différents de destructeurs de ressources, que vous pouvez
passer à cette fonction : un pointeur pour les ressources normales, et
un pointeur pour les ressources persistantes. Les ressources persistantes
sont par exemple utilisées dans les connexions aux bases de données.
Lorsque vous enregistrez une ressource, un de ces deux pointeurs devra
être fourni. Pour les autres pointeurs, passez simplement
NULL.
zend_register_list_destructors_ex accepte les paramètres
suivants :
>
>
ld |
Fonction de callback pour les destructeurs
de ressources normales. |
pld |
Fonction de callback pour les destructeurs
de ressources persistantes. |
type_name |
Une chaîne spécifiant le type de vos
ressources. C'est toujours mieux d'avoir un nom de ressource
unique à travers PHP, pour que les utilisateurs sachent ce
qu'ils manipulent sans ambiguité. Ce nom sera affiché
avec la fonction var_dump($resource);. |
module_number |
Le module_number
est automatiquement disponible dans votre fonction
PHP_MINIT_FUNCTION
et vous n'avez qu'à le passer ici. |
La valeur retournée est un identifiant unique ID pour votre
type de ressource .
Le pointeur de destructeur de ressource (soit normal, soit
persistant) a le prototype suivant :
void resource_destruction_handler(zend_rsrc_list_entry *rsrc TSRMLS_DC);
L'argument rsrc passé est un pointeur sur la structure suivante :
typedef struct _zend_rsrc_list_entry {
void *ptr;
int type;
int refcount;
} zend_rsrc_list_entry;
Le membre void *ptr est le pointeur réél sur votre
ressource.
Maintenant que nous savons comment tout cela se met en place,
nous pouvons définir nos propres ressources, que nous allons
enregistrer dans Zend. C'est une simple structure, avec deux
membres entiers :
typedef struct {
int resource_link;
int resource_type;
} my_resource;
Notre destructeur de ressources ressemblera à peut près à ceci :
void my_destruction_handler(zend_rsrc_list_entry *rsrc TSRMLS_DC) {
// Vous aurez probablement à transtyper votre pointeur void en
// une de vos structure
my_resource *my_rsrc = (my_resource *) rsrc->ptr;
// Maintenant, faites ce que vous voulez avec votre ressource.
// fermer des fichiers, libérer de la mémoire, etc...
// N'oubliez pas de libérer la mémoire de votre ressource elle-même
do_whatever_needs_to_be_done_with_the_resource(my_rsrc);
}
Note |
Une chose importante à mentionner : si votre ressource est
une structure plutôt complexe, qui contient elle aussi des
pointeurs de mémoire allouée par vos soins, durant l'exécution,
vous devez les libérer avant
de libérer la ressource elle-même.
|
Maintenant que nous avons défini
nous pouvons étudier les dernières étapes :
créer une variable globale dans l'extension,
qui contiendra l'identifiant de ressource, et qui sera ainsi
accessible à toutes les fonctions qui en ont besoin.
définir le nom de la ressource
écrire la fonction de destruction de la ressource
et finalement, enregistrer le pointeur
-
// Quelque part dans votre extension, définissez une variable pour vos ressources enregistrées
// si vous vous demandez ce que 'le' signifie : c'est simplement 'List Entry', élément de liste, en anglais.
static int le_myresource;
// Il est bon de définir votre nom de ressource quelque part
#define le_myresource_name "My type of resource"
[...]
// Maintenant, définissons le destructeur de pointeur de ressource
void my_destruction_handler(zend_rsrc_list_entry *rsrc TSRMLS_DC) {
my_resource *my_rsrc = (my_resource *) rsrc->ptr;
faite_ce_que_vous_devez_faire_avec_la_ressource(my_rsrc);
}
[...]
PHP_MINIT_FUNCTION(my_extension) {
// Notez que le 'module_number' est aussi fournit avec la fonction
// PHP_MINIT_FUNCTION().
le_myresource = zend_register_resource_destructors_ex(my_destruction_handler, NULL, le_myresource_name, module_number);
// Vous pouvez aussi enregistrer d'autres ressources, initialiser
// vos variables globales, etc...
}
Pour rééllement enregistrer une nouvelle ressource, vous pouvez
soit utiliser la fonction zend_register_resource
ou bien la macro zend_register_resoure : les deux
sont définies dans le fichier zend_list.h
.
Même si les deux sont identiques, il est toujours mieux de préférer
la macro, qui assure une compatibilité ascendante :
int ZEND_REGISTER_RESOURCE(zval *rsrc_result, void *rsrc_pointer, int rsrc_type);
>
>
rsrc_result |
C'est une enveloppe zval *
déjà initialisée. |
rsrc_pointer |
Le pointeur de ressource que vous voulez
stocker. |
rsrc_type |
Le type que vous avez reçu lorsque vous
avez enregistré la fonction de destruction de ressource. Si vous
avec suivi la méthode de nommage, cela devait être enregistré
dans le_myresource. |
La valeur retournée est un entier, qui identifiera sans ambiguité
la ressource.
Ce qui se passe en réalité lorsque vous enregistrez une ressource
est qu'elle est insérée dans une liste interne de Zend, et que le
résultat est simplement stocké dans l'enveloppe zval * :
rsrc_id = zend_list_insert(rsrc_pointer, rsrc_type);
if (rsrc_result) {
rsrc_result->value.lval = rsrc_id;
rsrc_result->type = IS_RESOURCE;
}
return rsrc_id;
La valeur retournée rsrc_id identifie la nouvelle ressource
enregistrée. Vous pouez utiliser la macro RETURN_RESOURE
pour la retourner à l'utilisateur.
RETURN_RESOURCE(rsrc_id)
Note |
C'est une pratique répandue que lorsque vous voulez retourner
une ressource immédiatement après sa création, à l'utilisateur,
de spécifier return_value comme enveloppe
de zval *.
|
Zend suit le nombre de références qui pointent sur cette ressource.
Aussitôt que le nombre de référence est rendu à 0, le destructeur
que vous avez enregistré est appelé. L'intérêt évident est que vous
n'avez plus à vous soucier de fuite de mémoire, introduites par
votre module : il vous suffit de lister toutes les allocations
que vous réalisez. Aussitôt que le script n'en aura plus besoin,
Zend les retrouvera pour vous, et vous les transmettra.
Maintenant que l'utilisateur a sa ressource, à un moment donné,
il va la passer à une de vos fonctions. Le membre value.lval
dans l'enveloppe zval * contient la clé de votre
ressource, et peut donc être utilisée pour lire la ressource avec cette
macro :
ZEND_FETCH_RESOURCE:
ZEND_FETCH_RESOURCE(rsrc, rsrc_type, rsrc_id, default_rsrc_id, resource_type_name, resource_type)
>
>
rsrc |
Ceci est votre pointeur, qui pointe sur vos
ressource déjà réservées.
|
rsrc_type |
C'est l'argument de transtypage de votre
pointeur, c'est à dire myresource *. |
rsrc_id |
Ceci est l,adresse de l'enveloppe
zval *, que l'utilisateur à passé
à votre fonction, c'est à dire &z_resource
si zval *z_resource est fourni. |
default_rsrc_id |
Cet entier spécifie l'identifiant
de ressource ID si aucune ressource n'a pu être lue,
ou bien -1. |
resource_type_name |
C'est le nom de la ressource demandée.
C'est une chaîne, et elle est utilisée lorsque la ressource
n'a pu être trouvée, ou bien est invalide. Elle formera un
message d'erreur significatif. |
resource_type |
Le type de ressource resource_type
que vous avez obtenu lors de l'enregistrement de votre fonction
de destruction de ressource. Dans notre exemple, c'était
le_myresource. |
Cette macro n'a pas de valeur de retour. Elle est faite pour le confort
des développeurs, et prend en charge le passage des arguments TSRMLS,
et vérifie aussi si la ressource peut être lue. Il affiche un message
d'alerte et termine la fonctoin PHP avec la valeur NULL
si un problème est survenu lors de la lecture de la ressource.
Pour forcer la suppression d'une ressource dans une liste, utilisez
la fonction zend_list_delete. Vous pouvez aussi
forcer l'augmentation du compteur de référence si vous savez que vous
créer une autre référence à une valeur déjà alloueé (par exemple, si
vous réutilisez automatiquement une connexion par défaut à une base
de données). Dans ce cas, utilisez la fonction zend_list_addref.
Pour rechercher des ressources déjà allouées, utilisez
zend_list_find. L'API complète est disponible
dans le fichier zend_list.h
.
|