0
Premiers pas dans les   extensions PHP   Pierrick Charron, Confoo, Mars 2011            pierrick@php.net
Qui suis-je ?●   Consultant TI à Montréal●   Auteur de lextension PHP Stomp●   Contributeur PHP depuis 2009      ●   Core ...
Une extension ?Premiers pas dans les extensions - Pierrick Charron    3
Pourquoi créer une extension ?●   Permettre lutilisation dune librairie externe      ●   Exemple : mysql, curl●   Améliore...
Avant de commencer●   Présentation basée sur PHP >= 5.3●   Utilisation de Linux #include <stdio.h>                        ...
Prérequis●   Familier avec PHP      ●   Configuration de PHP      ●   Installation de modules●   Connaissances en C●   Pat...
Architecture de PHP                                           API Serveur (SAPI)                Apache             FPM    ...
Cycle de vie dune extension●   Différentes étapes      ●   MINIT : Initialisation du module      ●   RINIT : Initialisatio...
Cycle de vie : CLI$ php monscript.php                                                  MINIT                              ...
Cycle de vie : Multiprocess                     MINIT                                 MINIT                       RINIT   ...
Cycle de vie : Multithreaded                                                      MINIT                       RINIT       ...
Zend Thread Safety / TSRM●   Utilisé avec des "threaded webservers"●   Chaque thread a son propre stockage local      ●   ...
Les macros ZTS #define TSRMLS_D #define TSRMLS_D                            void ***tsrmls                                ...
Zend ValuePremiers pas dans les extensions - Pierrick Charron    14
ZVAL●   Zval : valeur dans espace utilisateur      ●   Attention valeur != variable●   Conversion de type●   Compteur de r...
ZVALtypedef struct _zval_struct {typedef struct _zval_struct {   zvalue_value value;   zvalue_value value;   zend_uint ref...
ZVAL                                                      Nombre de variables quitypedef struct _zval_struct {typedef stru...
ZVAL                                                           Nombre de variables quitypedef struct _zval_struct {typedef...
ZVAL                                                           Nombre de variables quitypedef struct _zval_struct {typedef...
ZVAL                                                           Nombre de variables quitypedef struct _zval_struct {typedef...
ZVAL                                                           Nombre de variables quitypedef struct _zval_struct {typedef...
ZVAL : Récuperer le type #define Z_TYPE(zval) #define Z_TYPE(zval)      (zval).type                              (zval).ty...
ZVAL : Récuperer une valeur #define Z_LVAL(zval) #define Z_LVAL(zval)                                 (zval).value.lval   ...
ZVAL : Assigner une valeur ZVAL_NULL(zval); ZVAL_NULL(zval);                            Z_TYPE_P(zval) = IS_NULL;         ...
Conversion void convert_to_string(zval *); void convert_to_string(zval *); void convert_to_long(zval *); void convert_to_l...
Gestion de la mémoire●   Zend dispose dun memory manager      ●   évite les fuites de mémoire      ●   signature des fonct...
Les fonctions dallocation          Fonction C traditionnelle                            Fonction spécifique à PHPvoid *mal...
Et les extensions alors ?Premiers pas dans les extensions - Pierrick Charron     28
./ext_skel ●   Outil de génération de code ●   Génére le squelette de lextension$ ./ext_skel --extname=monextension$ ./ext...
Les fichiers de monextension$ tree monextension$ tree monextension                                                      ● ...
Config.m4 ●   Script de configuration sous Linux      ●   Utilisé par ./buildconf et phpizednl If your extension reference...
Compiler monextension●   Dynamique$ phpize$ phpize$ ./configure$ ./configure$ make$ make$ make test$ make test●   Statique...
PHPT       Avant même de commencer à programmer,              pensez à écrire vos tests !!!!                     http://qa...
php_monextension.h●   Déclaration des données pour la liaison    statiquePremiers pas dans les extensions - Pierrick Charr...
monextension.c●   #includes●   Structures statiques●   Fonctions PHP●   MINFO●   MINIT, MSHUTDOWN, RINIT, RSHUTDOWN●   Tab...
Définition du module●   Structure permettant à PHP dinitialiser ou de    désinitialiser le modulezend_module_entry monexte...
Liste des fonctionsconst zend_function_entry monextension_functions[] = {{const zend_function_entry monextension_functions...
Première fonctionmonextension.cconst zend_function_entry monextension_functions[] = {{const zend_function_entry monextensi...
PHP_FUNCTIONPHP_FUNCTION(monextension_helloworld) PHP_FUNCTION(monextension_helloworld){{   php_printf("Hello world !!!");...
Valeur de retour●   Modifier la variable return_value (zval *)●   Par défaut Z_TYPE_P(return_value) = IS_NULL●   Attention...
RETVAL_*                   ZVAL Macro                                         RETVAL_*ZVAL_NULL(return_value);            ...
RETURN_*●   RETVAL_* ninterrompt pas lexécution du code●   RETURN_* = RETVAL_*; return;PHP_FUNCTION(monextension_helloworl...
Paramètres de fonctionPHP_FUNCTION(monextension_helloworld) PHP_FUNCTION(monextension_helloworld){{    char *name;     cha...
Paramètres de fonctionint zend_parse_parameters (int num_args TSRMLS_DC, char *type_spec, ...) int zend_parse_parameters (...
Paramètres optionnels●   Utilisation du modificateur "|"PHP_FUNCTION(monextension_helloworld) PHP_FUNCTION(monextension_he...
Les tableaux (HashTable *)●   Stockage clef valeur●   Très rapide      ●   Combinaison de tableau C et de listes chaînées●...
Initialiser un tableauint array_init(zval *z); /* $array = array(); */ int array_init(zval *z); /* $array = array(); */PHP...
Ajout délémentsTableau numérique                   Syntaxe PHP                                          Syntaxe C$arr[1] =...
Ajout délémentsTableau associatif        Syntaxe PHP                                            Syntaxe C$arr["foo"] = nul...
Recherche délémentsint zend_hash_find(const HashTable *ht, int zend_hash_find(const HashTable *ht,      const char *arKey,...
Suppression délémentsint zend_hash_del(HashTable *ht, char *arKey, uint nKeyLen); int zend_hash_del(HashTable *ht, char *a...
Création dune classezend_class_entry *counter_ce; zend_class_entry *counter_ce;PHP_MINIT_FUNCTION(monextension) PHP_MINIT_...
Les méthodesPHP_METHOD(Counter, getValue) PHP_METHOD(Counter, getValue){{   zval *object = getThis();   zval *object = get...
Quelques outils bien utiles ;)Premiers pas dans les extensions - Pierrick Charron   54
Code compatible ZTS ?                 Compilez toujours votre PHP avec                     --enable-maintainer-ztsPremiers...
Fuites de mémoire ?                                         --with-debug$ php -e $ php -e<?php leak(); <?php leak();[Tue F...
Fuites de mémoire ?                                              valgrind$ USE_ZEND_ALLOC=0 valgrind --tool=memcheck --lea...
Recherche de code ?                                                  grep                                     http://lxr.p...
Premiers pas dans les extensions - Pierrick Charron   59
Premiers pas dans les extensions - Pierrick Charron   60
Segfault ?                             GDB (gnome debugger)$ gdb --args php -d extension=monextension.so segfault.php $ gd...
Besoin daide ?                             Irc.EFNet.org #php.pecl                                Mailing Lists           ...
Envie de lecture ?     http://www.php.net/manual/en/internals2.php                      Advanced PHP Programming          ...
Questions ?                                        pierrick@php.net                                        Twitter: @adoyy...
Upcoming SlideShare
Loading in...5
×

Premiers pas dans les extensions PHP, Pierrick Charron, Confoo 2011

1,546

Published on

1 Comment
0 Likes
Statistics
Notes
  • Be the first to like this

No Downloads
Views
Total Views
1,546
On Slideshare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
Downloads
22
Comments
1
Likes
0
Embeds 0
No embeds

No notes for slide

Transcript of "Premiers pas dans les extensions PHP, Pierrick Charron, Confoo 2011"

  1. 1. Premiers pas dans les extensions PHP Pierrick Charron, Confoo, Mars 2011 pierrick@php.net
  2. 2. Qui suis-je ?● Consultant TI à Montréal● Auteur de lextension PHP Stomp● Contributeur PHP depuis 2009 ● Core ● RFC (Request For Comment) ● Documentation (Fr & En)Premiers pas dans les extensions - Pierrick Charron 2
  3. 3. Une extension ?Premiers pas dans les extensions - Pierrick Charron 3
  4. 4. Pourquoi créer une extension ?● Permettre lutilisation dune librairie externe ● Exemple : mysql, curl● Améliorer les performances● Opération impossible dans lespace utilisateur ● Exemple : Xdebug, operator, vld● Satisfaire sa curiositéPremiers pas dans les extensions - Pierrick Charron 4
  5. 5. Avant de commencer● Présentation basée sur PHP >= 5.3● Utilisation de Linux #include <stdio.h> $ echo "terminal linux" void main() { terminal linux printf("C Code"); }Premiers pas dans les extensions - Pierrick Charron 5
  6. 6. Prérequis● Familier avec PHP ● Configuration de PHP ● Installation de modules● Connaissances en C● Patience ● API très complet ● Beaucoup, beaucoup, beaucoup... de macrosPremiers pas dans les extensions - Pierrick Charron 6
  7. 7. Architecture de PHP API Serveur (SAPI) Apache FPM CLI Embed ... Zend Engine PHP Core API pour les extensions standard mysqli curl date ...Premiers pas dans les extensions - Pierrick Charron 7
  8. 8. Cycle de vie dune extension● Différentes étapes ● MINIT : Initialisation du module ● RINIT : Initialisation de la requête ● RSHUTDOWN : Arrêt de la requête ● MSHUTDOWN : Arrêt du module● Moment et nombre dappels dépend du SAPIPremiers pas dans les extensions - Pierrick Charron 8
  9. 9. Cycle de vie : CLI$ php monscript.php MINIT RINIT Execution du script RSHUTDOWN MSHUTDOWNPremiers pas dans les extensions - Pierrick Charron 9
  10. 10. Cycle de vie : Multiprocess MINIT MINIT RINIT RINIT Execution du Script Execution du Script RSHUTDOWN RSHUTDOWN RINIT RINIT Execution du Script Execution du Script RSHUTDOWN RSHUTDOWN MSHUTDOWN MSHUTDOWNPremiers pas dans les extensions - Pierrick Charron 10
  11. 11. Cycle de vie : Multithreaded MINIT RINIT RINIT Execution du Script Execution du Script RSHUTDOWN RSHUTDOWN RINIT RINIT Execution du Script Execution du Script RSHUTDOWN RSHUTDOWN MSHUTDOWNPremiers pas dans les extensions - Pierrick Charron 11
  12. 12. Zend Thread Safety / TSRM● Utilisé avec des "threaded webservers"● Chaque thread a son propre stockage local ● Evite les accès concurrentsPremiers pas dans les extensions - Pierrick Charron 12
  13. 13. Les macros ZTS #define TSRMLS_D #define TSRMLS_D void ***tsrmls void ***tsrmls #define TSRMLS_DC #define TSRMLS_DC ,, TSRMLS_D TSRMLS_D #define TSRMLS_C #define TSRMLS_C tsrmls tsrmls #define TSRMLS_CC #define TSRMLS_CC ,, TSRMLS_C TSRMLS_C static void ma_fonction(int ii TSRMLS_DC); static void ma_fonction(int TSRMLS_DC); ma_function(10 TSRMLS_CC); ma_function(10 TSRMLS_CC); static void ma_fonction(int i); static void ma_fonction(int i); static void ma_fonction(int i, void ***tsrmls); static void ma_fonction(int i, void ***tsrmls); ma_function(10); ma_function(10); ma_function(10, tsrmls); ma_function(10, tsrmls);Premiers pas dans les extensions - Pierrick Charron 13
  14. 14. Zend ValuePremiers pas dans les extensions - Pierrick Charron 14
  15. 15. ZVAL● Zval : valeur dans espace utilisateur ● Attention valeur != variable● Conversion de type● Compteur de référencePremiers pas dans les extensions - Pierrick Charron 15
  16. 16. ZVALtypedef struct _zval_struct {typedef struct _zval_struct { zvalue_value value; zvalue_value value; zend_uint refcount__gc; zend_uint refcount__gc; zend_uchar type; zend_uchar type; typedef union _zvalue_value { typedef union _zvalue_value { zend_uchar is_ref__gc; zend_uchar is_ref__gc; long lval; long lval;} zval;} zval; double dval; double dval; struct { struct { char *val; char *val; IS_NULL IS_NULL int len; int len; IS_LONG IS_LONG } str; } str; IS_DOUBLE IS_DOUBLE HashTable *ht; HashTable *ht; IS_BOOL IS_BOOL zend_object_value *obj; zend_object_value *obj; IS_ARRAY IS_ARRAY } zvalue_value; } zvalue_value; IS_OBJECT IS_OBJECT IS_STRING IS_STRING IS_RESOURCE IS_RESOURCEPremiers pas dans les extensions - Pierrick Charron 16
  17. 17. ZVAL Nombre de variables quitypedef struct _zval_struct {typedef struct _zval_struct { pointent vers cette valeur zvalue_value value; zvalue_value value; zend_uint refcount__gc; zend_uint refcount__gc; zend_uchar type; zend_uchar type; zend_uchar is_ref__gc; zend_uchar is_ref__gc; Définit si oui ou non une valeur est une référence} zval;} zval;Premiers pas dans les extensions - Pierrick Charron 17
  18. 18. ZVAL Nombre de variables quitypedef struct _zval_struct {typedef struct _zval_struct { pointent vers cette valeur zvalue_value value; zvalue_value value; zend_uint refcount__gc; zend_uint refcount__gc; zend_uchar type; zend_uchar type; zend_uchar is_ref__gc; zend_uchar is_ref__gc; Définit si oui ou non une valeur est une référence} zval;} zval; $a $b $a = 10; $a = 10; value.lval = 10 value.lval = 10 $b = $a; $b = $a; refcount = 2 refcount = 2 $b = 20; $b = 20; type = IS_LONG type = IS_LONG is_ref = 0 is_ref = 0Premiers pas dans les extensions - Pierrick Charron 18
  19. 19. ZVAL Nombre de variables quitypedef struct _zval_struct {typedef struct _zval_struct { pointent vers cette valeur zvalue_value value; zvalue_value value; zend_uint refcount__gc; zend_uint refcount__gc; zend_uchar type; zend_uchar type; zend_uchar is_ref__gc; zend_uchar is_ref__gc; Définit si oui ou non une valeur est une référence} zval;} zval; $a $b $a = 10; $a = 10; value.lval = 10 value.lval = 10 value.lval = 20 value.lval = 20 $b = $a; $b = $a; refcount = 2 refcount = 11 2 refcount = 1 refcount = 1 $b = 20; $b = 20; type = IS_LONG type = IS_LONG type = IS_LONG type = IS_LONG is_ref = 0 is_ref = 0 is_ref = 0 is_ref = 0Premiers pas dans les extensions - Pierrick Charron 19
  20. 20. ZVAL Nombre de variables quitypedef struct _zval_struct {typedef struct _zval_struct { pointent vers cette valeur zvalue_value value; zvalue_value value; zend_uint refcount__gc; zend_uint refcount__gc; zend_uchar type; zend_uchar type; zend_uchar is_ref__gc; zend_uchar is_ref__gc; Définit si oui ou non une valeur est une référence} zval;} zval; $a $b $a = 10; $a = 10; value.lval = 10 value.lval = 10 $b = &$a; $b = &$a; refcount = 2 refcount = 2 $b = 20; $b = 20; type = IS_LONG type = IS_LONG is_ref = 0 is_ref = 1 1 0Premiers pas dans les extensions - Pierrick Charron 20
  21. 21. ZVAL Nombre de variables quitypedef struct _zval_struct {typedef struct _zval_struct { pointent vers cette valeur zvalue_value value; zvalue_value value; zend_uint refcount__gc; zend_uint refcount__gc; zend_uchar type; zend_uchar type; zend_uchar is_ref__gc; zend_uchar is_ref__gc; Définit si oui ou non une valeur est une référence} zval;} zval; $a $b $a = 10; $a = 10; value.lval = 10 value.lval = 20 20 10 $b = &$a; $b = &$a; refcount = 2 refcount = 2 $b = 20; $b = 20; type = IS_LONG type = IS_LONG is_ref = 0 is_ref = 1 1 0Premiers pas dans les extensions - Pierrick Charron 21
  22. 22. ZVAL : Récuperer le type #define Z_TYPE(zval) #define Z_TYPE(zval) (zval).type (zval).type (zval).type (zval).type #define Z_TYPE(zval_p) #define Z_TYPE_P(zval_p) Z_TYPE(*zval_p) Z_TYPE(*zval_p) Z_TYPE_P(zval_p) Z_TYPE(*zval_p) Z_TYPE(zval_p) Z_TYPE(*zval_p) #define Z_TYPE(zval_pp) #define Z_TYPE_PP(zval_pp)Z_TYPE(**zval_pp) Z_TYPE(**zval_pp) Z_TYPE_PP(zval_pp)Z_TYPE(**zval_pp) Z_TYPE(zval_pp) Z_TYPE(**zval_pp) zval foo; zval foo; Z_TYPE(foo) == IS_LONG Z_TYPE(foo) == IS_LONG zval *bar; zval *bar; Z_TYPE_P(bar) == IS_BOOL Z_TYPE_P(bar) == IS_BOOLPremiers pas dans les extensions - Pierrick Charron 22
  23. 23. ZVAL : Récuperer une valeur #define Z_LVAL(zval) #define Z_LVAL(zval) (zval).value.lval (zval).value.lval #define Z_BVAL(zval) #define Z_BVAL(zval) ((zend_bool)(zval).value.lval) ((zend_bool)(zval).value.lval) #define Z_DVAL(zval) #define Z_DVAL(zval) (zval).value.dval (zval).value.dval #define Z_STRVAL(zval) #define Z_STRVAL(zval) (zval).value.str.val (zval).value.str.val #define Z_STRLEN(zval) #define Z_STRLEN(zval) (zval).value.str.len (zval).value.str.len #define Z_ARRVAL(zval) #define Z_ARRVAL(zval) (zval).value.ht (zval).value.ht #define Z_OBJVAL(zval) #define Z_OBJVAL(zval) (zval).value.obj (zval).value.obj #define Z_*_P(zval_p) #define Z_*_P(zval_p) (*zval). (*zval). #define Z_*_PP(zval_pp) #define Z_*_PP(zval_pp) (**zval). (**zval).Premiers pas dans les extensions - Pierrick Charron 23
  24. 24. ZVAL : Assigner une valeur ZVAL_NULL(zval); ZVAL_NULL(zval); Z_TYPE_P(zval) = IS_NULL; Z_TYPE_P(zval) = IS_NULL; ZVAL_LONG(zval,l); ZVAL_LONG(zval,l); Z_TYPE_P(zval) = IS_LONG; Z_TYPE_P(zval) = IS_LONG; Z_LVAL_P(zval) = l; Z_LVAL_P(zval) = l; ZVAL_DOUBLE(zval,d); ZVAL_DOUBLE(zval,d); Z_TYPE_P(zval) = IS_DOUBLE; Z_TYPE_P(zval) = IS_DOUBLE; Z_DVAL_P(zval) = d; Z_DVAL_P(zval) = d; ZVAL_STRINGL(zval,str,len,dup) Z_TYPE_P(zval) = IS_STRING; ZVAL_STRINGL(zval,str,len,dup) Z_TYPE_P(zval) = IS_STRING; Z_STRLEN_P(zval) = len; Z_STRLEN_P(zval) = len; if (dup) {{ if (dup) Z_STRVAL_P(zval) = estrndup(str, len+1); Z_STRVAL_P(zval) = estrndup(str, len+1); }} else {{ else Z_STRVAL_P(zval) = str; Z_STRVAL_P(zval) = str; }} ZVAL_BOOL(zval, b) ZVAL_BOOL(zval, b) Z_TYPE_P(zval) = IS_BOOLEAN; Z_TYPE_P(zval) = IS_BOOLEAN; Z_BVAL_P(zval) = b ? 1 :: 0; Z_BVAL_P(zval) = b ? 1 0;Premiers pas dans les extensions - Pierrick Charron 24
  25. 25. Conversion void convert_to_string(zval *); void convert_to_string(zval *); void convert_to_long(zval *); void convert_to_long(zval *); void convert_to_double(zval *); void convert_to_double(zval *); void convert_to_null(zval *); void convert_to_null(zval *); void convert_to_boolean(zval *); void convert_to_boolean(zval *); void convert_to_array(zval *); void convert_to_array(zval *); void convert_to_object(zval *); void convert_to_object(zval *);Premiers pas dans les extensions - Pierrick Charron 25
  26. 26. Gestion de la mémoire● Zend dispose dun memory manager ● évite les fuites de mémoire ● signature des fonctions similaires aux fonctions natives CPremiers pas dans les extensions - Pierrick Charron 26
  27. 27. Les fonctions dallocation Fonction C traditionnelle Fonction spécifique à PHPvoid *malloc(size_t count); void *emalloc(size_t count);void *calloc(size_t nmemb, size_t size); void *ecalloc(size_t nmemb, size_t size);void *realloc(void *ptr, size_t size); void *erealloc(void *ptr, size_t size);char *strdup(const char *s); char *estrdup(const char *s);char *strndup(const char *s, size_t n); char *estrndup(const char *s, size_t n);void free(void *ptr); void efree(void *ptr); Premiers pas dans les extensions - Pierrick Charron 27
  28. 28. Et les extensions alors ?Premiers pas dans les extensions - Pierrick Charron 28
  29. 29. ./ext_skel ● Outil de génération de code ● Génére le squelette de lextension$ ./ext_skel --extname=monextension$ ./ext_skel --extname=monextensionPremiers pas dans les extensions - Pierrick Charron 29
  30. 30. Les fichiers de monextension$ tree monextension$ tree monextension ● Fichiers de configurationmonextension/ monextension/ ● Config.m4|-- config.m4 |-- config.m4 ● Config.w32|-- config.w32 |-- config.w32|-- CREDITS |-- CREDITS|-- EXPERIMENTAL |-- EXPERIMENTAL ● Fichiers de code|-- monextension.c |-- monextension.c|-- monextension.php |-- monextension.php ● monextension.c|-- php_monextension.h |-- php_monextension.h ● php_monextension.h`-- tests `-- tests `-- 001.phpt `-- 001.phpt1 directory, 8 files1 directory, 8 filesPremiers pas dans les extensions - Pierrick Charron 30
  31. 31. Config.m4 ● Script de configuration sous Linux ● Utilisé par ./buildconf et phpizednl If your extension references something external, use with:dnl If your extension references something external, use with:dnl PHP_ARG_WITH(monextension, for monextension support,dnl PHP_ARG_WITH(monextension, for monextension support,dnl Make sure that the comment is aligned:dnl Make sure that the comment is aligned:dnl [[ --with-monextensiondnl --with-monextension Include monextension support]) Include monextension support])dnl Otherwise use enable:dnl Otherwise use enable:PHP_ARG_ENABLE(monextension, whether to enable monextension support,dnl PHP_ARG_ENABLE(monextension, whether to enable monext support, dnl PHP_ARG_ENABLE(monextension, whether to enable monext support,Make suresure that comment is aligned: dnl Make that the the comment is aligned:dnl Make sure that the comment is aligned:[dnl [[ --enable-monextension Enable monextension support]) --enable-monextensiondnl --enable-monextension Enable monextension support]) Enable monextension support])Premiers pas dans les extensions - Pierrick Charron 31
  32. 32. Compiler monextension● Dynamique$ phpize$ phpize$ ./configure$ ./configure$ make$ make$ make test$ make test● Statique$ ./buildconf --force$ ./buildconf --force$ ./configure --enable-monextension$ ./configure --enable-monextension$ make$ make$ make test$ make testPremiers pas dans les extensions - Pierrick Charron 32
  33. 33. PHPT Avant même de commencer à programmer, pensez à écrire vos tests !!!! http://qa.php.net/write-test.phpPremiers pas dans les extensions - Pierrick Charron 33
  34. 34. php_monextension.h● Déclaration des données pour la liaison statiquePremiers pas dans les extensions - Pierrick Charron 34
  35. 35. monextension.c● #includes● Structures statiques● Fonctions PHP● MINFO● MINIT, MSHUTDOWN, RINIT, RSHUTDOWN● Table des fonctions● Définition du modulePremiers pas dans les extensions - Pierrick Charron 35
  36. 36. Définition du module● Structure permettant à PHP dinitialiser ou de désinitialiser le modulezend_module_entry monextension_module_entry = {{zend_module_entry monextension_module_entry = STANDARD_MODULE_HEADER, STANDARD_MODULE_HEADER, "monextension", "monextension", monextension_functions, monextension_functions, PHP_MINIT(monextension), PHP_MINIT(monextension), PHP_MSHUTDOWN(monextension), PHP_MSHUTDOWN(monextension), PHP_RINIT(monextension), PHP_RINIT(monextension), PHP_RSHUTDOWN(monextension), PHP_RSHUTDOWN(monextension), PHP_MINFO(monextension), PHP_MINFO(monextension), "0.1", "0.1", STANDARD_MODULE_PROPERTIES STANDARD_MODULE_PROPERTIES};};Premiers pas dans les extensions - Pierrick Charron 36
  37. 37. Liste des fonctionsconst zend_function_entry monextension_functions[] = {{const zend_function_entry monextension_functions[] = PHP_FE(confirm_monextension_compiled, NULL) PHP_FE(confirm_monextension_compiled, NULL) {NULL, NULL, NULL} {NULL, NULL, NULL}};}; ● PHP_FE(nom, signature); ● PHP_FALIAS(nom, nom_original, signature);Premiers pas dans les extensions - Pierrick Charron 37
  38. 38. Première fonctionmonextension.cconst zend_function_entry monextension_functions[] = {{const zend_function_entry monextension_functions[] = PHP_FE(monextension_helloworld, NULL) PHP_FE(monextension_helloworld, NULL) {NULL, NULL, NULL} {NULL, NULL, NULL}};};/** … **/ /** … **/PHP_FUNCTION(monextension_helloworld) PHP_FUNCTION(monextension_helloworld){{ php_printf("Hello world !!!"); php_printf("Hello world !!!");}; };php_monextension.hPHP_FUNCTION(monextension_helloworld);PHP_FUNCTION(monextension_helloworld);Premiers pas dans les extensions - Pierrick Charron 38
  39. 39. PHP_FUNCTIONPHP_FUNCTION(monextension_helloworld) PHP_FUNCTION(monextension_helloworld){{ php_printf("Hello world !!!"); php_printf("Hello world !!!");}}void zif_monextension_helloworld(int ht, zval *return_value, zval void zif_monextension_helloworld(int ht, zval *return_value, zval**return_value_ptr, zval *this_ptr, int return_value_used TSRMLS_DC) **return_value_ptr, zval *this_ptr, int return_value_used TSRMLS_DC){{ php_printf("Hello world !!!"); php_printf("Hello world !!!");}}Premiers pas dans les extensions - Pierrick Charron 39
  40. 40. Valeur de retour● Modifier la variable return_value (zval *)● Par défaut Z_TYPE_P(return_value) = IS_NULL● Attention ne pas retourner la valeur !PHP_FUNCTION(monextension_helloworld) PHP_FUNCTION(monextension_helloworld){{ ZVAL_STRING(return_value, "Hello world !!!", 1); ZVAL_STRING(return_value, "Hello world !!!", 1); return; return;}; };Premiers pas dans les extensions - Pierrick Charron 40
  41. 41. RETVAL_* ZVAL Macro RETVAL_*ZVAL_NULL(return_value); RETVAL_NULL();ZVAL_BOOL(return_value, bval); RETVAL_BOOL(bval);ZVAL_TRUE(return_value); RETVAL_TRUE();ZVAL_FALSE(return_value); RETVAL_FALSE();ZVAL_LONG(return_value, lval); RETVAL_LONG(lval);ZVAL_DOUBLE(return_value, dval); RETVAL_DOUBLE(dval);ZVAL_STRING(return_value, str, dup); RETVAL_STRING(str, dup);ZVAL_STRINGL(return_value, str, len, dup); RETVAL_STRINGL(str, len, dup);ZVAL_RESOURCE(return_value, rval); RETVAL_RESOURCE(rval); PHP_FUNCTION(monextension_helloworld) PHP_FUNCTION(monextension_helloworld) {{ RETVAL_STRING("Hello world !!!", 1); RETVAL_STRING("Hello world !!!", 1); /* Code executé */ /* Code executé */ return; return; }; }; Premiers pas dans les extensions - Pierrick Charron 41
  42. 42. RETURN_*● RETVAL_* ninterrompt pas lexécution du code● RETURN_* = RETVAL_*; return;PHP_FUNCTION(monextension_helloworld) PHP_FUNCTION(monextension_helloworld){{ RETURN_STRING("Hello world !!!", 1); RETURN_STRING("Hello world !!!", 1); /* Code jamais executé */ /* Code jamais executé */}; };Premiers pas dans les extensions - Pierrick Charron 42
  43. 43. Paramètres de fonctionPHP_FUNCTION(monextension_helloworld) PHP_FUNCTION(monextension_helloworld){{ char *name; char *name; int name_len; int name_len; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE) {{ "s", &name, &name_len) == FAILURE) return; return; }} php_printf("Hello %s !", name); php_printf("Hello %s !", name);}; };Premiers pas dans les extensions - Pierrick Charron 43
  44. 44. Paramètres de fonctionint zend_parse_parameters (int num_args TSRMLS_DC, char *type_spec, ...) int zend_parse_parameters (int num_args TSRMLS_DC, char *type_spec, ...) Spécificateur du type Type côté PHP Type de donnée côté C b Boolean zend_bool * l Entier long * d Virgule floatante double * s Chaine de caractère char **, int * r Ressource zval ** a Tableau zval ** o Objet zval ** O Objet dun type spécifique zval **, zend_class_entry * z zval zval **Premiers pas dans les extensions - Pierrick Charron 44
  45. 45. Paramètres optionnels● Utilisation du modificateur "|"PHP_FUNCTION(monextension_helloworld) PHP_FUNCTION(monextension_helloworld){{ char *name = "world"; char *name = "world"; int name_len = sizeof("world")-1; int name_len = sizeof("world")-1; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &name, &name_len) == FAILURE) {{ "|s", &name, &name_len) == FAILURE) return; return; }} php_printf("Hello %s !", name); php_printf("Hello %s !", name);}; };Premiers pas dans les extensions - Pierrick Charron 45
  46. 46. Les tableaux (HashTable *)● Stockage clef valeur● Très rapide ● Combinaison de tableau C et de listes chaînées● Utilisés presque partout dans le corp PHP● Recherche par valeur impossiblePremiers pas dans les extensions - Pierrick Charron 46
  47. 47. Initialiser un tableauint array_init(zval *z); /* $array = array(); */ int array_init(zval *z); /* $array = array(); */PHP_FUNCTION(monextension_emptyarray) PHP_FUNCTION(monextension_emptyarray){{ array_init(return_value); array_init(return_value);}; };Premiers pas dans les extensions - Pierrick Charron 47
  48. 48. Ajout délémentsTableau numérique Syntaxe PHP Syntaxe C$arr[1] = null; add_index_null(arr, 1);$arr[2] = "foo"; add_index_string(arr, 2, "foo", 1);$arr[3] = true; add_index_bool(arr, 3, 1);$arr[4] = 10; add_index_long(arr, 4, 10);$arr[5] = 3.1416; add_index_double(arr, 5, 3.1416);$arr[6] = $foo; add_index_zval(arr, 6, foo);$arr[] = null; add_next_index_null(arr);$arr[] = "foo"; add_next_index_string(arr, "foo", 1);$arr[] = true; add_next_index_bool(arr, 1);$arr[] = 10; add_next_index_long(arr, 10);$arr[] = 3.1416; add_next_index_double(arr, 3.1416);$arr[] = $foo; add_next_index_zval(arr, foo); Premiers pas dans les extensions - Pierrick Charron 48
  49. 49. Ajout délémentsTableau associatif Syntaxe PHP Syntaxe C$arr["foo"] = null; add_assoc_null(arr, "foo"); add_assoc_null_ex(arr, "foo", sizeof("foo"));$arr["bar"] = "foo"; add_assoc_string(arr, "bar", "foo", 1); add_assoc_string_ex(arr, "bar", sizeof("bar"), "foo", 1);$arr["baz"] = true; add_assoc_bool(arr, "baz", 1); add_assoc_bool_ex(arr, "baz", sizeof("baz"), 1);$arr["boz"] = 10; add_assoc_long(arr, "boz", 10); add_assoc_long_ex(arr, "boz", sizeof("boz"), 10);$arr["biz"] = 3.1416; add_assoc_double(arr, "biz", 3.1416); add_assoc_double_ex(arr, "biz", sizeof("biz"), 3.1416);$arr["buz"] = $foo; add_assoc_zval(arr, "buz", foo); add_assoc_zval(arr, "buz", sizeof("buz"), foo);Premiers pas dans les extensions - Pierrick Charron 49
  50. 50. Recherche délémentsint zend_hash_find(const HashTable *ht, int zend_hash_find(const HashTable *ht, const char *arKey, uint nKeyLength, void **pData) const char *arKey, uint nKeyLength, void **pData)int zend_hash_quick_find(const HashTable *ht, int zend_hash_quick_find(const HashTable *ht, const char *arKey, uint nKeyLength, ulong h, void **pData) const char *arKey, uint nKeyLength, ulong h, void **pData)int zend_hash_index_find(const HashTable *ht, ulong h, void **pData) int zend_hash_index_find(const HashTable *ht, ulong h, void **pData)zval **data;zval **data;if (zend_symtable_find(Z_ARRVAL(zval), "clef", sizeof("clef"), (void**)&data) == if (zend_symtable_find(Z_ARRVAL(zval), "clef", sizeof("clef"), (void**)&data) ==SUCCESS) {{ SUCCESS) switch (Z_TYPE_PP(data)) {{ switch (Z_TYPE_PP(data)) /* ... */ /* ... */ }}}}Premiers pas dans les extensions - Pierrick Charron 50
  51. 51. Suppression délémentsint zend_hash_del(HashTable *ht, char *arKey, uint nKeyLen); int zend_hash_del(HashTable *ht, char *arKey, uint nKeyLen);int zend_hash_quick_del(HashTable *ht, char *arKey, uint nKeyLen, ulong h); int zend_hash_quick_del(HashTable *ht, char *arKey, uint nKeyLen, ulong h);int zend_hash_index_del(HashTable *ht, ulong h); int zend_hash_index_del(HashTable *ht, ulong h);Premiers pas dans les extensions - Pierrick Charron 51
  52. 52. Création dune classezend_class_entry *counter_ce; zend_class_entry *counter_ce;PHP_MINIT_FUNCTION(monextension) PHP_MINIT_FUNCTION(monextension){{ zend_class_entry ce; zend_class_entry ce; INIT_CLASS_ENTRY(ce, "Counter", monextension_counter_methods); INIT_CLASS_ENTRY(ce, "Counter", monextension_counter_methods); counter_ce = zend_register_internal_class(&ce TSRMLS_CC); counter_ce = zend_register_internal_class(&ce TSRMLS_CC); zend_declare_property_long(counter_ce, "value", sizeof("value")-1, 0, zend_declare_property_long(counter_ce, "value", sizeof("value")-1, 0, ZEND_ACC_PUBLIC TSRMLS_CC); ZEND_ACC_PUBLIC TSRMLS_CC); return SUCCESS; return SUCCESS;}}static zend_function_entry monextension_counter_methods[] = {{static zend_function_entry monextension_counter_methods[] = PHP_ME(Counter, reset, NULL, ZEND_ACC_PUBLIC) PHP_ME(Counter, reset, NULL, ZEND_ACC_PUBLIC) PHP_ME(Counter, getValue, NULL, ZEND_ACC_PUBLIC) PHP_ME(Counter, getValue, NULL, ZEND_ACC_PUBLIC) {NULL, NULL, NULL} {NULL, NULL, NULL}};};Premiers pas dans les extensions - Pierrick Charron 52
  53. 53. Les méthodesPHP_METHOD(Counter, getValue) PHP_METHOD(Counter, getValue){{ zval *object = getThis(); zval *object = getThis(); zval *details = NULL; zval *details = NULL; details = zend_read_property(counter_ce, object, "value", sizeof("value")-1, 1 details = zend_read_property(counter_ce, object, "value", sizeof("value")-1, 1TSRMLS_CC); TSRMLS_CC); RETURN_LONG(Z_LVAL(value)); RETURN_LONG(Z_LVAL(value));}}PHP_METHOD(Counter, reset) PHP_METHOD(Counter, reset){{ zend_update_property_long(counter_ce, getThis(), "value", sizeof("value")-1, 0 zend_update_property_long(counter_ce, getThis(), "value", sizeof("value")-1, 0TSRMLS_DC) TSRMLS_DC) RETURN_TRUE; RETURN_TRUE;}}Premiers pas dans les extensions - Pierrick Charron 53
  54. 54. Quelques outils bien utiles ;)Premiers pas dans les extensions - Pierrick Charron 54
  55. 55. Code compatible ZTS ? Compilez toujours votre PHP avec --enable-maintainer-ztsPremiers pas dans les extensions - Pierrick Charron 55
  56. 56. Fuites de mémoire ? --with-debug$ php -e $ php -e<?php leak(); <?php leak();[Tue Feb 22 20:12:17 2011] Script: - [Tue Feb 22 20:12:17 2011] Script: -/home/pierrick/php-src/trunk/Zend/zend_builtin_functions.c(1425) :: Freeing /home/pierrick/php-src/trunk/Zend/zend_builtin_functions.c(1425) Freeing0x7FA54892B708 (3 bytes), script=- 0x7FA54892B708 (3 bytes), script=-=== Total 1 memory leaks detected === === Total 1 memory leaks detected ===$$Premiers pas dans les extensions - Pierrick Charron 56
  57. 57. Fuites de mémoire ? valgrind$ USE_ZEND_ALLOC=0 valgrind --tool=memcheck --leak-check=yes --num-$ USE_ZEND_ALLOC=0 valgrind --tool=memcheck --leak-check=yes --num-callers=30 --show-reachable=yes sapi/cli/php leak.phpcallers=30 --show-reachable=yes sapi/cli/php leak.php….….==7164== LEAK SUMMARY:==7164== LEAK SUMMARY:==7164== definitely lost: 0 bytes in 0 blocks==7164== definitely lost: 0 bytes in 0 blocks==7164== indirectly lost: 0 bytes in 0 blocks==7164== indirectly lost: 0 bytes in 0 blocks==7164====7164== possibly lost: 0 bytes in 0 blocks possibly lost: 0 bytes in 0 blocks==7164== still reachable: 1,111,059 bytes in 8,728 blocks==7164== still reachable: 1,111,059 bytes in 8,728 blocks==7164====7164== suppressed: 0 bytes in 0 blocks suppressed: 0 bytes in 0 blocks….….Premiers pas dans les extensions - Pierrick Charron 57
  58. 58. Recherche de code ? grep http://lxr.php.netPremiers pas dans les extensions - Pierrick Charron 58
  59. 59. Premiers pas dans les extensions - Pierrick Charron 59
  60. 60. Premiers pas dans les extensions - Pierrick Charron 60
  61. 61. Segfault ? GDB (gnome debugger)$ gdb --args php -d extension=monextension.so segfault.php $ gdb --args php -d extension=monextension.so segfault.php(gdb) rr (gdb)Starting program: /usr/local/bin/php -d extension=monextension.so segfault.php Starting program: /usr/local/bin/php -d extension=monextension.so segfault.php[Thread debugging using libthread_db enabled] [Thread debugging using libthread_db enabled][New Thread 0x7fffefd1f700 (LWP 9457)] [New Thread 0x7fffefd1f700 (LWP 9457)][Thread 0x7fffefd1f700 (LWP 9457) exited] [Thread 0x7fffefd1f700 (LWP 9457) exited]Program received signal SIGSEGV, Segmentation fault.Program received signal SIGSEGV, Segmentation fault.__strcpy_chk () at ../sysdeps/x86_64/strcpy_chk.S:196__strcpy_chk () at ../sysdeps/x86_64/strcpy_chk.S:196196 ../sysdeps/x86_64/strcpy_chk.S: No such file or directory.in ../sysdeps/x86_64/strcpy_chk.S196 ../sysdeps/x86_64/strcpy_chk.S: No such file or directory.in ../sysdeps/x86_64/strcpy_chk.S(gdb) bt (gdb) bt#0 __strcpy_chk () at ../sysdeps/x86_64/strcpy_chk.S:196 #0 __strcpy_chk () at ../sysdeps/x86_64/strcpy_chk.S:196#1 0x00007fffefd20b0c in strcpy (ht=<value optimized out>, return_value=<value optimized out>, #1 0x00007fffefd20b0c in strcpy (ht=<value optimized out>, return_value=<value optimized out>,return_value_ptr=<value optimized out>, this_ptr=0x6, return_value_used=0, tsrm_ls=0xfa70c0) at return_value_ptr=<value optimized out>, this_ptr=0x6, return_value_used=0, tsrm_ls=0xfa70c0) at/usr/include/bits/string3.h:107 /usr/include/bits/string3.h:107#2 zif_monextension_helloworld (ht=<value optimized out>, return_value=<value optimized out>, #2 zif_monextension_helloworld (ht=<value optimized out>, return_value=<value optimized out>,return_value_ptr=<value optimized out>, this_ptr=0x6, return_value_used=0, tsrm_ls=0xfa70c0) at return_value_ptr=<value optimized out>, this_ptr=0x6, return_value_used=0, tsrm_ls=0xfa70c0) at/home/pierrick/php-src/trunk/ext/monextension/monextension.c:162 /home/pierrick/php-src/trunk/ext/monextension/monextension.c:162#3 0x00007ffff2658b35 in xdebug_execute_internal (current_execute_data=0x7ffff7eb7050, #3 0x00007ffff2658b35 in xdebug_execute_internal (current_execute_data=0x7ffff7eb7050,return_value_used=0, tsrm_ls=0xfa70c0) at /home/pierrick/installs/xdebug-2.1.0/xdebug.c:1339 return_value_used=0, tsrm_ls=0xfa70c0) at /home/pierrick/installs/xdebug-2.1.0/xdebug.c:1339#4 0x000000000081b777 in zend_do_fcall_common_helper_SPEC (execute_data=0x7ffff7eb7050, #4 0x000000000081b777 in zend_do_fcall_common_helper_SPEC (execute_data=0x7ffff7eb7050,tsrm_ls=0xfa70c0) at /home/pierrick/php- tsrm_ls=0xfa70c0) at /home/pierrick/php- Premiers pas dans les extensions - Pierrick Charron 61
  62. 62. Besoin daide ? Irc.EFNet.org #php.pecl Mailing Lists http://marc.info/?l=php-internals http://marc.info/?l=pecl-devPremiers pas dans les extensions - Pierrick Charron 62
  63. 63. Envie de lecture ? http://www.php.net/manual/en/internals2.php Advanced PHP Programming par George Schlossnagle Extending and Embedding PHP par Sara Golemon ISBN#0-6723-2704-XPremiers pas dans les extensions - Pierrick Charron 63
  64. 64. Questions ? pierrick@php.net Twitter: @adoyy Commentaires et présentation : http://joind.in/2869Premiers pas dans les extensions - Pierrick Charron 64
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×