• Like
Premiers pas dans les extensions PHP, Pierrick Charron, Confoo 2011
Upcoming SlideShare
Loading in...5
×

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

  • 1,445 views
Uploaded on

 

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
  • Very good
    Are you sure you want to
    Your message goes here
    Be the first to like this
No Downloads

Views

Total Views
1,445
On Slideshare
0
From Embeds
0
Number of Embeds
3

Actions

Shares
Downloads
20
Comments
1
Likes
0

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Premiers pas dans les extensions PHP Pierrick Charron, Confoo, Mars 2011 pierrick@php.net
  • 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. Une extension ?Premiers pas dans les extensions - Pierrick Charron 3
  • 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. 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. 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. 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. 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. Cycle de vie : CLI$ php monscript.php MINIT RINIT Execution du script RSHUTDOWN MSHUTDOWNPremiers pas dans les extensions - Pierrick Charron 9
  • 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. 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. 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. 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. Zend ValuePremiers pas dans les extensions - Pierrick Charron 14
  • 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. Et les extensions alors ?Premiers pas dans les extensions - Pierrick Charron 28
  • 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. 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. 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. 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. 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. php_monextension.h● Déclaration des données pour la liaison statiquePremiers pas dans les extensions - Pierrick Charron 34
  • 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. Quelques outils bien utiles ;)Premiers pas dans les extensions - Pierrick Charron 54
  • 55. Code compatible ZTS ? Compilez toujours votre PHP avec --enable-maintainer-ztsPremiers pas dans les extensions - Pierrick Charron 55
  • 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. 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. Recherche de code ? grep http://lxr.php.netPremiers pas dans les extensions - Pierrick Charron 58
  • 59. Premiers pas dans les extensions - Pierrick Charron 59
  • 60. Premiers pas dans les extensions - Pierrick Charron 60
  • 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. 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. 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. Questions ? pierrick@php.net Twitter: @adoyy Commentaires et présentation : http://joind.in/2869Premiers pas dans les extensions - Pierrick Charron 64