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

            pierrick@php.net
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>                                   $ echo "terminal linux"
 void main() {                                        terminal linux
    printf("C Code");
 }




Premiers pas dans les extensions - Pierrick Charron                             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              curl      date         ...




Premiers pas dans les extensions - Pierrick Charron                                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                               MSHUTDOWN




Premiers pas dans les extensions - Pierrick Charron                         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 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
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 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_RESOURCE
Premiers pas dans les extensions - Pierrick Charron                                   16
ZVAL
                                                      Nombre de variables qui
typedef 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
ZVAL
                                                           Nombre de variables qui
typedef 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 = 0


Premiers pas dans les extensions - Pierrick Charron                                           18
ZVAL
                                                           Nombre de variables qui
typedef 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 = 0


Premiers pas dans les extensions - Pierrick Charron                                           19
ZVAL
                                                           Nombre de variables qui
typedef 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
                                               0


Premiers pas dans les extensions - Pierrick Charron                                           20
ZVAL
                                                           Nombre de variables qui
typedef 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
                                               0


Premiers pas dans les extensions - Pierrick Charron                                           21
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_BOOL




Premiers pas dans les extensions - Pierrick Charron   22
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
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
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
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 --extname=monextension
$ ./ext_skel --extname=monextension




Premiers pas dans les extensions - Pierrick Charron   29
Les fichiers de monextension
$ tree monextension
$ tree monextension
                                                      ●   Fichiers de configuration

monextension/
 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.phpt

1 directory, 8 files
1 directory, 8 files




Premiers pas dans les extensions - Pierrick Charron                                   30
Config.m4
 ●   Script de configuration sous Linux
      ●   Utilisé par ./buildconf et phpize

dnl 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-monextension
dnl --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-monextension
dnl --enable-monextension         Enable monextension support])
                                   Enable monextension support])



Premiers pas dans les extensions - Pierrick Charron                    31
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 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 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
Liste des fonctions
const 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
Première fonction
monextension.c
const 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.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 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
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
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
RETURN_*
●   RETVAL_* n'interrompt pas l'exé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
Paramètres de fonction
PHP_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
Paramètres de fonction
int 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 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 *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
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 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
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;                                          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
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);
$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
Recherche d'éléments
int 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
Suppression d'éléments
int 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
Création d'une classe
zend_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
Les méthodes
PHP_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, 1
TSRMLS_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, 0
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 ?

                                         --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) Freeing
0x7FA54892B708 (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
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.php
callers=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
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 --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:196
196 ../sysdeps/x86_64/strcpy_chk.S: No such file or directory.in ../sysdeps/x86_64/strcpy_chk.S
196 ../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
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 ?
                                        pierrick@php.net
                                        Twitter: @adoyy

                           Commentaires et présentation :
                               http://joind.in/2869




Premiers pas dans les extensions - Pierrick Charron         64

Premiers pas dans les extensions PHP

  • 1.
    Premiers pas dansles extensions PHP Pierrick Charron, Confoo, Mars 2011 pierrick@php.net
  • 2.
    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
  • 3.
    Une extension ? Premierspas dans les extensions - Pierrick Charron 3
  • 4.
    Pourquoi créer uneextension ? ● 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
  • 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 macros Premiers 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 vied'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
  • 9.
    Cycle de vie: CLI $ php monscript.php MINIT RINIT Execution du script RSHUTDOWN MSHUTDOWN Premiers 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 MSHUTDOWN Premiers 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 MSHUTDOWN Premiers 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 concurrents Premiers 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 Value Premiers pasdans les extensions - Pierrick Charron 14
  • 15.
    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
  • 16.
    ZVAL typedef 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_RESOURCE Premiers pas dans les extensions - Pierrick Charron 16
  • 17.
    ZVAL Nombre de variables qui typedef 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 qui typedef 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 = 0 Premiers pas dans les extensions - Pierrick Charron 18
  • 19.
    ZVAL Nombre de variables qui typedef 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 = 0 Premiers pas dans les extensions - Pierrick Charron 19
  • 20.
    ZVAL Nombre de variables qui typedef 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 0 Premiers pas dans les extensions - Pierrick Charron 20
  • 21.
    ZVAL Nombre de variables qui typedef 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 0 Premiers pas dans les extensions - Pierrick Charron 21
  • 22.
    ZVAL : Récupererle 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_BOOL Premiers pas dans les extensions - Pierrick Charron 22
  • 23.
    ZVAL : Récupererune 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 : Assignerune 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 lamé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
  • 27.
    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
  • 28.
    Et les extensionsalors ? Premiers pas dans les extensions - Pierrick Charron 28
  • 29.
    ./ext_skel ● Outil de génération de code ● Génére le squelette de l'extension $ ./ext_skel --extname=monextension $ ./ext_skel --extname=monextension Premiers pas dans les extensions - Pierrick Charron 29
  • 30.
    Les fichiers demonextension $ tree monextension $ tree monextension ● Fichiers de configuration monextension/ 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.phpt 1 directory, 8 files 1 directory, 8 files Premiers pas dans les extensions - Pierrick Charron 30
  • 31.
    Config.m4 ● Script de configuration sous Linux ● Utilisé par ./buildconf et phpize dnl 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-monextension dnl --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-monextension dnl --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 test Premiers 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.php Premiers pas dans les extensions - Pierrick Charron 33
  • 34.
    php_monextension.h ● Déclaration des données pour la liaison statique Premiers 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 module Premiers pas dans les extensions - Pierrick Charron 35
  • 36.
    Définition du module ● Structure permettant à PHP d'initialiser ou de désinitialiser le module zend_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 fonctions constzend_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 fonction monextension.c const zend_function_entrymonextension_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.h PHP_FUNCTION(monextension_helloworld); PHP_FUNCTION(monextension_helloworld); Premiers pas dans les extensions - Pierrick Charron 38
  • 39.
    PHP_FUNCTION PHP_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_* n'interrompt pas l'exé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 fonction PHP_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 fonction intzend_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 d'un 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 impossible Premiers pas dans les extensions - Pierrick Charron 46
  • 47.
    Initialiser un tableau intarray_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é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; 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é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); $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éments int zend_hash_find(constHashTable *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éments int 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 d'une classe zend_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éthodes PHP_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, 1 TSRMLS_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, 0 TSRMLS_DC) TSRMLS_DC) RETURN_TRUE; RETURN_TRUE; }} Premiers pas dans les extensions - Pierrick Charron 53
  • 54.
    Quelques outils bienutiles ;) Premiers pas dans les extensions - Pierrick Charron 54
  • 55.
    Code compatible ZTS? Compilez toujours votre PHP avec --enable-maintainer-zts Premiers 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) Freeing 0x7FA54892B708 (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.php callers=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.net Premiers pas dans les extensions - Pierrick Charron 58
  • 59.
    Premiers pas dansles extensions - Pierrick Charron 59
  • 60.
    Premiers pas dansles 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:196 196 ../sysdeps/x86_64/strcpy_chk.S: No such file or directory.in ../sysdeps/x86_64/strcpy_chk.S 196 ../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 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
  • 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-X Premiers pas dans les extensions - Pierrick Charron 63
  • 64.
    Questions ? pierrick@php.net Twitter: @adoyy Commentaires et présentation : http://joind.in/2869 Premiers pas dans les extensions - Pierrick Charron 64