1ª PHP UnConference Brasil

    Desenvolvimento de
      extensões PECL
     Erick Belluci Tedeschi - @ericktedeschi




                        
Agenda

­ PHP LifeCycle
­ Estrutura ZVAL
­ Ambiente de Desenvolvimento (*nix)
­ ext_skel (Esqueleto de uma extensão)
­ API Zend
­ Aceitando parâmetros
­ Exemplo: Função recebendo parâmetro e retornando 
valor

* Live DEMO :­D



                            
PHP Page Life Cycle


     Ciclo de vida de uma requisição de página (script) PHP originada de um WebServer:



Processo do Apache                           Inicia WebServer
 LoadModule php5_module                      Carrega módulo do PHP
     mysql,sockets,curl,curses,etc...        PHP Carrega suas extensões (built­in e php.ini)

                  MINIT                      Carrega constantes, ini entries, resources, etc...

                   RINIT                     Inicializa autoglobals, symbol table, log, etc...

              Script Execution

               RSHUTDOWN                     Libera memória...

             MSHUTDOWN                       Libera memória... (ini entries, resources, etc...)


                                              
Estrutura ZVAL

typedef struct _zval_struct {   typedef union _zvalue_value {
    zvalue_value value;             long lval;   // Long,Bool,Resource
    zend_uint refcont;              double dval; // Double
    zend_uchar type;                struct {
    zend_uchar is_ref;                  char *val;
} zval;                                 long length;
                                    } str; // String
                                    HashTable *ht; // Array
                                    zend_object_value obj; // Object
                                } zvalue_value;
       IS_NULL
       IS_BOOL
       IS_LONG
       IS_DOUBLE
       IS_STRING
       IS_ARRAY
       IS_OBJECT
       IS_RESOURCE

                                    
Ambiente de Desenvolvimento (*nix)


 Requisitos necessários para compilar extensões:

 Ubuntu: m4 e build­essential

 ­ autoconf 2.13 (http://ftp.gnu.org/gnu/autoconf)

 ­ automake 1.4 (http://ftp.gnu.org/gnu/automake)

 ­ libtool 1.4.x+ (except 1.4.2) (http://ftp.gnu.org/gnu/libtool)

 ­ bison 1.28 (http://ftp.gnu.org/gnu/bison)

 ­ flex 2.5.4 (http://prdownloads.sourceforge.net/flex/flex­2.5.4a.tar.gz?download)

 ­ re2c 0.13.4+ (http://re2c.org)

 * Caso a extensão faça uso de alguma bilioteca externa, a mesma deve ser instalada:
 Libcurses­dev, libxml­dev, etc...
                                                    
Esqueleto da Extensão

Arquivos básicos que compõe a extensão:

Obrigatórios:

­ config.m4     ­ Arquivo de configuração *unix
­ config.w32   ­ Arquivo de configuração Windows
­ php_EXTNAME.h  ­ Cabeçalho (includes, structs, protótipo de funções, macros, etc...)
­ EXTNAME.c – Esqueleto da extensão e implementação das funções/classes

Opcionais:

­ CREDITS   ­ 1ª linha Nome da Extensão 2ª linha em diante nome dos colaboradores
­ EXPERIMENTAL  ­ Não estável
­ EXTNAME.php – Teste básico da extensão
­ tests – Diretório onde ficam os casos de teste escritos para a extensão

Obs.: EXTNAME é o nome da extensão criada


                                               
Esqueleto da Extensão


 Estrutura interna do código fonte de uma extensão:


     cabeçalho        Licença, Créditos, Descrição, etc...
     includes         API e bibliotecas externas
     funções          Funções existentes na extensão
     MINFO            Informações do módulo (phpinfo())
     MINIT            Tarefas a serem executadas ao carregar a extensão
     MSHUTDOWN        Libera memórias das tarefas executadas no MINIT
     RINIT            Tarefas a serem executadas na requisição do script PHP
     RSUTDOWN         Libera memória das tarefas executadas no RINIT
     function_entry   Registra as funções para a extensão
     module_entry     Entrada do módulo no PHP


                                                
Esqueleto da Extensão - Cabeçalho



/*
  +----------------------------------------------------------------------+
  | PHP Version 5                                                        |
  +----------------------------------------------------------------------+
  | Copyright (c) 1997-2008 The PHP Group                                |
  +----------------------------------------------------------------------+
  | This source file is subject to version 3.01 of the PHP license,      |
  | that is bundled with this package in the file LICENSE, and is        |
  | available through the world-wide-web at the following url:           |
  | http://www.php.net/license/3_01.txt                                  |
  | If you did not receive a copy of the PHP license and are unable to   |
  | obtain it through the world-wide-web, please send a note to          |
  | license@php.net so we can mail you a copy immediately.               |
  +----------------------------------------------------------------------+
  | Author: Fulano de Tal < fulano at tal dot com >                      |
  +----------------------------------------------------------------------+
*/

/* $Id: header 252479 2008-02-07 19:39:50Z iliaa $ */



                                             
Esqueleto da Extensão - Includes




        /* Créditos … */

        #ifdef HAVE_CONFIG_H
        #include "config.h"
        #endif

        #include   "php.h"
        #include   "php_ini.h"
        #include   "ext/standard/info.h"
        #include   "php_ssp.h"




                                
Esqueleto da Extensão - Funções

// Exemplo de funções definidas para o “user space”.
PHP_FUNCTION(mysql_connect)
{
    /* código da função */
}

PHP_FUNCTION(mysql_close)
{
    /* código da função */
}

// Exemplo da implementação de classes para o “user space”.
PHP_METHOD(Cachorro, __construct)
{
    /* código do construtor */
}

PHP_METHOD(Cachorro, latir)
{
    /* código do método */
}                                 
Esqueleto da Extensão - MINFO


static PHP_MINFO_FUNCTION(libxml)
{
    php_info_print_table_start();
    php_info_print_table_row(2, "libXML   support", "active");
    php_info_print_table_row(2, "libXML   Compiled Version", LIBXML_DOTTED_VERSION);
    php_info_print_table_row(2, "libXML   Loaded Version", (char *)xmlParserVersion);
    php_info_print_table_row(2, "libXML   streams", "enabled");
    php_info_print_table_end();
}




                                            
Esqueleto da Extensão -                MINIT/MSHUTDOWN




 PHP_MINIT_FUNCTION(extname)
 {
    REGISTER_INI_ENTRIES();
    return SUCCESS;
 }

 PHP_MSHUTDOWN_FUNCTION(extname)
 {
    UNREGISTER_INI_ENTRIES();
    return SUCCESS;
 }




                                    
Esqueleto da Extensão -            RINIT/RSHUTDOWN




         PHP_RINIT_FUNCTION(extname)
         {
            return SUCCESS;
         }


         PHP_RSHUTDOWN_FUNCTION(extname)
         {

             return SUCCESS;
         }




                                
Esqueleto da Extensão –                    Function Entry




const zend_function_entry extname_functions[] = {
    PHP_FE(extname_abrir, NULL)
    PHP_FE(extname_colar, NULL)
    PHP_FE(extname_recortar, NULL)
    {NULL, NULL, NULL} /* Must be the last line in extname_functions[] */
};




                                        
Esqueleto da Extensão –               Module Entry




zend_module_entry extname_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
   STANDARD_MODULE_HEADER,
#endif
   "extname",
   extname_functions,
   PHP_MINIT(extname),
   PHP_MSHUTDOWN(extname),
   PHP_RINIT(extname),
   PHP_RSHUTDOWN(extname),
   PHP_MINFO(extname),
#if ZEND_MODULE_API_NO >= 20010901
   "0.1", /* Replace with version number for your extension */
#endif
   STANDARD_MODULE_PROPERTIES
};

                                   
API ZEND – Manipulação ZVAL

Macros para manipulação de ZVAL

ZVAL_RESOURCE(zval, 234)
ZVAL_NULL(zval)
ZVAL_BOOL(zval, 1)
ZVAL_LONG(zval, 1234)
ZVAL_DOUBLE(zval, 34.5);
ZVAL_STRING(zval, “Fulano”, 0)
ZVAL_EMPTY_STRING(zval)
ZVAL_FALSE(zval) // = ZVAL_BOOL(zval, 0);
ZVAL_TRUE(zval) // = ZVAL_BOOL(zval, 1);

Macros para manipulação do valor de retorno da função

RETVAL_RESOURCE(234) // ZVAL_RESOURCE(return_value, 234)
RETVAL_BOOL(1) // = ZVAL_BOOL(return_value, 1)
RETVAL_NULL() // = ZVAL_NULL(return_value)
RETVAL_LONG(1234) // = ZVAL_LONG(return_value, 1234)
RETVAL_DOUBLE(34.5) // = ZVAL_DOUBLE(return_value, 34.5)
RETVAL_STRING(“Fulano”, 0) // = ZVAL_STRING(return_value, “Fulano”, 0)
RETVAL_FALSE
RETVAL_TRUE
                                    
etc...
API ZEND – Manipulação Arrays

PHP_FUNCTION(retorna_array)
{
   array_init(return_value);
   add_assoc_long(return_value, “Numero”, 1234);
   add_assoc_bool(return_value, “Verdade”, 1);
   add_assoc_double(return_value, “Peso”, 27.4);
}

<?php print_r(retorna_array()); ?>
Resultado
{
    [Numero] => 1234
    [Verdade] => 1
    [Peso] => 27.4
}


int add_assoc_long(zval *arg, char *key, long n);
int add_assoc_null(zval *arg, char *key);
int add_assoc_bool(zval *arg, char *key, int b);
int add_assoc_resource(zval *arg, char *key, int r);
int add_assoc_double(zval *arg, char *key, double d);
int add_assoc_string(zval *arg, char *key, char *str, int dup);
int add_assoc_stringl(zval *arg, char *key, char *str, uint len, int dup);
int   add_assoc_zval(zval *arg, char *key,   zval *value);
API ZEND – Manipulação Arrays


Adiciona com um número de índice específico

int   add_index_long(zval *arg, uint idx, long n);
int   add_index_null(zval *arg, uint idx);
int   add_index_bool(zval *arg, uint idx, int b);
int   add_index_resource(zval *arg, uint idx, int r);
int   add_index_double(zval *arg, uint idx, double d);
int   add_index_string(zval *arg, uint idx, char *str, int duplicate);
int   add_index_stringl(zval *arg, uint idx, char *str, uint length, int duplicate);
int   add_index_zval(zval *arg, uint idx, zval *value);

Adiciona no próximo índice

int   add_next_index_long(zval *arg, long n);
int   add_next_index_null(zval *arg);
int   add_next_index_bool(zval *arg, int b);
int   add_next_index_resource(zval *arg, int r);
int   add_next_index_double(zval *arg, double d);
int   add_next_index_string(zval *arg, char *str, int duplicate);
int   add_next_index_stringl(zval *arg, char *str, uint length, int duplicate);
int   add_next_index_zval(zval *arg, zval *value);

                                           
Aceitando Parâmetros

           Syntax: zend_parse_parameters(num_args, “format args”, &arg1, &arg2, ...)




l       Long       long *
d       double     double *
b       Boolean    zend_bool *
a       array      zval **
o       Object     zval **
O       Object     zval **, zend_class_Entry *
                   Força ser da classe/tipo determinada
s       String     char **, int *
                   Sempre recebe string e tamanho
r       resource   zval **
z       zval       zval **
Z       zval-ref   zval ***


|       Restante (parte direita) são opcionais
!       Proximo parametro retorna NULL se o tipo é IS_NULL
                                                
Aceitando Parâmetros – Exemplo 1



PHP_FUNCTION(exemplo1)
{
    /* Definição das variáveis */
    char *nome;
    int nome_len;

        /* Pegando os parâmetros */
        if (zend_parse_parameters(1 TSRMLS_CC, “s”, &nome, &nome_len) == FAILURE)
        {
            return;
        }

        /* Código da função... */
        php_printf(“Nome: %s”, nome);

        /* Retorno de valor */
        RETVAL_NULL;
}


                                           
Aceitando Parâmetros – Exemplo 2

PHP_FUNCTION(tipovar)
{
    /* Declaração das variáveis */
    zval *variavel;
    /* Recebendo parâmetros */
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &variavel)
                    == FAILURE) {
        return;
    }
    /* Código da função */
    switch (Z_TYPE_P(variavel)) {
         case IS_LONG:
             php_printf("Inteiron");
             break;
         case IS_ARRAY:
             php_printf("Matrizn");
             break;
         default:
             php_printf("Tipo desconhecidon");
             break;
    }

    /* Retorno de valor */
}                                        
Retornando Valor – Exemplo 3




           PHP_FUNCTION(numeroCao)
           {
               /* Declaração das variáveis */

               /* Recebendo parâmetros */

               /* Código da função */

               /* Retorno de valor */
               RETVAL_LONG(666);
           }




                               
Live DEMO




             
die()




        Erick Belluci Tedeschi ­ @ericktedeschi

        htp://itatux.blogspot.com
        http://oerick.com
        http://www.linkedin.com/in/ericktedeschi
                                  

Desenvolvimento de Extensões PECL

  • 1.
    1ª PHP UnConference Brasil Desenvolvimento de extensões PECL Erick Belluci Tedeschi - @ericktedeschi    
  • 2.
  • 3.
    PHP Page LifeCycle Ciclo de vida de uma requisição de página (script) PHP originada de um WebServer: Processo do Apache Inicia WebServer LoadModule php5_module Carrega módulo do PHP mysql,sockets,curl,curses,etc... PHP Carrega suas extensões (built­in e php.ini) MINIT Carrega constantes, ini entries, resources, etc... RINIT Inicializa autoglobals, symbol table, log, etc... Script Execution RSHUTDOWN Libera memória... MSHUTDOWN Libera memória... (ini entries, resources, etc...)    
  • 4.
    Estrutura ZVAL typedef struct_zval_struct { typedef union _zvalue_value { zvalue_value value; long lval; // Long,Bool,Resource zend_uint refcont; double dval; // Double zend_uchar type; struct { zend_uchar is_ref; char *val; } zval; long length; } str; // String HashTable *ht; // Array zend_object_value obj; // Object } zvalue_value; IS_NULL IS_BOOL IS_LONG IS_DOUBLE IS_STRING IS_ARRAY IS_OBJECT IS_RESOURCE    
  • 5.
    Ambiente de Desenvolvimento(*nix) Requisitos necessários para compilar extensões: Ubuntu: m4 e build­essential ­ autoconf 2.13 (http://ftp.gnu.org/gnu/autoconf) ­ automake 1.4 (http://ftp.gnu.org/gnu/automake) ­ libtool 1.4.x+ (except 1.4.2) (http://ftp.gnu.org/gnu/libtool) ­ bison 1.28 (http://ftp.gnu.org/gnu/bison) ­ flex 2.5.4 (http://prdownloads.sourceforge.net/flex/flex­2.5.4a.tar.gz?download) ­ re2c 0.13.4+ (http://re2c.org) * Caso a extensão faça uso de alguma bilioteca externa, a mesma deve ser instalada: Libcurses­dev, libxml­dev, etc...    
  • 6.
  • 7.
    Esqueleto da Extensão Estrutura interna do código fonte de uma extensão: cabeçalho Licença, Créditos, Descrição, etc... includes API e bibliotecas externas funções Funções existentes na extensão MINFO Informações do módulo (phpinfo()) MINIT Tarefas a serem executadas ao carregar a extensão MSHUTDOWN Libera memórias das tarefas executadas no MINIT RINIT Tarefas a serem executadas na requisição do script PHP RSUTDOWN Libera memória das tarefas executadas no RINIT function_entry Registra as funções para a extensão module_entry Entrada do módulo no PHP    
  • 8.
    Esqueleto da Extensão- Cabeçalho /* +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2008 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Fulano de Tal < fulano at tal dot com > | +----------------------------------------------------------------------+ */ /* $Id: header 252479 2008-02-07 19:39:50Z iliaa $ */    
  • 9.
    Esqueleto da Extensão- Includes /* Créditos … */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "php.h" #include "php_ini.h" #include "ext/standard/info.h" #include "php_ssp.h"    
  • 10.
    Esqueleto da Extensão- Funções // Exemplo de funções definidas para o “user space”. PHP_FUNCTION(mysql_connect) { /* código da função */ } PHP_FUNCTION(mysql_close) { /* código da função */ } // Exemplo da implementação de classes para o “user space”. PHP_METHOD(Cachorro, __construct) { /* código do construtor */ } PHP_METHOD(Cachorro, latir) { /* código do método */ }   
  • 11.
    Esqueleto da Extensão- MINFO static PHP_MINFO_FUNCTION(libxml) { php_info_print_table_start(); php_info_print_table_row(2, "libXML support", "active"); php_info_print_table_row(2, "libXML Compiled Version", LIBXML_DOTTED_VERSION); php_info_print_table_row(2, "libXML Loaded Version", (char *)xmlParserVersion); php_info_print_table_row(2, "libXML streams", "enabled"); php_info_print_table_end(); }    
  • 12.
    Esqueleto da Extensão- MINIT/MSHUTDOWN PHP_MINIT_FUNCTION(extname) { REGISTER_INI_ENTRIES(); return SUCCESS; } PHP_MSHUTDOWN_FUNCTION(extname) { UNREGISTER_INI_ENTRIES(); return SUCCESS; }    
  • 13.
    Esqueleto da Extensão- RINIT/RSHUTDOWN PHP_RINIT_FUNCTION(extname) { return SUCCESS; } PHP_RSHUTDOWN_FUNCTION(extname) { return SUCCESS; }    
  • 14.
    Esqueleto da Extensão– Function Entry const zend_function_entry extname_functions[] = { PHP_FE(extname_abrir, NULL) PHP_FE(extname_colar, NULL) PHP_FE(extname_recortar, NULL) {NULL, NULL, NULL} /* Must be the last line in extname_functions[] */ };    
  • 15.
    Esqueleto da Extensão– Module Entry zend_module_entry extname_module_entry = { #if ZEND_MODULE_API_NO >= 20010901 STANDARD_MODULE_HEADER, #endif "extname", extname_functions, PHP_MINIT(extname), PHP_MSHUTDOWN(extname), PHP_RINIT(extname), PHP_RSHUTDOWN(extname), PHP_MINFO(extname), #if ZEND_MODULE_API_NO >= 20010901 "0.1", /* Replace with version number for your extension */ #endif STANDARD_MODULE_PROPERTIES };    
  • 16.
    API ZEND –Manipulação ZVAL Macros para manipulação de ZVAL ZVAL_RESOURCE(zval, 234) ZVAL_NULL(zval) ZVAL_BOOL(zval, 1) ZVAL_LONG(zval, 1234) ZVAL_DOUBLE(zval, 34.5); ZVAL_STRING(zval, “Fulano”, 0) ZVAL_EMPTY_STRING(zval) ZVAL_FALSE(zval) // = ZVAL_BOOL(zval, 0); ZVAL_TRUE(zval) // = ZVAL_BOOL(zval, 1); Macros para manipulação do valor de retorno da função RETVAL_RESOURCE(234) // ZVAL_RESOURCE(return_value, 234) RETVAL_BOOL(1) // = ZVAL_BOOL(return_value, 1) RETVAL_NULL() // = ZVAL_NULL(return_value) RETVAL_LONG(1234) // = ZVAL_LONG(return_value, 1234) RETVAL_DOUBLE(34.5) // = ZVAL_DOUBLE(return_value, 34.5) RETVAL_STRING(“Fulano”, 0) // = ZVAL_STRING(return_value, “Fulano”, 0) RETVAL_FALSE RETVAL_TRUE     etc...
  • 17.
    API ZEND –Manipulação Arrays PHP_FUNCTION(retorna_array) { array_init(return_value); add_assoc_long(return_value, “Numero”, 1234); add_assoc_bool(return_value, “Verdade”, 1); add_assoc_double(return_value, “Peso”, 27.4); } <?php print_r(retorna_array()); ?> Resultado { [Numero] => 1234 [Verdade] => 1 [Peso] => 27.4 } int add_assoc_long(zval *arg, char *key, long n); int add_assoc_null(zval *arg, char *key); int add_assoc_bool(zval *arg, char *key, int b); int add_assoc_resource(zval *arg, char *key, int r); int add_assoc_double(zval *arg, char *key, double d); int add_assoc_string(zval *arg, char *key, char *str, int dup); int add_assoc_stringl(zval *arg, char *key, char *str, uint len, int dup); int   add_assoc_zval(zval *arg, char *key,   zval *value);
  • 18.
    API ZEND –Manipulação Arrays Adiciona com um número de índice específico int add_index_long(zval *arg, uint idx, long n); int add_index_null(zval *arg, uint idx); int add_index_bool(zval *arg, uint idx, int b); int add_index_resource(zval *arg, uint idx, int r); int add_index_double(zval *arg, uint idx, double d); int add_index_string(zval *arg, uint idx, char *str, int duplicate); int add_index_stringl(zval *arg, uint idx, char *str, uint length, int duplicate); int add_index_zval(zval *arg, uint idx, zval *value); Adiciona no próximo índice int add_next_index_long(zval *arg, long n); int add_next_index_null(zval *arg); int add_next_index_bool(zval *arg, int b); int add_next_index_resource(zval *arg, int r); int add_next_index_double(zval *arg, double d); int add_next_index_string(zval *arg, char *str, int duplicate); int add_next_index_stringl(zval *arg, char *str, uint length, int duplicate); int add_next_index_zval(zval *arg, zval *value);    
  • 19.
    Aceitando Parâmetros Syntax: zend_parse_parameters(num_args, “format args”, &arg1, &arg2, ...) l Long long * d double double * b Boolean zend_bool * a array zval ** o Object zval ** O Object zval **, zend_class_Entry * Força ser da classe/tipo determinada s String char **, int * Sempre recebe string e tamanho r resource zval ** z zval zval ** Z zval-ref zval *** | Restante (parte direita) são opcionais ! Proximo parametro retorna NULL se o tipo é IS_NULL    
  • 20.
    Aceitando Parâmetros –Exemplo 1 PHP_FUNCTION(exemplo1) { /* Definição das variáveis */ char *nome; int nome_len; /* Pegando os parâmetros */ if (zend_parse_parameters(1 TSRMLS_CC, “s”, &nome, &nome_len) == FAILURE) { return; } /* Código da função... */ php_printf(“Nome: %s”, nome); /* Retorno de valor */ RETVAL_NULL; }    
  • 21.
    Aceitando Parâmetros –Exemplo 2 PHP_FUNCTION(tipovar) { /* Declaração das variáveis */ zval *variavel; /* Recebendo parâmetros */ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &variavel) == FAILURE) { return; } /* Código da função */ switch (Z_TYPE_P(variavel)) { case IS_LONG: php_printf("Inteiron"); break; case IS_ARRAY: php_printf("Matrizn"); break; default: php_printf("Tipo desconhecidon"); break; } /* Retorno de valor */ }    
  • 22.
    Retornando Valor –Exemplo 3 PHP_FUNCTION(numeroCao) { /* Declaração das variáveis */ /* Recebendo parâmetros */ /* Código da função */ /* Retorno de valor */ RETVAL_LONG(666); }    
  • 23.
  • 24.
    die() Erick Belluci Tedeschi ­ @ericktedeschi htp://itatux.blogspot.com http://oerick.com http://www.linkedin.com/in/ericktedeschi