8.10 Créer des variables
8 Développer PHP 4.0
Manuel PHP
. Présentation . Entiers (Longs) . Les nombres à virgules flottantes (Doubles, Floats) . Chaînes de caractères (strings) . Booléens . Tableaux . Objets ->Ressources . Macros de création automatique de variables globales . Créations de constantes
|
8.10.8 Ressources
Les ressources sont des types de données spéciaux en PHP. Le terme de
ressources
ne fait pas référence à un type spécial
de données, mais représente une méthode d'abstraction, pour gérer
n'importe quelle type d'information. Les ressources sont gérées dans
une liste spéciale de Zend. Chaque entrée de cette liste dispose d'une
définition de type spéciale. Zend gère en interne les références
de toutes ces ressources. L'accès aux ressources n'est pas possible
directement : il faut utiliser l'API fournie. Aussitot que
toutes les références à une ressources sont perdues, une fonction
de destruction est appelée.
Par exemple, des ressources sont utilisées pour stocker les connexions
aux bases de données, ou des pointeurs de fichiers. Le standard
de facto
d'iomplémentation peut être trouvée dans
le module MySQL, mais d'autres modules comme celui d'Oracle
utilisent aussi des ressources.
Note |
En fait, une ressource peut être un pointeur sur n'importe quoi dont vous
auriez besoin pour gérer vos fonctions (ce peut être un pointeur sur une
structure), et l'utilisateur a simplement à passer cette variable de ressource
à toutes vos fonctions.
|
Pour créer une nouvelle ressource, vous devez enregistrer un destructeur
de ressource. Comme vous allez stocker n'importe quel type de données
dans votre ressource, Zend doit savoir comment les détuire lorsque la
ressource devra être libérée. Cela se fait en enregistrant un gestionnaire
de ressource, qui sera appelé par Zend dès que votre ressource doit être
libérée (manuellemetn ou automatiquement). Cet enregistrement auprès de
Zend vous donne le
gestionnaire de ressource
de cette ressource. Ce gestionnaire est nécessaire à chaque fois que
vous aurez à accéder à une ressource de ce type, et la plus part du temps,
il est stocké dans une variable globale statique de votre extension.
Il n'y a pas de problème de sécurité avec les threads, car ce gestionnaire
est crée une fois, durant l'initialisation du module.
La fonction d'enrgistrement de votre gestionnaire de ressource est le 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 adeux types de gestionnaire de ressources que vous pouvez passer à
cette fonction : le destructeur de ressources normales, et le destructeur
de ressources persistantes. Les ressources sont utilisées dans le cas
des connexions aux bases de données. Lorsque vous enregistrez une ressource,
l'un de ces deux gestionnaires doit être fourni. Si vous n'en utilisez
qu'un seul, passez la valeur de
NULL
pour l'autre.
zend_register_list_destructors_ex
accepte les
paramètres suivants :
ld
|
Destructeur de ressource normale. |
pld
|
Destructeur de ressource persistante. |
type_name
|
Une chaîne spécifiant le nom de votre
ressource. C'est toujours une bonne chose que de spécifier un
nom unique dans PHP pour le type de ressource. Lorsque l'utilisateur
appellera
var_dump
, il saura aussi quel
type de ressource est utilisé. |
module_number
|
La valeur de
module_number
est automatiquement disponible dans la macro
PHP_MINIT_FUNCTION
et donc, vous pouvez l'ignorer. |
La valeur retournée par la fonction est un identifiant unique de votre
type de ressource
.
Les destructeurs de ressources (permanantes ou normales) ont le
prototype suivant :
void resource_destruction_handler(zend_rsrc_list_entry *rsrc TSRMLS_DC);
Le pointeur
rsrc
référence une structure comme celle-ci :
typedef struct _zend_rsrc_list_entry { void *ptr; int type; int refcount;
} zend_rsrc_list_entry;
Le membre
void *ptr
est le pointeur réel de votre
ressource.
Maintenant que nous savons comment démarrer, définissons la ressource
que nous souhaitons dans Zend. C'est simplement une structure avec
deux entiers membres :
typedef struct { int resource_link; int resource_type;
} my_resource;
Notre destructeur de ressource va probablement ressembler à ceci :
void my_destruction_handler(zend_rsrc_list_entry *rsrc TSRMLS_DC) {
// Généralement, on transptype le pointeur void vers une structure my_resource *my_rsrc = (my_resource *) rsrc->ptr;
// Maintanent, faites ce que vous souhaitez avec votre ressource. // Fermer des fichiers, des sockets, libérez de la mémoire, etc... // De plus, 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 à citer : si votre ressource
est une structure plutôt complexe, qui contient des pointeurs vers
de la mémoire allouée durant l'exécution, il faut aussi les
libérer mais
avant
de libérer
votre ressource.
|
Maintenant que nous avons définit
- Ce que notre ressource est
- notre destructeur de ressource
nous pouvons nous consacrer aux autres étapes :
- créer une variable globale dans l'extension pour stocker
l'identifiant de ressource, pour qu'il soit accessible à toutes les
fonctions qui en auront besoin
- Définir un nom de ressource
- Ecrire le desctructeur de ressource
- et finalement, enregistrer le gestionnaire
// Quelque part dans votre extension, définissez la variable contenant vos ressources enregistrées // Si vous vous demandez ce que "le" signifie, c'est 'list entry' (élément de liste). static int le_myresource;
// C'est une bonne chose que de donner un nom à votre ressource #define le_myresource_name "My type of resource"
[...]
// Maintenant, codons réellement votre desctructeur de ressources void my_destruction_handler(zend_rsrc_list_entry *rsrc TSRMLS_DC) {
my_resource *my_rsrc = (my_resource *) rsrc->ptr; do_whatever_needs_to_be_done_with_the_resource(my_rsrc); }
[...]
PHP_MINIT_FUNCTION(my_extension) {
// Notez qu8e "module_number" est déjà fournie grâce à la définition // de PHP_MINIT_FUNCTION().
le_myresource = zend_register_resource_destructors_ex(my_destruction_handler, NULL, le_myresource_name, module_number);
// Vous pouvez enregistrer d'autres ressources, initialiser vos // variables globales, vos constantes, etc... }
Pour enregistrer réellement votre nouvelle ressource, vous pouvez
soit utiliser la fonction
zend_register_resource
ou bien la macro
zend_register_resoure
, qui sont
toutes les deux définies dans le fichier d'entête zend_list.h . Bien
que les arguments des deux soient exactement les mêmes, c'est
une bonne idée que d'utiliser la macro pour assurer une meilleure
compatibilité :
int ZEND_REGISTER_RESOURCE(zval *rsrc_result, void *rsrc_pointer, int rsrc_type);
rsrc_result
|
Une enveloppe
zval *
déjà allouée. |
rsrc_pointer
|
Votre pointeur de ressource, que vous souhaitez stocker. |
rsrc_type
|
Le type que vous avez reçu lorsque vous
avez enregistré votre destructeur de ressources. Si vous avez
suivi la convention de nommage, c'est
le_myresource
. |
La valeur retournée est un identifiant de ressource unique.
Ce qui se passe en réalité lorsque vous enregistrez une novuelle ressource,
c'est que vos valeurs sont insérées dans une liste interne de Zend, et que
le résultat est stocké dans l'enveloppe
zval *
fournie :
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 de manière unique
la nouvelle ressource. Vous pouvez utiliser la macro
RETURN_RESOURE
pour la retourner à l'utilisateur.
RETURN_RESOURCE(rsrc_id)
Note |
C'est une pratique courante si vous souhaitez retourner
imméditament une ressource à votre utilisateur que de spécifier
return_value
comme enveloppe
zval *
.
|
Zend prend en charge la ressource. Aussitôt que toutes les références
à cette ressources seront perdues, le destructeur que vous avez enregisté
sera appelé. La magie de ce concept est que vous n'avez pas à vous
soucier de fuites de mémoire, introduites par votre module : notez
bien toutes les allocations que votre ressource demande. Aussitôt que
cette mémoire doit etre libérée, Zend vous appelera, et vous demandera
de les libérer.
keeps track of all references to this resource. As soon as
Mainteant que l'utilisateur a sa ressource, et il la passe à
chacune de vos fonctions qui en a besoin. Le champs
value.lval
dans l'enveloppe
zval *
contient une clé vers votre ressource,
et sert donc à la récuperer, avec la macro suivante :
ZEND_FETCH_RESOURCE
:
ZEND_FETCH_RESOURCE(rsrc, rsrc_type, rsrc_id, default_rsrc_id, resource_type_name, resource_type)
rsrc
|
Votre pointeur, qui va pointer sur
votre ressource enregistrée précédemment. |
rsrc_type
|
C'est le type de votre pointeur,
i.e.
myresource *
. |
rsrc_id
|
C'est l'adresse de votre enveloppe
zval *
, que l'utilisateur a passé
à votre f onction, i.e.
&z_resource
si
zval *z_resource
est fourni. |
default_rsrc_id
|
Cet entier spécifie l'identifiant de ressource
par défaut, 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 de caractèers, et elle est utilisée lorsque
la ressource n'a pu être trouvée, ou qu'un message d'erreur
intelligible n'a pu être constitué. |
resource_type
|
Le type de ressource
resource_type
que vous avez obtenu lorsque de l'enregistrement de votre destructeur de
ressource. Dans notre exemple, c'était
le_myresource
. |
Cette macro n'a pas de valeur de retour. C'est fait pour le confort
des développeurs, et elle prend en charge les arguments
de TSRMLS, ainsi que la vérification de la validité de la ressource
lue. Au besoin, elle émet une alerte, et termine la fonction PHP
courante avec la valeur
NULL
, si un problème de
lecture de la ressource été rencontré.
Pour forcer la suppression d'une ressource de la liste, utilisez la
fonction
zend_list_delete
. Vous pouvez aussi
former le compteur de référence à 0 si vous savez que vous allez
creer un autre référence pour une valeur précédemment allouée
(par exemple, si vous réutilisez une connexion à une base de données
par défaut). Pour recherche les ressources déjà allouée, utilisez
la fonction
zend_list_find
. L'API complète est
disponible dans le fichier
zend_list.h
.
|