Premiers pas dans les extensions PHP
Transcription
Premiers pas dans les extensions PHP
Premiers pas dans les extensions PHP Pierrick Charron, Confoo, Mars 2011 [email protected] Qui suis-je ? ● Consultant TI à Montréal ● Auteur de l'extension PHP Stomp ● Contributeur PHP depuis 2009 ● Core ● RFC (Request For Comment) ● Documentation (Fr & En) Premiers pas dans les extensions - Pierrick Charron 2 Une extension ? Premiers pas dans les extensions - Pierrick Charron 3 Pourquoi créer une extension ? ● Permettre l'utilisation d'une librairie externe ● Exemple : mysql, curl ● Améliorer les performances ● Opération impossible dans l'espace utilisateur ● ● Exemple : Xdebug, operator, vld Satisfaire sa curiosité Premiers pas dans les extensions - Pierrick Charron 4 Avant de commencer ● Présentation basée sur PHP >= 5.3 ● Utilisation de Linux #include <stdio.h> void main() { printf("C Code"); } Premiers pas dans les extensions - Pierrick Charron $ echo "terminal linux" terminal linux 5 Prérequis ● Familier avec PHP ● Configuration de PHP ● Installation de modules ● Connaissances en C ● Patience ● API très complet ● Beaucoup, beaucoup, beaucoup... de macros Premiers pas dans les extensions - Pierrick Charron 6 Architecture de PHP API Serveur (SAPI) Apache FPM CLI Embed Zend Engine ... PHP Core API pour les extensions standard mysqli Premiers pas dans les extensions - Pierrick Charron curl date ... 7 Cycle de vie d'une 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 d'appels dépend du SAPI Premiers pas dans les extensions - Pierrick Charron 8 Cycle de vie : CLI $ php monscript.php MINIT RINIT Execution du script RSHUTDOWN MSHUTDOWN Premiers pas dans les extensions - Pierrick Charron 9 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 Premiers pas dans les extensions - Pierrick Charron MSHUTDOWN 10 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 MSHUTDOWN Premiers pas dans les extensions - Pierrick Charron 11 Zend Thread Safety / TSRM ● Utilisé avec des "threaded webservers" ● Chaque thread a son propre stockage local ● Evite les accès concurrents Premiers pas dans les extensions - Pierrick Charron 12 Les macros ZTS #define #define TSRMLS_D TSRMLS_D #define #define TSRMLS_DC TSRMLS_DC #define #define TSRMLS_C TSRMLS_C #define #define TSRMLS_CC TSRMLS_CC void void ***tsrmls ***tsrmls ,, TSRMLS_D TSRMLS_D tsrmls tsrmls ,, TSRMLS_C TSRMLS_C static static void void ma_fonction(int ma_fonction(int ii TSRMLS_DC); TSRMLS_DC); ma_function(10 ma_function(10 TSRMLS_CC); TSRMLS_CC); static static void void ma_fonction(int ma_fonction(int i); i); ma_function(10); ma_function(10); static static void void ma_fonction(int ma_fonction(int i,i, void void ***tsrmls); ***tsrmls); ma_function(10, ma_function(10, tsrmls); tsrmls); Premiers pas dans les extensions - Pierrick Charron 13 Zend Value Premiers pas dans les extensions - Pierrick Charron 14 ZVAL ● Zval : valeur dans espace utilisateur ● Attention valeur != variable ● Conversion de type ● Compteur de référence Premiers pas dans les extensions - Pierrick Charron 15 ZVAL typedef typedef struct struct _zval_struct _zval_struct {{ zvalue_value zvalue_value value; value; zend_uint zend_uint refcount__gc; refcount__gc; zend_uchar zend_uchar type; type; zend_uchar zend_uchar is_ref__gc; is_ref__gc; }} zval; zval; IS_NULL IS_NULL IS_LONG IS_LONG IS_DOUBLE IS_DOUBLE IS_BOOL IS_BOOL IS_ARRAY IS_ARRAY IS_OBJECT IS_OBJECT IS_STRING IS_STRING IS_RESOURCE IS_RESOURCE Premiers pas dans les extensions - Pierrick Charron typedef typedef union union _zvalue_value _zvalue_value {{ long long lval; lval; double double dval; dval; struct struct {{ char char *val; *val; int int len; len; }} str; str; HashTable HashTable *ht; *ht; zend_object_value zend_object_value *obj; *obj; }} zvalue_value; zvalue_value; 16 ZVAL typedef typedef struct struct _zval_struct _zval_struct {{ zvalue_value zvalue_value value; value; zend_uint zend_uint refcount__gc; refcount__gc; zend_uchar zend_uchar type; type; zend_uchar zend_uchar is_ref__gc; is_ref__gc; }} zval; zval; Premiers pas dans les extensions - Pierrick Charron Nombre de variables qui pointent vers cette valeur Définit si oui ou non une valeur est une référence 17 ZVAL Nombre de variables qui pointent vers cette valeur typedef typedef struct struct _zval_struct _zval_struct {{ zvalue_value zvalue_value value; value; zend_uint zend_uint refcount__gc; refcount__gc; zend_uchar zend_uchar type; type; zend_uchar zend_uchar is_ref__gc; is_ref__gc; }} zval; zval; $a $a $a == 10; 10; $b $b == $a; $a; $b $b == 20; 20; Définit si oui ou non une valeur est une référence $b value.lval value.lval == 10 10 refcount refcount == 22 type type == IS_LONG IS_LONG is_ref is_ref == 00 Premiers pas dans les extensions - Pierrick Charron 18 ZVAL Nombre de variables qui pointent vers cette valeur typedef typedef struct struct _zval_struct _zval_struct {{ zvalue_value zvalue_value value; value; zend_uint zend_uint refcount__gc; refcount__gc; zend_uchar zend_uchar type; type; zend_uchar zend_uchar is_ref__gc; is_ref__gc; }} zval; zval; $a $a $a == 10; 10; $b $b == $a; $a; $b $b == 20; 20; Définit si oui ou non une valeur est une référence $b value.lval value.lval == 10 10 21 refcount refcount == 1 2 type type == IS_LONG IS_LONG is_ref is_ref == 00 Premiers pas dans les extensions - Pierrick Charron value.lval value.lval == 20 20 refcount refcount == 11 type type == IS_LONG IS_LONG is_ref is_ref == 00 19 ZVAL Nombre de variables qui pointent vers cette valeur typedef typedef struct struct _zval_struct _zval_struct {{ zvalue_value zvalue_value value; value; zend_uint zend_uint refcount__gc; refcount__gc; zend_uchar zend_uchar type; type; zend_uchar zend_uchar is_ref__gc; is_ref__gc; }} zval; zval; $a $a $a == 10; 10; $b $b == &$a; &$a; $b $b == 20; 20; Définit si oui ou non une valeur est une référence $b value.lval value.lval == 10 10 refcount refcount == 22 type type == IS_LONG IS_LONG is_ref 01 is_ref == 1 0 Premiers pas dans les extensions - Pierrick Charron 20 ZVAL Nombre de variables qui pointent vers cette valeur typedef typedef struct struct _zval_struct _zval_struct {{ zvalue_value zvalue_value value; value; zend_uint zend_uint refcount__gc; refcount__gc; zend_uchar zend_uchar type; type; zend_uchar zend_uchar is_ref__gc; is_ref__gc; }} zval; zval; $a $a $a == 10; 10; $b $b == &$a; &$a; $b $b == 20; 20; Définit si oui ou non une valeur est une référence $b value.lval 10 value.lval == 20 10 20 refcount refcount == 22 type type == IS_LONG IS_LONG is_ref 01 is_ref == 1 0 Premiers pas dans les extensions - Pierrick Charron 21 ZVAL : Récuperer le type #define (zval).type (zval).type #define Z_TYPE(zval) Z_TYPE(zval) (zval).type (zval).type #define Z_TYPE(zval_p) Z_TYPE(*zval_p) Z_TYPE(*zval_p) #define Z_TYPE_P(zval_p) Z_TYPE(zval_p) Z_TYPE_P(zval_p) Z_TYPE(*zval_p) Z_TYPE(*zval_p) #define Z_TYPE(zval_pp) Z_TYPE(**zval_pp) Z_TYPE(**zval_pp) #define Z_TYPE_PP(zval_pp) Z_TYPE(zval_pp) Z_TYPE_PP(zval_pp) Z_TYPE(**zval_pp) Z_TYPE(**zval_pp) zval zval foo; foo; Z_TYPE(foo) Z_TYPE(foo) == == IS_LONG IS_LONG zval zval *bar; *bar; Z_TYPE_P(bar) Z_TYPE_P(bar) == == IS_BOOL IS_BOOL Premiers pas dans les extensions - Pierrick Charron 22 ZVAL : Récuperer une valeur #define #define Z_LVAL(zval) Z_LVAL(zval) #define #define Z_BVAL(zval) Z_BVAL(zval) #define #define Z_DVAL(zval) Z_DVAL(zval) #define #define Z_STRVAL(zval) Z_STRVAL(zval) #define #define Z_STRLEN(zval) Z_STRLEN(zval) #define #define Z_ARRVAL(zval) Z_ARRVAL(zval) #define #define Z_OBJVAL(zval) Z_OBJVAL(zval) (zval).value.lval (zval).value.lval ((zend_bool)(zval).value.lval) ((zend_bool)(zval).value.lval) (zval).value.dval (zval).value.dval (zval).value.str.val (zval).value.str.val (zval).value.str.len (zval).value.str.len (zval).value.ht (zval).value.ht (zval).value.obj (zval).value.obj #define #define Z_*_P(zval_p) Z_*_P(zval_p) #define #define Z_*_PP(zval_pp) Z_*_PP(zval_pp) (*zval). (*zval). (**zval). (**zval). Premiers pas dans les extensions - Pierrick Charron 23 ZVAL : Assigner une valeur ZVAL_NULL(zval); ZVAL_NULL(zval); Z_TYPE_P(zval) Z_TYPE_P(zval) == IS_NULL; IS_NULL; ZVAL_LONG(zval,l); ZVAL_LONG(zval,l); Z_TYPE_P(zval) Z_TYPE_P(zval) == IS_LONG; IS_LONG; Z_LVAL_P(zval) Z_LVAL_P(zval) == l;l; ZVAL_DOUBLE(zval,d); ZVAL_DOUBLE(zval,d); Z_TYPE_P(zval) Z_TYPE_P(zval) == IS_DOUBLE; IS_DOUBLE; Z_DVAL_P(zval) Z_DVAL_P(zval) == d; d; ZVAL_STRINGL(zval,str,len,dup) ZVAL_STRINGL(zval,str,len,dup) Z_TYPE_P(zval) Z_TYPE_P(zval) == IS_STRING; IS_STRING; Z_STRLEN_P(zval) Z_STRLEN_P(zval) == len; len; ifif (dup) (dup) {{ Z_STRVAL_P(zval) Z_STRVAL_P(zval) == estrndup(str, estrndup(str, len+1); len+1); }} else else {{ Z_STRVAL_P(zval) Z_STRVAL_P(zval) == str; str; }} ZVAL_BOOL(zval, ZVAL_BOOL(zval, b) b) Z_TYPE_P(zval) Z_TYPE_P(zval) == IS_BOOLEAN; IS_BOOLEAN; Z_BVAL_P(zval) Z_BVAL_P(zval) == bb ?? 11 :: 0; 0; Premiers pas dans les extensions - Pierrick Charron 24 Conversion void void convert_to_string(zval convert_to_string(zval *); *); void void convert_to_long(zval convert_to_long(zval *); *); void void convert_to_double(zval convert_to_double(zval *); *); void void convert_to_null(zval convert_to_null(zval *); *); void void convert_to_boolean(zval convert_to_boolean(zval *); *); void void convert_to_array(zval convert_to_array(zval *); *); void void convert_to_object(zval convert_to_object(zval *); *); Premiers pas dans les extensions - Pierrick Charron 25 Gestion de la mémoire ● Zend dispose d'un memory manager ● ● évite les fuites de mémoire signature des fonctions similaires aux fonctions natives C Premiers pas dans les extensions - Pierrick Charron 26 Les fonctions d'allocation Fonction C traditionnelle Fonction spécifique à PHP void *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 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 l'extension $$ ./ext_skel ./ext_skel --extname=monextension --extname=monextension Premiers pas dans les extensions - Pierrick Charron 29 Les fichiers de monextension $$ tree tree monextension monextension monextension/ monextension/ |-|-- config.m4 config.m4 |-|-- config.w32 config.w32 |-|-- CREDITS CREDITS |-|-- EXPERIMENTAL EXPERIMENTAL |-|-- monextension.c monextension.c |-|-- monextension.php monextension.php |-|-- php_monextension.h php_monextension.h `-`-- tests tests `-`-- 001.phpt 001.phpt ● ● Fichiers de configuration ● Config.m4 ● Config.w32 Fichiers de code ● monextension.c ● php_monextension.h 11 directory, directory, 88 files files Premiers pas dans les extensions - Pierrick Charron 30 Config.m4 ● Script de configuration sous Linux ● Utilisé par ./buildconf et phpize dnl dnl IfIf your your extension extension references references something something external, external, use use with: with: dnl dnl PHP_ARG_WITH(monextension, PHP_ARG_WITH(monextension, for for monextension monextension support, support, dnl dnl Make Make sure sure that that the the comment comment is is aligned: aligned: dnl Include dnl [[ --with-monextension --with-monextension Include monextension monextension support]) support]) dnl dnl Otherwise Otherwise use use enable: enable: PHP_ARG_ENABLE(monextension, whether to enable monextension support, dnl whether to monext dnl PHP_ARG_ENABLE(monextension, PHP_ARG_ENABLE(monextension, whether to enable enable monext support, support, Make suresure thatthat the comment is aligned: dnl the is dnl Make Make sure that the comment comment is aligned: aligned: [dnl --enable-monextension monextension support]) [[ --enable-monextension Enable monextension support]) dnl --enable-monextension Enable Enable monextension support]) Premiers pas dans les extensions - Pierrick Charron 31 Compiler monextension ● Dynamique $$ phpize phpize $$ ./configure ./configure $$ make make $$ make make test test ● Statique $$ ./buildconf ./buildconf --force --force $$ ./configure ./configure --enable-monextension --enable-monextension $$ make make $$ make make test test Premiers pas dans les extensions - Pierrick Charron 32 PHPT Avant même de commencer à programmer, pensez à écrire vos tests !!!! http://qa.php.net/write-test.php Premiers pas dans les extensions - Pierrick Charron 33 php_monextension.h ● Déclaration des données pour la liaison statique Premiers pas dans les extensions - Pierrick Charron 34 monextension.c ● #includes ● Structures statiques ● Fonctions PHP ● MINFO ● MINIT, MSHUTDOWN, RINIT, RSHUTDOWN ● Table des fonctions ● Définition du module Premiers pas dans les extensions - Pierrick Charron 35 Définition du module ● Structure permettant à PHP d'initialiser ou de désinitialiser le module zend_module_entry zend_module_entry monextension_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 Liste des fonctions const const zend_function_entry zend_function_entry monextension_functions[] monextension_functions[] == {{ PHP_FE(confirm_monextension_compiled, PHP_FE(confirm_monextension_compiled, NULL) 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 Première fonction monextension.c const const zend_function_entry zend_function_entry monextension_functions[] monextension_functions[] == {{ PHP_FE(monextension_helloworld, PHP_FE(monextension_helloworld, NULL) NULL) {NULL, {NULL, NULL, NULL, NULL} NULL} };}; /** /** … … **/ **/ PHP_FUNCTION(monextension_helloworld) PHP_FUNCTION(monextension_helloworld) {{ php_printf("Hello php_printf("Hello world world !!!"); !!!"); };}; php_monextension.h PHP_FUNCTION(monextension_helloworld); PHP_FUNCTION(monextension_helloworld); Premiers pas dans les extensions - Pierrick Charron 38 PHP_FUNCTION PHP_FUNCTION(monextension_helloworld) PHP_FUNCTION(monextension_helloworld) {{ php_printf("Hello php_printf("Hello world world !!!"); !!!"); }} void void zif_monextension_helloworld(int zif_monextension_helloworld(int ht, ht, zval zval *return_value, *return_value, zval zval **return_value_ptr, **return_value_ptr, zval zval *this_ptr, *this_ptr, int int return_value_used return_value_used TSRMLS_DC) TSRMLS_DC) {{ php_printf("Hello php_printf("Hello world world !!!"); !!!"); }} Premiers pas dans les extensions - Pierrick Charron 39 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, ZVAL_STRING(return_value, "Hello "Hello world world !!!", !!!", 1); 1); return; return; };}; Premiers pas dans les extensions - Pierrick Charron 40 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 RETVAL_STRING("Hello world world !!!", !!!", 1); 1); /* /* Code Code executé executé */ */ return; return; };}; Premiers pas dans les extensions - Pierrick Charron 41 RETURN_* ● RETVAL_* n'interrompt pas l'exécution du code ● RETURN_* = RETVAL_*; return; PHP_FUNCTION(monextension_helloworld) PHP_FUNCTION(monextension_helloworld) {{ RETURN_STRING("Hello RETURN_STRING("Hello world world !!!", !!!", 1); 1); /* /* Code Code jamais jamais executé executé */ */ };}; Premiers pas dans les extensions - Pierrick Charron 42 Paramètres de fonction PHP_FUNCTION(monextension_helloworld) PHP_FUNCTION(monextension_helloworld) {{ char char *name; *name; int int name_len; name_len; ifif (zend_parse_parameters(ZEND_NUM_ARGS() (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, TSRMLS_CC, "s", "s", &name, &name, &name_len) &name_len) == == FAILURE) FAILURE) {{ return; return; }} php_printf("Hello php_printf("Hello %s %s !", !", name); name); };}; Premiers pas dans les extensions - Pierrick Charron 43 Paramètres de fonction int int zend_parse_parameters zend_parse_parameters (int (int num_args num_args TSRMLS_DC, TSRMLS_DC, char char *type_spec, *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 d'un type spécifique zval **, zend_class_entry * z zval zval ** Premiers pas dans les extensions - Pierrick Charron 44 Paramètres optionnels ● Utilisation du modificateur "|" PHP_FUNCTION(monextension_helloworld) PHP_FUNCTION(monextension_helloworld) {{ char char *name *name == "world"; "world"; int int name_len name_len == sizeof("world")-1; sizeof("world")-1; ifif (zend_parse_parameters(ZEND_NUM_ARGS() (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, TSRMLS_CC, "|s", "|s", &name, &name, &name_len) &name_len) == == FAILURE) FAILURE) {{ return; return; }} php_printf("Hello php_printf("Hello %s %s !", !", name); name); };}; Premiers pas dans les extensions - Pierrick Charron 45 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 impossible Premiers pas dans les extensions - Pierrick Charron 46 Initialiser un tableau int int array_init(zval array_init(zval *z); *z); /* /* $array $array == 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 Ajout d'éléments Tableau 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; $arr[5] = 3.1416; add_index_long(arr, 4, 10); 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; $arr[] = 3.1416; add_next_index_long(arr, 10); add_next_index_double(arr, 3.1416); $arr[] = $foo; add_next_index_zval(arr, foo); Premiers pas dans les extensions - Pierrick Charron 48 Ajout d'éléments Tableau 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); add_assoc_double(arr, "biz", 3.1416); add_assoc_double_ex(arr, "biz", sizeof("biz"), 3.1416); $arr["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 Recherche d'éléments int int zend_hash_find(const zend_hash_find(const HashTable HashTable *ht, *ht, const const char char *arKey, *arKey, uint uint nKeyLength, nKeyLength, void void **pData) **pData) int int zend_hash_quick_find(const zend_hash_quick_find(const HashTable HashTable *ht, *ht, const const char char *arKey, *arKey, uint uint nKeyLength, nKeyLength, ulong ulong h, h, void void **pData) **pData) int int zend_hash_index_find(const zend_hash_index_find(const HashTable HashTable *ht, *ht, ulong ulong h, h, void void **pData) **pData) zval zval **data; **data; ifif (zend_symtable_find(Z_ARRVAL(zval), (zend_symtable_find(Z_ARRVAL(zval), "clef", "clef", sizeof("clef"), sizeof("clef"), (void**)&data) (void**)&data) == == SUCCESS) SUCCESS) {{ switch switch (Z_TYPE_PP(data)) (Z_TYPE_PP(data)) {{ /* /* ... ... */ */ }} }} Premiers pas dans les extensions - Pierrick Charron 50 Suppression d'éléments int int zend_hash_del(HashTable zend_hash_del(HashTable *ht, *ht, char char *arKey, *arKey, uint uint nKeyLen); nKeyLen); int int zend_hash_quick_del(HashTable zend_hash_quick_del(HashTable *ht, *ht, char char *arKey, *arKey, uint uint nKeyLen, nKeyLen, ulong ulong h); h); int int zend_hash_index_del(HashTable zend_hash_index_del(HashTable *ht, *ht, ulong ulong h); h); Premiers pas dans les extensions - Pierrick Charron 51 Création d'une classe zend_class_entry zend_class_entry *counter_ce; *counter_ce; PHP_MINIT_FUNCTION(monextension) PHP_MINIT_FUNCTION(monextension) {{ zend_class_entry zend_class_entry ce; ce; INIT_CLASS_ENTRY(ce, INIT_CLASS_ENTRY(ce, "Counter", "Counter", monextension_counter_methods); monextension_counter_methods); counter_ce counter_ce == zend_register_internal_class(&ce zend_register_internal_class(&ce TSRMLS_CC); TSRMLS_CC); zend_declare_property_long(counter_ce, zend_declare_property_long(counter_ce, "value "value",", sizeof( sizeof("value "value")-1, ")-1, 0, 0, ZEND_ACC_PUBLIC ZEND_ACC_PUBLIC TSRMLS_CC); TSRMLS_CC); return return SUCCESS; SUCCESS; }} static static zend_function_entry zend_function_entry monextension_counter_methods[] monextension_counter_methods[] == {{ PHP_ME(Counter, PHP_ME(Counter, reset, reset, NULL, NULL, ZEND_ACC_PUBLIC) ZEND_ACC_PUBLIC) PHP_ME(Counter, PHP_ME(Counter, getValue, getValue, NULL, NULL, ZEND_ACC_PUBLIC) ZEND_ACC_PUBLIC) {NULL, {NULL, NULL, NULL, NULL} NULL} };}; Premiers pas dans les extensions - Pierrick Charron 52 Les méthodes PHP_METHOD(Counter, PHP_METHOD(Counter, getValue) getValue) {{ zval zval *object *object == getThis(); getThis(); zval zval *details *details == NULL; NULL; details details == zend_read_property(counter_ce, zend_read_property(counter_ce, object, object, "value", "value", sizeof("value")-1, sizeof("value")-1, 11 TSRMLS_CC); TSRMLS_CC); RETURN_LONG(Z_LVAL(value)); RETURN_LONG(Z_LVAL(value)); }} PHP_METHOD(Counter, PHP_METHOD(Counter, reset) reset) {{ zend_update_property_long(counter_ce, zend_update_property_long(counter_ce, getThis(), getThis(), "value", "value", sizeof("value")-1, sizeof("value")-1, 00 TSRMLS_DC) TSRMLS_DC) RETURN_TRUE; RETURN_TRUE; }} Premiers pas dans les extensions - Pierrick Charron 53 Quelques outils bien utiles ;) Premiers pas dans les extensions - Pierrick Charron 54 Code compatible ZTS ? Compilez toujours votre PHP avec --enable-maintainer-zts Premiers pas dans les extensions - Pierrick Charron 55 Fuites de mémoire ? --enable-debug $$ php php -e -e <?php <?php leak(); leak(); [Tue [Tue Feb Feb 22 22 20:12:17 20:12:17 2011] 2011] Script: Script: '-' '-' /home/pierrick/php-src/trunk/Zend/zend_builtin_functions.c(1425) /home/pierrick/php-src/trunk/Zend/zend_builtin_functions.c(1425) :: Freeing Freeing 0x7FA54892B708 0x7FA54892B708 (3 (3 bytes), bytes), script=script==== === Total Total 11 memory memory leaks leaks detected detected === === $$ Premiers pas dans les extensions - Pierrick Charron 56 Fuites de mémoire ? valgrind $$ USE_ZEND_ALLOC=0 USE_ZEND_ALLOC=0 valgrind valgrind --tool=memcheck --tool=memcheck --leak-check=yes --leak-check=yes --num--numcallers=30 callers=30 --show-reachable=yes --show-reachable=yes sapi/cli/php sapi/cli/php leak.php leak.php …. …. ==7164== ==7164== LEAK LEAK SUMMARY: SUMMARY: ==7164== ==7164== definitely definitely lost: lost: 00 bytes bytes in in 00 blocks blocks ==7164== ==7164== indirectly indirectly lost: lost: 00 bytes bytes in in 00 blocks blocks ==7164== possibly ==7164== possibly lost: lost: 00 bytes bytes in in 00 blocks blocks ==7164== ==7164== still still reachable: reachable: 1,111,059 1,111,059 bytes bytes in in 8,728 8,728 blocks blocks ==7164== suppressed: ==7164== suppressed: 00 bytes bytes in in 00 blocks blocks …. …. Premiers pas dans les extensions - Pierrick Charron 57 Recherche de code ? grep http://lxr.php.net Premiers pas dans les extensions - Pierrick Charron 58 Premiers pas dans les extensions - Pierrick Charron 59 Premiers pas dans les extensions - Pierrick Charron 60 Segfault ? GDB (gnome debugger) $$ gdb gdb --args --args php php -d -d extension=monextension.so extension=monextension.so segfault.php segfault.php (gdb) (gdb) rr Starting Starting program: program: /usr/local/bin/php /usr/local/bin/php -d -d extension=monextension.so extension=monextension.so segfault.php segfault.php [Thread debugging using libthread_db enabled] [Thread debugging using libthread_db enabled] [New [New Thread Thread 0x7fffefd1f700 0x7fffefd1f700 (LWP (LWP 9457)] 9457)] [Thread 0x7fffefd1f700 (LWP 9457) [Thread 0x7fffefd1f700 (LWP 9457) exited] exited] Program Program received received signal signal SIGSEGV, SIGSEGV, Segmentation Segmentation fault. fault. __strcpy_chk () at ../sysdeps/x86_64/strcpy_chk.S:196 __strcpy_chk () at ../sysdeps/x86_64/strcpy_chk.S:196 196 196 ../sysdeps/x86_64/strcpy_chk.S: ../sysdeps/x86_64/strcpy_chk.S: No No such such file file or or directory.in directory.in ../sysdeps/x86_64/strcpy_chk.S ../sysdeps/x86_64/strcpy_chk.S (gdb) (gdb) bt bt #0 #0 __strcpy_chk __strcpy_chk ()() at at ../sysdeps/x86_64/strcpy_chk.S:196 ../sysdeps/x86_64/strcpy_chk.S:196 #1 #1 0x00007fffefd20b0c 0x00007fffefd20b0c in in strcpy strcpy (ht=<value (ht=<value optimized optimized out>, out>, return_value=<value return_value=<value optimized optimized out>, out>, return_value_ptr=<value return_value_ptr=<value optimized optimized out>, out>, this_ptr=0x6, this_ptr=0x6, return_value_used=0, return_value_used=0, tsrm_ls=0xfa70c0) tsrm_ls=0xfa70c0) at at /usr/include/bits/string3.h:107 /usr/include/bits/string3.h:107 #2 #2 zif_monextension_helloworld zif_monextension_helloworld (ht=<value (ht=<value optimized optimized out>, out>, return_value=<value return_value=<value optimized optimized out>, out>, return_value_ptr=<value optimized out>, this_ptr=0x6, return_value_used=0, tsrm_ls=0xfa70c0) return_value_ptr=<value optimized out>, this_ptr=0x6, return_value_used=0, tsrm_ls=0xfa70c0) at at /home/pierrick/php-src/trunk/ext/monextension/monextension.c:162 /home/pierrick/php-src/trunk/ext/monextension/monextension.c:162 #3 #3 0x00007ffff2658b35 0x00007ffff2658b35 in in xdebug_execute_internal xdebug_execute_internal (current_execute_data=0x7ffff7eb7050, (current_execute_data=0x7ffff7eb7050, return_value_used=0, return_value_used=0, tsrm_ls=0xfa70c0) tsrm_ls=0xfa70c0) at at /home/pierrick/installs/xdebug-2.1.0/xdebug.c:1339 /home/pierrick/installs/xdebug-2.1.0/xdebug.c:1339 #4 0x000000000081b777 in zend_do_fcall_common_helper_SPEC #4 0x000000000081b777 in zend_do_fcall_common_helper_SPEC (execute_data=0x7ffff7eb7050, (execute_data=0x7ffff7eb7050, tsrm_ls=0xfa70c0) at /home/pierrick/phptsrm_ls=0xfa70c0) at /home/pierrick/phpPremiers pas dans les extensions - Pierrick Charron 61 Besoin d'aide ? Irc.EFNet.org #php.pecl Mailing Lists http://marc.info/?l=php-internals http://marc.info/?l=pecl-dev Premiers pas dans les extensions - Pierrick Charron 62 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-X Premiers pas dans les extensions - Pierrick Charron 63 Questions ? [email protected] Twitter: @adoyy Commentaires et présentation : http://joind.in/2869 Premiers pas dans les extensions - Pierrick Charron 64