Upload
erick-belluci-tedeschi
View
970
Download
1
Embed Size (px)
Citation preview
Desenvolvimento de extensões PECL
Erick Belluci Tedeschi - @ericktedeschi
PHPSC Conference 2010
Agenda
O que é PECL? Motivação 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 C com OOP?
* Live DEMO :D
Quem é Erick Tedeschi?
Conheceu PHP em 2003
Analista de Segurança da Informação
Doctrine (extensão PECL classe Lexer)
Motociclista
Obs.: ..ñ é Takashi, Takeshi, Takeushi..É TEDESCHI
O que é PECL?
PHP Extension and Application Repository
O que é PECL?
PHP Extension and Application Repository
PHP Extension Community Library
PHP Extension and Application Repository
PHP Extension Community Library
O que é PECL?
← Escrito em PHP
← Escrito em “C”
Motivação!!! heee
Aumento de performance
Adicionar novas funcionalidades
Embarcar PHP
PHP Page Life Cycle
Processo do Apache
LoadModule php5_module
mysql,sockets,curl,curses,etc...
MINIT
RINIT
Script Execution
RSHUTDOWN
MSHUTDOWN
Inicia WebServer
Carrega módulo do PHP
PHP Carrega suas extensões (builtin e php.ini)
Carrega constantes, ini entries, resources, etc...
Inicializa autoglobals, symbol table, log, etc...
Libera memória...
Libera memória... (ini entries, resources, etc...)
Ciclo de vida de uma requisição de página (script) PHP originada de um WebServer:
Estrutura ZVAL
typedef struct _zval_struct { zvalue_value value; zend_uint refcont; zend_uchar type; zend_uchar is_ref;} zval;
typedef union _zvalue_value { long lval; // Long,Bool,Resource double dval; // Double struct { char *val; long length; } str; // String HashTable *ht; // Array zend_object_value obj; // Object} zvalue_value;
IS_NULLIS_BOOLIS_LONGIS_DOUBLEIS_STRINGIS_ARRAYIS_OBJECTIS_RESOURCE
Ambiente de Desenvolvimento (*nix)
Requisitos necessários para compilar extensões:
Ubuntu: m4 e buildessential
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/flex2.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 serInstalada: Libcursesdev, libxmldev, etc...
Esqueleto da Extensão – Arquivos
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
Obs.: EXTNAME é o nome da extensão criada
Arquivos básicos que compõe a extensão:
Opcionais:
CREDITS 1ª linha Nome da Extensão, 2ª linha em diante nome dos colaboradores
EXPERIMENTAL Não estável. Conteúdo: observação sobre o que está instável ou o que pode ser alterado.
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 – Arquivos
Script: ext_skel
fulano@machine:/home/dev/php-5.3/ext$ ./ext_skel –extname=phpscfulano@machine:/home/dev/php-5.3/ext$ cd phpscfulano@machine:/home/dev/php-5.3/ext/phpsc$ ls -lh
-rw-r--r-- 1 kirex kirex 2,0K 2010-08-28 10:25 config.m4-rw-r--r-- 1 kirex kirex 289 2010-08-28 10:25 config.w32-rw-r--r-- 1 kirex kirex 5 2010-08-28 10:25 CREDITS-rw-r--r-- 1 kirex kirex 0 2010-08-28 10:25 EXPERIMENTAL-rw-r--r-- 1 kirex kirex 2,8K 2010-08-28 10:25 php_phpsc.h-rw-r--r-- 1 kirex kirex 5,1K 2010-08-28 10:25 phpsc.c-rw-r--r-- 1 kirex kirex 499 2010-08-28 10:25 phpsc.phpdrwxr-xr-x 2 kirex kirex 4,0K 2010-08-28 10:25 tests
O script ext_skel fica localizado dentro do diretório “ext” na raiz do source do PHP.
A extensão gerada é uma cópia dos arquivos do diretório “ext/skeleton”, substituindo apenas o nome da extensão definida no parâmetro “extname” do script ext_skel.
API – Macros e mais macros de macros!
Com macros (menor margem para erros):
zval *nome = NULL;ALLOC_ZVAL(nome);ZVAL_STRING(nome, “Cássia”, 0);
Sem macros (maior margem para erros):
zval *nome = NULL;nome = (zval *)emalloc(sizeof(zval));(*nome).value.str.len = strlen(“Cássia”);(*nome).value.str.value = estrndup(“Cássia”, strlen(“Cássia”);(*nome).type = 6; /* IS_STRING */
Esqueleto da Extensão – config.m4
PHP_ARG_ENABLE(EXTNAME, Whether to enable the EXTNAME extension,[ --enable-EXTNAME Enable extension description ])
If test $PHP_EXTNAME != “no”; then PHP_NEW_EXTENSION(EXTNAME, EXTNAME.c, $ext_shared)fi
Obs.: Sempre que alterar o config.m4, executar o phpize para gerar novamente o script “configure” e outros arquivos que são utilizados para compilar a extensão.
Esqueleto da Extensão – php_EXTNAME.h
#ifndef PHP_EXTNAME_H/* Prevent double inclusion */#define PHP_EXTNAME_H
/* Define extension properties */#define PHP_EXTNAME_NAME “Extension Name for Minfo”#define PHP_EXTNAME_VER “1.0”
/* Import configure options when building outside Of the PHP source tree */#ifdef HAVE_CONFIG_H#include “config.h”#endif
/* Include PHP standard header */#include “php.h”
/* Define the entry point symbol. Zend will use when loading this module */extern zend_module_entry extname_module_entry;#define phpext_EXTNAME_ptr &extname_module_entry
#endif /* PHP_EXTNAME_H */
Esqueleto da Extensão - EXTNAME.c
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
Estrutura do arquivo “.c”:
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 | | [email protected] 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_EXTNAME.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 */}
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 - MINFO
Esqueleto da Extensão - MINIT/MSHUTDOWN
PHP_MINIT_FUNCTION(extname){
REGISTER_INI_ENTRIES();return SUCCESS;
}
PHP_MSHUTDOWN_FUNCTION(extname){
UNREGISTER_INI_ENTRIES();return SUCCESS;
}
PHP_RINIT_FUNCTION(extname){
return SUCCESS;}
PHP_RSHUTDOWN_FUNCTION(extname){
return SUCCESS;}
Esqueleto da Extensão - RINIT/RSHUTDOWN
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", /* Version number for your extension */
#endifSTANDARD_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_FALSERETVAL_TRUEetc...
API ZEND – Manipulação Arrays
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);
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}
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 determinadas String char **, int * Sempre recebe string e tamanhor 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){ /* 1 - Definição das variáveis */ char *nome; int nome_len; /* 2 - Pegando os parâmetros */ if (zend_parse_parameters(1 TSRMLS_CC, “s”, &nome, &nome_len) == FAILURE) { return; } /* 3 - Implementação da função... */ php_printf(“Nome: %s”, nome); /* 4 - Retorno de valor */ RETVAL_NULL;}
Em PHP (User Space):
<?php exemplo1(“Cássia”); ?>
Resultado:
Nome: Cássia
Aceitando Parâmetros – Exemplo 2
PHP_FUNCTION(meu_gettype){ /* 1 - Declaração das variáveis */
zval *variavel; /* 2 - Recebendo parâmetros */ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &variavel) == FAILURE) {
return; } /* 3 - Implementação da função */ switch (Z_TYPE_P(variavel)) { case IS_LONG: php_printf("Inteiro"); break; case IS_ARRAY: php_printf("Matriz"); break; default: php_printf("Tipo desconhecido"); break; } /* 4 - Retorno de valor */}
Em PHP (User Space):
<?phpmeu_gettype(array(2,2));?>
Resultado:
Matriz
Retornando Valor – Exemplo 3
PHP_FUNCTION(numeroCao){ /* 1 - Declaração das variáveis */
/* 2 - Recebendo parâmetros */
/* 3 - Implementação da função */
/* 4 - Retorno de valor */ RETVAL_LONG(666);}
Definição de Classe - phpsc.c
/* Arquivo phpsc.c */zend_class_entry *phpsc_pessoa_ce;/* Declaração de métodos */const zend_function_entry phpsc_pessoa_functions[] = {
ZEND_ME(phpscPessoa, “__construct”, NULL, ZEND_ACC_PUBLIC)ZEND_ME(phpscPessoa, “getNome”, NULL, ZEND_ACC_PUBLIC)ZEND_ME(phpscPessoa, “getVersion”, NULL, ZEND_ACC_STATIC){NULL, NULL, NULL}
};/* Declaração da classe */PHP_MINIT_FUNCTION(EXTNAME){ zend_class_entry ce; INIT_NS_CLASS_ENTRY(ce, “phpsc”, “Pessoa”, phpsc_pessoa_functions); phpsc_pessoa_ce = zend_register_internal_class(&ce TSRMLS_CC);
/* Definindo propriedades */ zend_declare_property_null(phpsc_pessoa_ce, “_nome”, sizeof(“_nome”)-1, \ ZEND_ACC_PUBLIC TSRMLS_CC); zend_declare_property_long(phpsc_pessoa_ce, “_idade”, sizeof(“_idade”)-1, \
ZEND_ACC_PRIVATE TSRMLS_CC);}
/* Implementação dos métodos */PHP_METHOD(phpscPessoa, __construct)...
Definição de Classe - phpsc.c
/* Implementação dos métodos */PHP_METHOD(phpscPessoa, __construct){ php_printf(“Construtor chamado! rá!\r\n”);}
PHP_METHOD(phpscPessoa, getNome){ zval *nome = NULL; nome = zend_read_property(phpsc_pessoa_ce, getThis(), “_nome”, \ sizeof(“_nome”)-1, 0 TSRMLS_CC); RETVAL_STRING(Z_STRVAL_P(nome), 1);}
Definição de Classe - php_phpsc.h
/* Arquivo php_phpsc.h */
/* ... */
/* Declaração dos protótipos */
PHP_METHOD(phpscPessoa, __construct);PHP_METHOD(phpscPessoa, getNome);PHP_METHOD(phpscPessoa, getVersion);
/* ... */
Macros/Funcs OOP - Constantes
int zend_declare_class_constant(zend_class_entry *ce, char *name, size_t name_len, zval *value TSRMLS_DC);
int zend_declare_class_constant_long(zend_class_entry *ce, char *name, size_t name_len, long value TSRMLS_DC);
int zend_declare_class_constant_bool(zend_class_entry *ce, char *name, size_t name_len, zend_bool value TSRMLS_DC);
int zend_declare_class_constant_double(zend_class_entry *ce, char *name, size_t name_len, double value TSRMLS_DC);
int zend_declare_class_constant_stringl(zend_class_entry *ce, char *name, size_t name_len, char *val, size_t val_len TSRMLS_DC);
int zend_declare_class_constant_string(zend_class_entry *ce, char *name, size_t name_len, char *value TSRMLS_DC);
Obs.: Usar sizeof para passar o argumento name_len.
Macros/Funcs OOP - Propriedades
int zend_declare_property(zend_class_entry *ce, char *name, int name_length, zval *property, int access_type TSRMLS_DC);
int zend_declare_property_null(zend_class_entry *ce, char *name, int name_length, int access_type TSRMLS_DC);
int zend_declare_property_bool(zend_class_entry *ce, char *name, int name_length, long value, int access_type TSRMLS_DC);
int zend_declare_property_long(zend_class_entry *ce, char *name, int name_length, long value, int access_type TSRMLS_DC);
int zend_declare_property_double(zend_class_entry *ce, char *name, int name_length, double value, int access_type TSRMLS_DC);
int zend_declare_property_string(zend_class_entry *ce, char *name, int name_length, char *value, int access_type TSRMLS_DC);
zval *zend_read_property(zend_class_entry *scope, zval *object, char *name, int name_length, zend_bool silent TSRMLS_DC);
Live DEMO
Referência
Livros
Advanced PHP Programming Autor: George Schlossnagle ISBN10: 0672325616
Extending and Embedding PHP Autor: Sara Golemon ISBN#067232704X
Apresentações Marcus Börger http://talks.somabo.de
die()
Erick Belluci Tedeschi @ericktedeschi
http://oerick.comhttp://www.linkedin.com/in/ericktedeschi
Grupo PHPBRInternalshttp://groups.google.com/group/phpbrinternals