Top Banner
Desenvolvendo Extensões PECL PHP Conference Brasil 2010 26 de novembro Pedro Padron – [email protected] - @ppadron
89

Desenvolvendo Extensões PECL

Jan 24, 2015

Download

Technology

Palestra apresentada no PHP Conference Brasil 2010 sobre desenvolvimento de extensões PECL.
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Desenvolvendo Extensões PECL

Desenvolvendo Extensões PECL

PHP Conference Brasil 201026 de novembro

Pedro Padron – [email protected] - @ppadron

Page 2: Desenvolvendo Extensões PECL

Hello World

- php, pear, pecl, linux, plesk, puppet...

- pecl.php.net/augeas

- spamassassin php api

- api api api api api api api api

- wordpress

Page 3: Desenvolvendo Extensões PECL

Por que você está aqui?(nesta sala, não no universo)

Page 4: Desenvolvendo Extensões PECL

pecl

- php extension community library

- dizem que se lê “pickle”

- ou no brasil: “pê” “ê” (ou “é”) “cê” “éle”

Page 5: Desenvolvendo Extensões PECL

Motivos para criar uma extensão

- performance

- “esconder o código” do cliente

- acessar funções de uma biblioteca C

- modificar o comportamento do PHP

Page 6: Desenvolvendo Extensões PECL

acessar funções de uma biblioteca em C

"It is a glue language that glues the web server to all the interesting backend libraries available out there." *

Rasmus Lerdorf

* http://www.urgig.com/int/0107_rl_a_int.html

Page 7: Desenvolvendo Extensões PECL

modificar o comportamento do PHP

funcall

Page 8: Desenvolvendo Extensões PECL

zend extensions

- trabalham na camada da ZendEngine

- bytecode compiler

- opcode handlers

- exemplos: xdebug, test_handlers, ZendGuardLoader

Page 9: Desenvolvendo Extensões PECL

zend extensions

Page 10: Desenvolvendo Extensões PECL

php extensions

não faz nada do que uma zend extension faz

Page 11: Desenvolvendo Extensões PECL

montando o ambiente de trabalho

Page 12: Desenvolvendo Extensões PECL

montando o ambiente - linux

- debian/ubuntu:

apt-get install php5-dev (headers & phpize)

apt-get build-dep php5 (libs necessárias)

apt-get install php5-dbg (debug symbols)

- redhat/fedora:

yum install php5-dev

yum install yum-utils

yum-builddep php5

Page 13: Desenvolvendo Extensões PECL

montando o ambiente - windows

- sim, é possível; sim, é mais chato que no linux

- visual c++ 2008 (express edition é de graça)

- microsoft platform sdk

- várias bibliotecas necessárias pelo PHP

- variáveis de ambiente no console do visual studio

- processo completo: http://wiki.php.net/internals/windows/stepbystepbuild

Page 14: Desenvolvendo Extensões PECL

código fonte do PHP

- php.net/downloads

- 5.3.3

- extraia p/ algum diretório

- em windows, não use caminhos que contenham espaços

- cd php-src/ext

Page 15: Desenvolvendo Extensões PECL

compilando a extensão - linux

$ cd ext/minhaextensao$ phpize$ ./configure$ make$ (sudo) make install

“extension=minhaextensao.so” no php.ini

Page 16: Desenvolvendo Extensões PECL

compilando a extensão - windows

- siga todos os passos da etapa de setup do ambiente

- garanta que a extensão está no diretório ext/

- abra o Visual Studio Command Prompt

> vcvars32.bat> buildconf> configure –disable-all –enable-minhaextensao=shared –enable-cli> nmake

- dentro de Release_TS estará php_minhaextensao.dll

Page 17: Desenvolvendo Extensões PECL

gerando o esqueleto de uma extensão

Page 18: Desenvolvendo Extensões PECL

gerando o esqueleto de uma extensão

- é tão chato que foi preciso criar um script pra isso

- php-src/ext/ext_skel

- php-src/ext/ext_skel_win32.php* precisa de CygWin instalado* gera o arquivo .dsp do VisualStudio

Page 19: Desenvolvendo Extensões PECL

gerando o esqueleto de uma extensão

./ext_skel –extname=minhaextensao

.cvsignore (renomeie para .gitignore =P)

config.m4 (config script linux)

config.w32 (config script windows)

CREDITS (seu nome e seu e-mail)

EXPERIMENTAL (not for use in production)

minhaextensao.c (código da extensão)

minhaextensao.php (script de teste)

php_minhaextensao.h (headers)

tests/001.phpt (primeiro teste)

Page 20: Desenvolvendo Extensões PECL

minhaextensao.c – module entry

essa estrutura vai armazenar todas as informações sobre sua extensão

Page 21: Desenvolvendo Extensões PECL

minhaextensao.c - functions

Sim, a última linha tem sempre que ser {NULL, NULL, NULL}, isso indica para a Zend Engine que a lista de funções acabou.

Internamente, confirm_minha_extensao_compiled será chamada de zif_confirm_minhaextensao_compiled. (zif = zend internal function)

Page 22: Desenvolvendo Extensões PECL

minhaextensao.c - functions

E essa é a função!

Page 23: Desenvolvendo Extensões PECL

php_minhaextensao.h

extern zend_module_entry minhaextensao_module_entry;

PHP_MINIT_FUNCTION(minhaextensao);PHP_MSHUTDOWN_FUNCTION(minhaextensao);PHP_RINIT_FUNCTION(minhaextensao);PHP_RSHUTDOWN_FUNCTION(minhaextensao);PHP_MINFO_FUNCTION(minhaextensao);

PHP_FUNCTION(confirm_minhaextensao_compiled);

Declarando as funções e a definição do módulo

Page 24: Desenvolvendo Extensões PECL

php_minhaextensao.h

- ZTS = Zend Thread Safety

- TSRM = Thread Safe Resource Manager

#ifdef ZTS#include "TSRM.h"#endif

Page 25: Desenvolvendo Extensões PECL

config.m4

Se a sua extensão não usa nenhuma biblioteca externa:

Page 26: Desenvolvendo Extensões PECL

config.m4Se a sua extensão usa alguma biblioteca externa

Page 27: Desenvolvendo Extensões PECL

config.m4

Testando a biblioteca pela presença de algum símbolo

Page 28: Desenvolvendo Extensões PECL

config.m4

símbolos de uma biblioteca são todos os elementos visíveis ao seu usuário, podem ser classes, funções,

estruturas de dados, etc...

Page 29: Desenvolvendo Extensões PECL

bibliotecas externas – embutir ou linkar?

- em windows é preferível embutir a biblioteca externa, pois o usuário final só precisa instalar sua dll (php_minhaextensao.dll)

- em linux, verifique se as distribuições possuem pacotes para a biblioteca em questão;

- se for embutir, verifique se a licença da biblioteca permite isso

Page 30: Desenvolvendo Extensões PECL

phpinfo(); - PHP_MINFO_FUNCTION

Page 31: Desenvolvendo Extensões PECL

phpinfo(); - PHP_MINFO_FUNCTION

Page 32: Desenvolvendo Extensões PECL

phpinfo(); - PHP_MINFO_FUNCTION

não abuse da criatividade

void php_info_print_table_start(void)void php_info_print_table_end(void)void php_info_print_table_header(int cols, ...)void php_info_print_table_colspan_header(int cols, char *header)void php_info_print_table_row(int cols, ...)void php_info_print_table_row_ex(int cols, char *class, ...)void php_info_print_box_start(int flag)void php_info_print_box_end()void php_info_print_hr(void)...

Page 33: Desenvolvendo Extensões PECL

PHP_MINIT_FUNCTION

- executado uma vez para cada processo

- cli/cgi/multithread sapi => executa apenas uma vez (apache2-worker)

- sempre que houver fork(); inicia novamente o ambiente (mod_php no apache2-prefork)

- registrar classes, constantes, configurações php.ini...

Page 34: Desenvolvendo Extensões PECL

PHP_MINIT_FUNCTION

ppadron@delorean:$ php -r 'echo MINHAEXTENSAO_HELLO;'Hello World

Page 35: Desenvolvendo Extensões PECL

PHP_RINIT_FUNCTION

- executado a cada requisição feita ao script

- evite inicializar muita coisa aqui, economize memória

Page 36: Desenvolvendo Extensões PECL

.ini settings

- primeiro você declara as configs

- inicializa em PHP_MINIT_FUNCTION

- destrói em PHP_MINIT_SHUTDOWN

- exibe em PHP_MINFO_FUNCTION

Page 37: Desenvolvendo Extensões PECL

.ini settings – declara, inicializa, destrói

Page 38: Desenvolvendo Extensões PECL

.ini settings – exibindo no phpinfo();

Page 39: Desenvolvendo Extensões PECL

.ini settings – acessando os valores

/* VALORES ORIGINAIS */const char *strval = INI_ORIG_STR("minhaextensao.config");long lval = INI_ORIG_INT("minhaextensao.config_int");double dval = INI_ORIG_FLT("minhaextensao.config_float");zend_bool bval = INI_ORIG_BOOL("minhaextensao.config_bool");

/* VALORES ATUAIS */long lval = INI_INT("minhaextensao.config_int");double dval = INI_FLT("minhaextensao.config_float");zend_bool bval = INI_BOOL("minhaextensao.config_bool");

Page 40: Desenvolvendo Extensões PECL

chega de enrolação, vamos trabalhar

Page 41: Desenvolvendo Extensões PECL

quantos tipos de dados existem no PHP?

Page 42: Desenvolvendo Extensões PECL

por baixo dos panos, eles são representados por um só: o ZVAL

Page 43: Desenvolvendo Extensões PECL

struct { union { long lval; double dval; struct { char *val; int len; } str; HashTable *ht; zend_object_value obj; } value; zend_uint refcount; zend_uchar type; zend_uchar is_ref;} zval;

prazer, ZVAL.

Page 44: Desenvolvendo Extensões PECL

preciso sempre mexer direto no ZVAL?

Page 45: Desenvolvendo Extensões PECL

a não ser que você saiba o que está fazendo, não.

Page 46: Desenvolvendo Extensões PECL

existem diversas funções e macros para lidar com um ZVAL

Page 47: Desenvolvendo Extensões PECL

arrays

Page 48: Desenvolvendo Extensões PECL

PHP_FUNCTION(minhaextensao_me_da_um_array){ zval *meu_primeiro_array;

ALLOC_INIT_ZVAL(meu_primeiro_array);

array_init(meu_primeiro_array); array_init(return_value);

add_next_index_null(meu_primeiro_array); add_next_index_string(meu_primeiro_array, "ueeeba!!", 1);

/* uau */ add_next_index_zval(return_value, meu_primeiro_array);

}

arrays – minha primeira função

Page 49: Desenvolvendo Extensões PECL

arrays – minha primeira função

function minhaextensao_me_da_um_array(){ $meu_primeiro_array = array(); $retorno = array();

$meu_primeiro_array[] = null; $meu_primeiro_array[] = “ueeeba!!”;

$retorno[] = $meu_primeiro_array;

return $retorno;}

Page 50: Desenvolvendo Extensões PECL

arrays – minha primeira função

$ php -r 'var_dump(minhaextensao_me_da_um_array());'array(1) { [0]=> array(2) { [0]=> NULL [1]=> string(8) "ueeeba!!" }}

Page 51: Desenvolvendo Extensões PECL

arrays – lista de funções

Fonte: http://devzone.zend.com/node/view/id/1022#Heading5

Page 52: Desenvolvendo Extensões PECL

os outros tipos que não tem tanta graça

zval *meuzval;

ZVAL_NULL(meuzval);

ZVAL_LONG(meuzval, 1408);

/* bool usa o mesmo espaço de long */ZVAL_BOOL(meuzval, 1);

ZVAL_STRING(meuzval, “tchananan”, 0);

Page 53: Desenvolvendo Extensões PECL

daqui a pouco vamos discutir sobre resource e objetos, guentaí

Page 54: Desenvolvendo Extensões PECL

retornando valores em funções

- já vimos que existe um tal de return_value em algum lugar

- podemos manipular seu valor e deixar que o php o retorne

- ou podemos usar alguns atalhos

Page 55: Desenvolvendo Extensões PECL

retornando valores em funções

PHP_FUNCTION(minhaextensao_bool){ RETURN_TRUE; php_error_docref(NULL TSRMLS_CC, E_WARNING, "Nunca vai chegar aqui");}

Page 56: Desenvolvendo Extensões PECL

retornando os valores em funções

RETURN_NULL();RETURN_STRING(“bola”, 0);RETURN_TRUE;RETURN_FALSE;RETURN_DOUBLE(3.14);RETURN_LONG(1408);

e assim por diante...

Page 57: Desenvolvendo Extensões PECL

agora que sabemos como retornar valores, vamos receber valores

Page 58: Desenvolvendo Extensões PECL

recebendo valores em uma função

PHP_FUNCTION(minhaextensao_recebe_string){ char *param; int param_len;

if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &param, &param_len) == FAILURE) {

return; }

php_printf("Obrigado por me passar como parametro: "); PHPWRITE(param, param_len); php_printf("\n");}

Page 59: Desenvolvendo Extensões PECL

recebendo valores em uma função

minhaextensao_recebe_string("eba!");// Obrigado por me passar como parametro: eba!

minhaextensao_recebe_string();// PHP Warning: minhaextensao_recebe_string() expects exactly 1 parameter, 0 given

class bola { public function __toString() { return “bola”; }}

minhaextensao_recebe_string(new bola());// Obrigado por me passar como parametro: bola

Page 60: Desenvolvendo Extensões PECL

recebendo valores opcionais

PHP_FUNCTION(minhaextensao_recebe_string_opcional){ char *str = "default"; int str_len = sizeof("default") - 1;

if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &str, &str_len) == FAILURE) {

RETURN_FALSE; }

php_printf("vejam: "); PHPWRITE(str, str_len); php_printf("\n");}

Page 61: Desenvolvendo Extensões PECL

recebendo valores opcionais

minhaextensao_recebe_string_opcional();// vejam: default

minhaextensao_recebe_string_opcional(“bola”);// vejam: bola

Page 62: Desenvolvendo Extensões PECL

zend_parse_parameters

Fonte: http://devzone.zend.com/node/view/id/1022

Page 63: Desenvolvendo Extensões PECL

resources

Page 64: Desenvolvendo Extensões PECL

resources

- permite lidar com estruturas mais complexas em C e passá-las de um lado para o outro;

- inicializados em PHP_MINIT_FUNCTION;

- usado em extensões procedurais;

Page 65: Desenvolvendo Extensões PECL

resources – inicialização/destruição

/* isso está no topo do minhaextensao.c */static int le_minhaextensao;

static void php_minhaextensao_resource_destrutor(zend_rsrc_list_entry *rsrc TSRMLS_DC){ FILE *fp = (FILE *) rsrc->ptr; fclose(fp);}

PHP_MINIT_FUNCTION(minhaextensao){ le_minhaextensao = zend_register_list_destructors_ex( php_minhaextensao_resource_destrutor, NULL, "Resource da Minha Extensao", module_number);

return SUCCESS;}

Page 66: Desenvolvendo Extensões PECL

resources – criando e retornando

PHP_FUNCTION(minhaextensao_resource){ FILE *fp; fp = fopen("/tmp/arquivo", "r");

if (!fp) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Naaaaaao"); RETURN_FALSE; }

ZEND_REGISTER_RESOURCE(return_value, fp, le_minhaextensao);}

$ php -r 'var_dump(minhaextensao_resource());'resource(4) of type (Resource da Minha Extensao)

Page 67: Desenvolvendo Extensões PECL

resources – recebendo como parâmetro

PHP_FUNCTION(minhaextensao_resource_check){ FILE *fp; zval *resource;

if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &resource) == FAILURE) {

RETURN_NULL(); }

ZEND_FETCH_RESOURCE(fp, FILE*, &resource, -1, "Resource da Minha Extensao", le_minhaextensao);

if (!fp) { RETURN_FALSE; }

RETURN_TRUE;}

Page 68: Desenvolvendo Extensões PECL

resource – recebendo como parâmetro

$resource = minhaextensao_resource();$result = minhaextensao_resource_check($resource);

var_dump($result);

// bool(true)

$resource = curl_init();$result = minhaextensao_resource_check($resource);

var_dump($result);

// PHP Warning: minhaextensao_resource_check(): supplied resource is not a valid Resource da Minha Extensao resource

Page 69: Desenvolvendo Extensões PECL

orientação a objetos

Page 70: Desenvolvendo Extensões PECL

estudo de caso: extensão augeas

Page 71: Desenvolvendo Extensões PECL

declarando uma classe

/* {{{ zend_class_entry */zend_class_entry *augeas_ce_Augeas;/* }}} */

/* REFLECTION! *//* {{{ ZEND_BEGIN_ARG_INFO */ZEND_BEGIN_ARG_INFO_EX(arginfo_Augeas__construct, 0) ZEND_ARG_INFO(0, root) ZEND_ARG_INFO(0, loadpath) ZEND_ARG_INFO(0, flags)ZEND_END_ARG_INFO();

ZEND_BEGIN_ARG_INFO(arginfo_Augeas_get, 0) ZEND_ARG_INFO(0, path)ZEND_END_ARG_INFO();/* }}} */

Page 72: Desenvolvendo Extensões PECL

declarando uma classe – lista de métodos

/* {{{ augeas_methods */static zend_function_entry augeas_methods[] = { PHP_ME(Augeas, __construct, arginfo_Augeas__construct, ZEND_ACC_PUBLIC) PHP_ME(Augeas, get, arginfo_Augeas_get, ZEND_ACC_PUBLIC) PHP_ME(Augeas, set, arginfo_Augeas_set, ZEND_ACC_PUBLIC) PHP_ME(Augeas, match, arginfo_Augeas_match, ZEND_ACC_PUBLIC) PHP_ME(Augeas, rm, arginfo_Augeas_rm, ZEND_ACC_PUBLIC) PHP_ME(Augeas, save, arginfo_Augeas_save, ZEND_ACC_PUBLIC) PHP_ME(Augeas, mv, arginfo_Augeas_mv, ZEND_ACC_PUBLIC) PHP_ME(Augeas, insert, arginfo_Augeas_insert, ZEND_ACC_PUBLIC) { NULL, NULL, NULL }};/* }}} */

ZEND_ACC_PUBLICZEND_ACC_PROTECTEDZEND_ACC_PRIVATE

ZEND_ACC_STATICZEND_ACC_ABSTRACTZEND_ACC_FINAL

Page 73: Desenvolvendo Extensões PECL

declarando uma classe - inicialização

PHP_MINIT_FUNCTION(augeas){ zend_class_entry ce;

/* Register Augeas class */ INIT_CLASS_ENTRY(ce, "Augeas", augeas_methods); augeas_ce_Augeas = zend_register_internal_class(&ce TSRMLS_CC);

return SUCCESS;}

Page 74: Desenvolvendo Extensões PECL

declarando uma classe – inicialização (namespace)

PHP_MINIT_FUNCTION(augeas){ zend_class_entry ce;

/* Register Augeas class */ INIT_NS_CLASS_ENTRY(ce, “Augeas”, "Augeas", augeas_methods); augeas_ce_Augeas = zend_register_internal_class(&ce TSRMLS_CC);

return SUCCESS;}

Page 75: Desenvolvendo Extensões PECL

declarando uma classe - herança

/* Register AugeasException class (inherits Exception) */INIT_CLASS_ENTRY(ce, "AugeasException", NULL);

augeas_ce_AugeasException = zend_register_internal_class_ex( &ce_exception, zend_exception_get_default(TSRMLS_C), NULL TSRMLS_DC);

Page 76: Desenvolvendo Extensões PECL

Declarando uma classe - 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_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);

Créditos: Erick Tedeschi

Page 77: Desenvolvendo Extensões PECL

declarando uma classe - 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_string(zend_class_entry *ce, char *name, size_t name_len, char *value TSRMLS_DC);

Créditos: Erick Tedeschi

Page 78: Desenvolvendo Extensões PECL

mas... e os métodos?

Page 79: Desenvolvendo Extensões PECL

quase igual funções...

Page 80: Desenvolvendo Extensões PECL
Page 81: Desenvolvendo Extensões PECL

AUGEAS_FROM_OBJECT ???getThis() ???

Page 82: Desenvolvendo Extensões PECL

vamos dar um tempo aqui e ir logo para os arquivos...

Page 83: Desenvolvendo Extensões PECL

estamos de volta

Page 84: Desenvolvendo Extensões PECL

quer aprender mais?

Page 85: Desenvolvendo Extensões PECL

compre o livro da Sara Golemon“Extending and Embedding PHP”

Page 86: Desenvolvendo Extensões PECL

leia o código alheio

Page 87: Desenvolvendo Extensões PECL

http://lxr.php.net/

php cross-referenced source code

Page 88: Desenvolvendo Extensões PECL

dúvidas?

Page 89: Desenvolvendo Extensões PECL

obrigado =)