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