Retrouvez cet article dans : Linux Magazine 99
Cet article n’a la prétention ni d’être exhaustif, ni d’être très détaillé, mais plutôt de vous donner une vue d’ensemble et d’introduire les mécanismes de base nécessaires à l’écriture d’extensions pour PHP (des notions de shell, C et PHP sont nécessaires à sa compréhension).
Le langage PHP a été créé en 1995 par Rasmus Lerdorf. À l’origine, il s’agissait d’une simple collection de scripts Perl nommée « PHP/FI » (Personnal Home Page Tools). Par la suite, le PHP (Hypertext Preprocessor) a été réimplémenté en C pour devenir le langage que nous connaissons. La dernière avancée notable de ce langage est l’intégration d’un véritable modèle objet dans sa version 5.
Nous allons voir dans cet article comment écrire une extension pour PHP : une sorte de module écrit en C qui permet d’étendre le langage par des bibliothèques compilées, adaptées à des projets spécifiques, et optimisant le temps d’exécution de certaines fonctions. Le site PECL [1] recense l’ensemble des extensions « officielles » de PHP. Vous pourrez y trouver de nombreux exemples d’extensions :
statspermettant d’effectuer des calculs statistiques ;date_timepermettant de manipuler plus simplement les dates et les heures...
Il existe deux méthodes pour créer des extensions PHP : une méthode totalement manuelle et une méthode de génération de code à partir d’un fichier XML. Nous commencerons par vérifier que votre système est correctement configuré pour pouvoir compiler ces extensions. Ensuite, nous créerons deux extensions en utilisant les deux méthodes disponibles ; la méthode manuelle est bien sûr plus longue que celle utilisant le générateur de code, mais il faut parfois corriger le code généré et il est alors intéressant de savoir quels sont les fichiers à modifier.
1. Préparation de l’environnement de travail
La première des choses à faire est de vous assurer que vous possédez bien tous les outils permettant de compiler votre extension. Il vous faut le code source de la version de PHP que vous avez installé et les outils de compilation. Sous Debian, il vous faudra installer les paquetages suivants : php5, php5-dev, apache2, gcc, make, autoconf, automake et libtool. Les sources de PHP seront installés dans /usr/include/php5/. Ce répertoire contient, entre autres, les répertoires suivants :
ext/: contient les extensions déjà intégrées ;main/: contient entre autre les fichiersphp.hetphp_ini.hindispensables à la création d’une nouvelle extension ;Zend/: moteurZend.
Pour les autres systèmes, si vous disposez d’un gestionnaire de paquetages, vous pouvez l’utiliser pour l’installation ; puis recherchez le répertoire d’installation des sources de PHP (le répertoire php5/ que nous venons de voir et qui contient les répertoires ext/, main/ et Zend/) : une recherche du fichier php_ini.h devrait vous aider (locate php_ini.h). Sinon, récupérez les sources de PHP sur http://www.php.net/downloads et vérifiez que les outils mentionnés ci-dessus sont bien installés. Dans la suite de cet article, les chemins et noms de paquetages seront toujours donnés pour des distributions basées sur Debian : l’adaptation pour d’autres distributions ne devrait pas poser de problème.
Une fois le fichier contenant les sources correctement décompressé, la compilation de PHP est très simple et se déroule en deux étapes :
- La configuration permettant de choisir les options à activer (support du module
gd,pear...). Pour afficher la liste des options disponibles :./configure –help. Une fois vos options choisies, lancez la configuration avec, par exemple :./configure –enable-cli –enable-pear –enable-debug... - La compilation proprement dite :
make all install.
En figure 1, vous pourrez voir le mécanisme général de compilation de PHP pour les extensions choisies,

Figure 1 : Les étapes de la compilation de PHP
À la fin de cette étape, vous disposez d’un environnement PHP opérationnel et reconfigurable. Nous pouvons commencer l’écriture de notre extension.
2. Une première extension
Notre premier code sera le traditionnel « Hello World ». La création d’une extension se déroule en trois étapes :
- l’écriture d’un fichier de configuration (
config.m4) qui permettra d’activer l’extension lors de la compilation de PHP (voir figure 1) ; - l’écriture de l’extension en C qui se décompose elle-même en deux étapes avec la création d’un fichier contenant les en-têtes et d’un fichier contenant le code principal ;
- et, enfin, la compilation de l’extension qui aboutira à la création d’un fichier de module
.so.
Pour créer cette extension, nous allons nous placer dans le répertoire ext/ des sources de PHP (/usr/include/php5/ext/ sous Debian). Créez un répertoire hello_world/ – ce sera le nom de notre extension – en prenant garde aux droits d’écriture (vous devez être root pour écrire dans ce répertoire). L’ensemble des fichiers que nous allons maintenant créer sera contenu dans ce répertoire (/usr/include/php5/ext/hello_world/).
2.1 Fichier de configuration (config.m4)
Comme dit précédemment, le fichier de configuration de l’extension permet d’ajouter une option à activer lors de la configuration de PHP. Ce mécanisme est activé par la création d’un fichier config.m4.
01: PHP_ARG_ENABLE 02: ( 03: hello_world, 04: [ Whether to enable the «hello_world» extension ], 05: [ --enable-hello_world Enable «hello_world» extension support ] 06: ) 07: 08: if test $PHP_HELLO_WORLD = «yes»; then 09: AC_DEFINE(HAVE_HELLO_WORLD, 1, [ Wether you have «hello_world» ]) 10: PHP_NEW_EXTENSION(hello_world, hello_world.c, $ext_shared) 11: fi
Quelques explications sur le contenu de ce fichier :
Dans les lignes 1 à 6 :
- En ligne 3, on déclare le nom de notre extension.
- En ligne 4, on définit le message de vérification qui s’affichera lors de la compilation (si l’option
--quietn’a pas été activée ) sous la forme d’une ligne «checking...». - En ligne 5, le message d’aide.
En ligne 8, si la variable $PHP_HELLO_WORLD est bien activée (variable créée lors de la configuration si la compilation du module hello_world a été précisée à l’aide de l’option --enable-hello_world), alors on ajoute une constante HAVE_HELLO_WORLD ayant pour valeur 1 et avec, comme commentaire, le dernier paramètre de la macro AC_DEFINE (ici « Wether you have (...) », ligne 9). Ensuite, ligne 10, on active l’extension se trouvant dans le répertoire hello_world, composée du fichier hello_world.c.
2.2 Fichiers C
Nous allons maintenant définir le « cœur » de notre extension qui sera codé en C.
2.2.1 Fichier d’en-têtes (hello_world.h)
Le fichier d’en-têtes va permettre de déclarer les constantes et l’environnement de travail.
01: #ifndef PHP_HELLO_WORLD_H 02: 03: #define PHP_HELLO_WORLD_H 04: 05: #define PHP_HELLO_WORLD_EXTNAME «hello_world» 06: #define PHP_HELLO_WORLD_EXTVER «1.0» 07: 08: #ifdef HAVE_CONFIG_H 09: #include «config.h» 10: #endif 11: 12: #include «php.h» 13: extern zend_module_entry sample_module_entry; 14: #define phpext_sample_ptr &sample_module_entry 15: 16: #endif
Les lignes 1 et 3 permettent de prévenir des inclusions multiples du fichier d’en-têtes. Les lignes 5 et 6 définissent les propriétés de l’extension. Les lignes 8 à 10 importent les options de configuration pour le cas d’une compilation à l’extérieur de l’arbre des sources de PHP. Enfin, la ligne 12 inclut le header standard PHP et les lignes 13 et 14 définissent les symboles de point d’entrée que PHP utilisera lors du chargement de ce module.
2.2.2 Fichier principal (hello_world.c)
Le fichier principal contient le code qui sera accessible en utilisant notre extension.
01: #include «php_hello_world.h»
02:
03: zend_module_entry hello_world_module_entry =
04: {
05: #if ZEND_MODULE_API_NO >= 20010901
06: STANDARD_MODULE_HEADER,
07: #endif
08: PHP_HELLO_WORLD_EXTNAME,
09: NULL, // Fonctions
10: NULL, // MINIT
11: NULL, // MSHUTDOWN
12: NULL, // RINIT
13: NULL, // RSHUTDOWN
14: NULL, // MINFO
15: #if ZEND_MODULE_API_NO >= 20010901
16: PHP_HELLO_WORLD_EXTVER,
17: #endif
18: STANDARD_MODULE_PROPERTIES
19: };
20:
21: #ifdef COMPILE_DL_HELLO_WORLD
22: ZEND_GET_MODULE(hello_world)
23: #endif
En ligne 1, nous incluons le fichier d’en-têtes que nous avons créé (voir 2.1). Les lignes 3 à 19 définissent les propriétés de notre extension ; par exemple, le nom de notre extension en ligne 8, puis différentes listes de fonctions (toutes vides pour l’instant) :
- la liste des fonctions utilisateur en ligne 9 ;
- les fonctions appelées lors de l’initialisation (
MINIT) et de l’arrêt de l’extension (MSHUTDOWN) en lignes 10 et 11 (ces fonctions ne sont appelées qu’une fois) ; - les fonctions appelées à chaque début (
RINIT) ou fin d’appel à l’extension (RSHUTDOWN) en lignes 12 et 13 ; - la fonction appelée pour créer les informations sur l’extension dans le
phpinfo()(MINFO) en ligne 14.
Nous développerons plus loin les fonctions utilisateur et l’utilisation du phpinfo.
Enfin, les lignes 21 à 23 permettent d’ajouter une référence pour PHP qui sera utilisée lorsque l’extension sera chargée dynamiquement.
2.3 Compilation de l’extension
Il faut générer un fichier ./configure tenant compte des informations que nous avons ajoutées dans le fichier config.m4 de la section 2.1. Ceci est réalisé par la commande :
phpize
Il suffit ensuite d’exécuter :
./configure –enable-hello_world make
Et, si tout s’est correctement déroulé :
make install
Les anciennes extensions déjà activées seront conservées et un fichier hello_world.so sera généré dans le répertoire modules/ et copié dans votre répertoire d’extensions PHP (par exemple /usr/lib/php5/20060613+lfs/ – cette information vous est donnée par le make install).
Pour pouvoir utiliser notre extension, nous disposons alors de deux méthodes :
1. Déclaration dans le fichier php.ini (se trouvant dans /etc/php5/apache2/php.ini sur Debian) :
a. Aller en fin de fichier.
b. Ajouter les lignes :
extension = hello_world.so
c. Redémarrez le serveur Apache :
/etc/init.d/apache2 restart
Pour tester si l’extension est bien chargée, on peut alors créer et exécuter un petit script PHP get_loaded_extensions.php que je vous conseille de placer dans un répertoire extensions_tools/ dans lequel vous pourrez stocker tous vos petits scripts de test sur les extensions.
01: <?php
02: var_dump(get_loaded_extensions());
03: ?>
Le nom de notre extension « hello_world » doit apparaître dans la liste.
2. Chargement direct dans le fichier PHP grâce à l’instruction dl(). Ceci reviendrait à ajouter dans le script précédent une ligne dl(‘hello_world’); après la ligne 1. À mon avis, cette méthode n’est utile que si la première méthode ne fonctionne pas et pour ainsi savoir si l’erreur provient d’une mauvaise configuration du fichier php.ini. La première méthode est en effet beaucoup plus propre.
À ce point, notre extension ne fait strictement rien ! Il pourrait être intéressant de lui ajouter au moins une fonction...
2.4 Une fonction dans notre extension
Pour ajouter une fonction à notre extension, nous allons modifier le fichier hello_world.c de la façon suivante :
01: #include «php_hello_world.h»
02:
03: PHP_FUNCTION(print_hello_world)
04: {
05: php_printf(“Hello World !\n”);
06: }
07:
08: static function_entry php_hello_world_functions[] =
09: {
10: PHP_FE(print_hello_world, NULL)
11: {NULL, NULL, NULL}
12: };
13:
14: zend_module_entry hello_world_module_entry =
15: {
16: #if ZEND_MODULE_API_NO >= 20010901
17: STANDARD_MODULE_HEADER,
18: #endif
19: PHP_HELLO_WORLD_EXTNAME,
20: php_hello_world_functions, // Fonctions
21: NULL, // MINIT
22: NULL, // MSHUTDOWN
23: NULL, // RINIT
24: NULL, // RSHUTDOWN
25: NULL, // MINFO
26: #if ZEND_MODULE_API_NO >= 20010901
27: PHP_HELLO_WORLD_EXTVER,
28: #endif
29: STANDARD_MODULE_PROPERTIES
30: };
31:
32: #ifdef COMPILE_DL_HELLO_WORLD
33: ZEND_GET_MODULE(hello_world)
34: #endif
La variable php_hello_world_functions (lignes 8 à 12) contient la liste des fonctions définies dans notre extension (elle grossira au fur et à mesure que l’on ajoutera des fonctions) et se termine forcément par un vecteur NULL. L’instruction PHP_FE (PHP Function Entry) définit une entrée pour une fonction. La fonction elle-même est déclarée dans les lignes 3 à 6.
À ce stade, on peut tester notre fonction à l’aide du script suivant (test.php) :
01: <?php 02: print_hello_world(); 03: ?>
Vous devriez voir apparaître sur votre navigateur le message « Hello world ! ».
Notre extension est presque achevée ! Il nous reste à compléter les informations qui seront fournies par le phpinfo.
2.5 Le fichier phpinfo
Pour définir les informations contenues dans le phpinfo, il faut créer dans hello_world.c une fonction PHP_MINFO_FONCTION que vous pourrez par exemple placer en ligne 7 :
PHP_MINFO_FUNCTION(hello_world)
{
php_info_print_table_start();
php_info_print_table_row(2, «Sample Module», «enabled»);
php_info_print_table_row(2, «version», PHP_SAMPLE_EXTVER);
php_info_print_table_end();
}
De plus, il faudra modifier la ligne 25 de notre déclaration du hello_world_module_entry par :
PHP_MINFO(hello_world), // MINFO
Le premier argument de php_info_print_table_row indique le nombre de colonnes. Les arguments suivants remplissent les colonnes dans l’ordre.
Créez un petit script d’information sur la configuration de votre PHP, phpinfo.php, vous obtiendrez des informations sur votre extension :
01: <?php 02: phpinfo(); 03: ?>
Les lignes que nous venons d’écrire génèrent du code HTML. Il existe de nombreuses autres instructions php_info_print_* (pour la liste des fonctions voir [2]). Il est donc tout à fait possible d’utiliser également un simple php_printf pour générer les lignes du tableau (explorez le code source obtenu à partir du phpinfo pour trouver le nom des classes CSS correspondant à ce que vous désirez faire). Ainsi, on peut, par exemple, ajouter une image :
php_printf(«<tr><td class=\»v\»>Image</td><td class=\»v\»><a href=\»http://www.gnulinuxmag.com/\»><img src=\»lm_logo_150.png\» alt=\»LinuxMagazine\»/></a></td></tr>»);
Nous avons réussi à créer une extension simpliste entièrement manuellement. Mais, il existe une méthode plus efficace...
3. Alternative à la construction manuelle
Plutôt que d’écrire manuellement le squelette de toutes vos extensions, il existe un générateur de code sur PEAR : CodeGen_PECL [3] (connu auparavant sous le nom PECL_Gen dans PECL). Il s’agit du remplaçant du script ext_skel qui est maintenant déprécié (bien que toujours fourni avec les sources de PHP).
Ce générateur de code va lire les options de configuration, les prototypes de fonctions et les fragments de code dans un fichier de description XML et va générer une extension PECL complète et prête à être compilée (Voir Figure 2).
3.1 Installation de CodeGen_PECL
L’installation se fait de manière très simple comme pour toutes les extensions PEAR/PECL :
pear install --alldeps CodeGen_PECL
Et bien sûr, si vous ne disposez pas encore de l’installateur PEAR, il vous faudra le récupérer pour votre version de Linux (apt-get install pear pour Debian).

Figure 2 : Les étapes de la compilation de PHP en utilisant CodeGen_PECL
Il existe trois modes d’utilisation :
- génération complète d’une extension à partir de spécifications XML ;
- simple squelette généré depuis une ligne de commandes ;
- compatibilité avec
ext_skel.
Je ne m’intéresserai ici qu’au premier mode qui nous permettra de construire complètement notre extension (avant d’y faire éventuellement quelques retouches manuelles). Pour une utilisation en mode « ext_skel », vous pourrez vous reporter au manuel PHP [4].
3.2 Le fichier XML
Comme nous l’avons vu, les spécifications de l’extension sont stockées dans un fichier XML. Pour notre extension hello_world, nous allons donc créer un fichier hello_world_gen.xml (toujours dans le répertoire des extensions PHP /usr/include/php5/ext/). Le fichier minimal décrivant l’extension est :
01: <?xml version = «1.0»?> 02: <extension name = «hello_world_gen» />
La génération des fichiers de l’extension se fait alors en lançant le générateur CodeGen_PECL :
pecl-gen hello_world_gen.xml
Pour construire l’extension, les instructions sont alors les mêmes que celles vues à la section 2.3. De nombreux fichiers ont été générés dans /usr/include/php5/ext/hello_world_gen/. Nous reviendrons sur les plus importants par la suite.
Notez à ce point que, contrairement à la méthode précédente, si vous lancez le script phpinfo.php, vous obtiendrez des informations minimales sur votre extension (vide pour l’instant).
Bien sûr, les informations données pour le moment ne sont pas très intéressantes (quelque chose comme « The unknown extension »). Mais, vous pouvez voir que le générateur a renseigné automatiquement cette page. Amusons-nous donc maintenant à compléter correctement les informations fournies par le phpinfo (toujours dans le fichier hello_world_gen.xml) :
01: <?xml version = «1.0»?> 02: <extension name = «hello_world_gen»> 03: <summary>Ma premiere extension</summary> 04: <logo src=’lm_logo_150.png’ mimetype=’image/png’/> 05: 06: <maintainers> 07: <maintainer> 08: <user>tristan</user> 09: <name>Tristan Colombo</name> 10: <email>tristan.colombo@laposte.net</email> 11: <role>lead</role> 12: </maintainer> 13: </maintainers> 14: 15: <release> 16: <version>0.1</version> 17: <date>21-08-2007</date> 18: <state>alpha</state> 19: <license>php</license> 20: <notes> 21: - Extension experimenatale 22: </notes> 23: </release> 24: </extension>
Prenez garde à modifier la fin de la ligne 2 : la balise <extension> qui était fermée en fin de ligne (<extension ... />) est maintenant fermée en ligne 24. Vous pourrez noter également qu’en ligne 4 nous pouvons associer un logo à notre extension. Nous avons choisi ici le logo de GNU/Linux Magazine récupéré sur http://www.gnulinuxmag.com/static/download/lm_logo_150.png, et nous l’avons placé dans le même répertoire que notre fichier hello_world_gen.xml. En ligne 11, les différents rôles autorisés sont : lead, contributor et helper. Ici encore, reportez-vous à la section 2.3 pour les instructions de compilation de l’extension (et n’oubliez pas de redémarrer Apache !). Lancez votre script phpinfo.php pour voir les nouvelles informations (Voir Figure 3). Pour connaître l’ensemble des tags autorisés dans la déclaration de votre extension, vous pourrez vous référer au manuel de CodeGen_PECL [5].

Figure 3 : Aperçu du phpinfo
3.3 Une fonction dans notre fichier XML
Ajoutons maintenant une fonction à notre extension. Pour cela, nous allons modifier le code du fichier hello_world_gen.xml :
01: <?xml version = «1.0»?> 02: <extension name = «hello_world_gen»> 03: <summary>Ma premiere extension</summary> 04: <logo src=’lm_logo_150.png’ mimetype=’image/png’/> 05: 06: <maintainers> 07: <maintainer> 08: <user>tristan</user> 09: <name>Tristan Colombo</name> 10: <email>tristan.colombo@laposte.net</email> 11: <role>lead</role> 12: </maintainer> 13: </maintainers> 14: 15: <release> 16: <version>0.1</version> 17: <date>21-08-2007</date> 18: <state>alpha</state> 19: <license>php</license> 20: <notes> 21: - Extension experimentale 22: </notes> 23: </release> 25: 26: <function name=”hello_world_gen”> 27: <proto>void hello_world_gen(void)</proto> 28: <summary>Fonction experimentale</summary> 29: <description>Cette fonction affiche “Hello World !”</description> 30: <code> 31: <![CDATA[ 32: php_printf(“Hello World CodeGen_PECL !\n”); 33: ]]> 34: </code> 35: </function> 36: </extension>
Nous déclarons ici une fonction hello_world_gen (ligne 26) dont le prototype C est donné en ligne 27. Après des descriptions de fonction en lignes 27 et 28, le code de la fonction est donné en lignes 30 à 34. Comme vous avez pu le remarquer, il est beaucoup plus agréable d’écrire une extension avec l’aide de CodeGen_PECL ! Avant de terminer cet article, essayons quelques fonctions légèrement plus complexes.
3.4 Fonctions avancées
3.4.1 Renvoyer une variable
Pour créer des fonctions un peu plus complexes (renvoyant des valeurs), nous allons devoir utiliser des fonctions prédéfinies :

Pour renvoyer des variables spéciales (telles qu’un pointeur de fichier), vous pourrez voir la variable spéciale return_res [5]. De plus, pour une variable de type chaîne de caractères, vous pourrez récupérer sa taille dans une variable spéciale dont le nom est le nom de la chaîne suivi de « _len » (par exemple pour la variable maChaine, la taille est donnée par maChaine_len).
Pour renvoyer des tableaux, là encore, des fonctions sont prédéfinies. Elles utilisent la variable spéciale return_value qui sera automatiquement initialisée.

3.4.2 Constantes et variables globales
Vous pouvez également définir les constantes et les variables globales directement dans votre fichier XML.
Pour créer des constantes que vous auriez pu définir dans le fichier d’en-têtes par un
#define PI 3.14
vous pouvez utiliser la syntaxe suivante dans votre fichier XML :
<constant name = «PI» type = «float» value = «3.14» define = «yes»/>
Si vous omettez l’attribut define, la constante ne sera accessible qu’en PHP et pas en C. Dans une forme plus évoluée, vous pouvez utiliser ce tag en y ajoutant des informations sur la constante dans le champ de données... En effet, CodeGen_PECL génère également une documentation DocBook et ces données pourront être directement incorporées à la documentation !
<constant name = «PI» type = «float» value = «3.14»>Constante de calcul sur les cercles / disques / spheres</constant>
Nous vous l’avions caché jusqu’à maintenant, mais cette documentation se trouve dans le répertoire manual/ se trouvant dans le répertorie généré pour votre extension (dans le cas de notre exemple /usr/include/php5/ext/hello_world_gen/manual/).
Pour déclarer une variable globale à l’extension, la syntaxe XML se rapproche grandement de celle des constantes :
<global name = «var_globale» type = «int» value = «12»>
Pour accéder aux variables globales dans le code en C, vous devrez utiliser la macro EXTNAME_G(). Attention, EXTNAME est à remplacer par le nom donné à votre extension. Dans notre cas, pour utiliser la variable définie précédemment, il faudra appeler HELLO_WORLD_GEN_G(var_globale).
3.4.3 Bibliothèques C spéciales
Si vous utilisez dans vos fichiers C des bibliothèques spécifiques (la bibliothèque math par exemple) ou des fichiers d’en-têtes externes, vous devrez déclarer ces dépendances. Une dépendance a deux attributs :
- le langage de programmation utilisé (
CouC++) ; - la plate-forme sur laquelle l’extension doit être supportée (
unix,win32ouall).
Une fois la dépendance définie, vous devrez indiquer les fichiers d’en-têtes et les bibliothèques utilisées. Une bibliothèque est ici définie par son nom et une fonction qu’elle contient (pour que le script de configuration puisse la tester). Voici un exemple d’utilisation de la bibliothèque mathématique :
<deps lang=»c» platform = «unix»> <header name=»math.h» /> <lib name=»m» function = «floor» /> </deps>
Si votre extension requiert des instructions de compilation spécifiques que CodeGen_PECL ne peut générer, c’est dans ce tag <deps> que vous devrez l’indiquer en utilisant le tag <makefile> (voir [5] pour plus d’informations).
3.5 Cerise sur le gâteau : les tests
Vous pouvez incorporer des tests à vos fonctions directement dans le fichier XML. Il s’agit d’un code PHP et du résultat obtenu. Voici un exemple de test pour la fonction hello_world_gen() :
01: <function name=»hello_world_gen»> 02: <proto>void hello_world_gen(void)</proto> 03: <summary>Fonction experimentale</summary> 04: <description>Cette fonction affiche “Hello World !”</description> 05: <code> 06: <![CDATA[ 07: php_printf(«Hello World !»); 08: ]]> 09: </code> 10: <test> 11: <code> 12: hello_world_gen(); 13: </code> 14: <result mode = «format»> 15: Hello World ! 16: </result> 17: </test> 18: </function>
Pour lancer les tests sur votre extension, rendez-vous dans son répertoire (/usr/include/php5/ext/hello_world_gen/ par exemple) et lancez la commande make test. Vous obtiendrez la sortie suivante :
Build complete.
(It is safe to ignore warnings about tempnam and tmpnam).
=====================================================================
CWD : /usr/include/php5/ext/hello_world_gen
PHP : /usr/bin/php
PHP_SAPI : cli
PHP_VERSION : 5.2.1
ZEND_VERSION: 2.2.0
PHP_OS : Linux - Linux tcolombo 2.6.20-16-386 #2 Sun Sep 23
19:47:10 UTC 2007 i686
INI actual : /etc/php5/cli/php.ini
More .INIs : /etc/php5/cli/conf.d/curl.ini,/etc/php5/cli/conf.d/gd.ini,
/etc/php5/cli/conf.d/ldap.ini,/etc/php5/cli/conf.d/mysql.ini,
/etc/php5/cli/conf.d/mysqli.ini,/etc/php5/cli/conf.d/pdo.ini,
/etc/php5/cli/conf.d/pdo_mysql.ini,/etc/php5/cli/conf.d/xsl.ini
Extra dirs :
=====================================================================
Running selected tests.
PASS hello_world_gen() function [tests/hello_world_gen.phpt]
=====================================================================
Number of tests : 1 1
Tests skipped : 0 ( 0.0%) --------
Tests warned : 0 ( 0.0%) ( 0.0%)
Tests failed : 0 ( 0.0%) ( 0.0%)
Tests passed : 1 (100.0%) (100.0%)
---------------------------------------------------------------------
Time taken : 0 seconds
=====================================================================
Ce mécanisme vous permettra de contrôler qu’il n’y a pas de régression de vos extensions en cas de modification.
3.6 Un exemple plus complexe
Voici maintenant un exemple plus complet qui nous permet de tester à peu près toutes les notions abordées dans cet article. Nous testerons ici une structure un peu particulière : le tableau.
01: <?xml version = «1.0»?>
02: <extension name = «fact»>
03: <summary>Tests sur les tableaux</summary>
04:
05: <maintainers>
06: <maintainer>
07: <user>tristan</user>
08: <name>Tristan Colombo</name>
09: <email>tristan.colombo@laposte.net</email>
10: <role>lead</role>
11: </maintainer>
12: </maintainers>
13: <release>
14: <version>0.1</version>
15: <date>25-09-2007</date>
16: <state>alpha</state>
17: <license>php</license>
18: <notes>
19: - Extension de test sur le traitement des tableaux
20: </notes>
21: </release>
22:
23: <constant name=»PI» type=»float» value=»3.14» define=»yes»/>
24:
25: <function name=»cube»>
26: <proto>array cube(array tab);</proto>
27: <code>
28: <![CDATA[
29: int size;
30: zval **data;
31: HashTable *arr_hash;
32: HashPosition pointer;
33:
34: arr_hash = Z_ARRVAL_P(tab);
35: size = zend_hash_num_elements(arr_hash);
36:
37: php_printf(«Le tableau passé en argument contient %d elements<br />», 38: size);
39:
40: for (zend_hash_internal_pointer_reset_ex(arr_hash, &pointer);
41: zend_hash_get_current_data_ex(arr_hash, (void**) &data, &pointer) ==
42: SUCCESS;
43: zend_hash_move_forward_ex(arr_hash, &pointer))
44: {
45: zval temp;
46: char *key;
47: int key_len;
48: long index, cubeTmp;
49:
50: if (zend_hash_get_current_key_ex(arr_hash, &key, &key_len, &index, 0,
51: &pointer) == HASH_KEY_IS_STRING)
52: {
53: php_printf(«%s», key);
54: }
55: else
56: {
57: php_printf(«%ld», index);
58: }
59:
60: php_printf(« => «);
61:
62: temp = **data;
63: zval_copy_ctor(&temp);
64: convert_to_long(&temp);
65: cubeTmp = Z_LVAL(temp)*Z_LVAL(temp)*Z_LVAL(temp);
66: php_printf(«%ld^3 = %ld <br />», Z_LVAL(temp), cubeTmp);
67:
68: add_next_index_long(return_value, cubeTmp);
69:
70: zval_dtor(&temp);
71: }
72:
73: ]]>
74: </code>
75: </function>
76:
77: </extension>
Comme vous pouvez le voir dans cet exemple, nous utilisons une table de hachage en paramètre de la fonction... Cela mérite quelques explications :
- boucle
foreachdes lignes 40 à 43 :- ligne 40 : place le pointeur de parcourt du tableau au début du tableau ;
- lignes 41-42 : récupère les valeurs ;
- ligne 43 : incrémente le pointeur de parcours du tableau.
- copie « propre » de la zval data en ligne 63 ;
- conversion en long en ligne 64 (
Z_LVALeffectue le même travail) ; - enfin, ajout au tableau en ligne 68.
Voici le fichier PHP qui permettra de tester cette extension (le résultat est présenté en figure 4).
01: <!DOCTYPE HTML PUBLIC «-//W3C//DTD HTML 4.01//EN» 02: «http://www.w3.org/TR/html4/strict.dtd»> 03: <html> 04: <head> 05: <title>Test</title> 06: </head> 07: <body> 08: <div id= «content»> 09: <?php 10: echo ‘TEST de l\’extension<br /><br />’; 11: 12: echo ‘Valeur de la constante PI : ‘ . PI; 13: echo ‘<br /><br />’; 14: 15: $val = array(“un”=>1, “deux”=>2, “trois”=>3, 4=>5, 7=>10); 16: $result = cube($val); 17: 18: echo ‘<br />Valeur de retour :<br />’; 19: print_r($result); 20: ?> 21: </div> 22: </body> 23: </html>

Figure 4 : Résultat de notre extension de test traitant les tableaux.
Conclusion
Les extensions vous permettent ainsi de créer des bibliothèques en C qui étendront les fonctionnalités de PHP. Vous sacrifierez bien sûr le confort d’écriture et de lecture propre à PHP, mais vous optimiserez grandement le temps d’exécution.
J’espère que cet article vous aura fait découvrir les extensions de PHP et vous aura donné envie d’en écrire ! La documentation sur ce domaine est très peu fournie que ce soit en termes d’ouvrages ou d’articles sur internet. Toutefois, le livre de Sara Golemon [2] est un incontournable du domaine que je vous recommande d’acquérir si le sujet vous intéresse. Le livre de Blake Schwendiman [6], bien que plus ancien, pourra également vous rendre service.
Et surtout, si vous écrivez des extensions qui pourraient être intéressantes... pensez à la communauté et à PECL !
Références :
- [1] http://pecl.php.net/
- [2] GOLEMON (S.), Extending and Embedding PHP, Sams Publishing, 2006.
- [3] http://pear.php.net/package/CodeGen_PECL/
- [4] http://www.php.net/manual/fr/zend.build.php
- [5] http://php-baustelle.de/CodeGen_PECL/manual.html
- [6] SCHWENDIMAN (B.), Building Custom PHP Extensions, Lulu Press, 2003.


