Download - Dev Ext PHP

Transcript
Page 1: Dev Ext PHP

Desenvolvendo Extensões PECL

PHP Conference Brasil 201026 de novembro

Pedro Padron – [email protected] - @ppadron

Page 2: Dev Ext PHP

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: Dev Ext PHP

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

Page 4: Dev Ext PHP

pecl

- php extension community library

- dizem que se lê “pickle”

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

Page 5: Dev Ext PHP

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: Dev Ext PHP

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: Dev Ext PHP

modificar o comportamento do PHP

funcall

Page 8: Dev Ext PHP

zend extensions

- trabalham na camada da ZendEngine

- bytecode compiler

- opcode handlers

- exemplos: xdebug, test_handlers, ZendGuardLoader

Page 9: Dev Ext PHP

zend extensions

Page 10: Dev Ext PHP

php extensions

não faz nada do que uma zend extension faz

Page 11: Dev Ext PHP

montando o ambiente de trabalho

Page 12: Dev Ext PHP

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: Dev Ext PHP

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: Dev Ext PHP

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: Dev Ext PHP

compilando a extensão - linux

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

“extension=minhaextensao.so” no php.ini

Page 16: Dev Ext PHP

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: Dev Ext PHP

gerando o esqueleto de uma extensão

Page 18: Dev Ext PHP

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: Dev Ext PHP

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: Dev Ext PHP

minhaextensao.c – module entry

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

Page 21: Dev Ext PHP

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: Dev Ext PHP

minhaextensao.c - functions

E essa é a função!

Page 23: Dev Ext PHP

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: Dev Ext PHP

php_minhaextensao.h

- ZTS = Zend Thread Safety

- TSRM = Thread Safe Resource Manager

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

Page 25: Dev Ext PHP

config.m4

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

Page 26: Dev Ext PHP

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

Page 27: Dev Ext PHP

config.m4

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

Page 28: Dev Ext PHP

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: Dev Ext PHP

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: Dev Ext PHP

phpinfo(); - PHP_MINFO_FUNCTION

Page 31: Dev Ext PHP

phpinfo(); - PHP_MINFO_FUNCTION

Page 32: Dev Ext PHP

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: Dev Ext PHP

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: Dev Ext PHP

PHP_MINIT_FUNCTION

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

Page 35: Dev Ext PHP

PHP_RINIT_FUNCTION

- executado a cada requisição feita ao script

- evite inicializar muita coisa aqui, economize memória

Page 36: Dev Ext PHP

.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: Dev Ext PHP

.ini settings – declara, inicializa, destrói

Page 38: Dev Ext PHP

.ini settings – exibindo no phpinfo();

Page 39: Dev Ext PHP

.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: Dev Ext PHP

chega de enrolação, vamos trabalhar

Page 41: Dev Ext PHP

quantos tipos de dados existem no PHP?

Page 42: Dev Ext PHP

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

Page 43: Dev Ext PHP

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: Dev Ext PHP

preciso sempre mexer direto no ZVAL?

Page 45: Dev Ext PHP

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

Page 46: Dev Ext PHP

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

Page 47: Dev Ext PHP

arrays

Page 48: Dev Ext PHP

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: Dev Ext PHP

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: Dev Ext PHP

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: Dev Ext PHP

arrays – lista de funções

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

Page 52: Dev Ext PHP

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: Dev Ext PHP

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

Page 54: Dev Ext PHP

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: Dev Ext PHP

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: Dev Ext PHP

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: Dev Ext PHP

agora que sabemos como retornar valores, vamos receber valores

Page 58: Dev Ext PHP

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: Dev Ext PHP

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: Dev Ext PHP

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: Dev Ext PHP

recebendo valores opcionais

minhaextensao_recebe_string_opcional();// vejam: default

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

Page 62: Dev Ext PHP

zend_parse_parameters

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

Page 63: Dev Ext PHP

resources

Page 64: Dev Ext PHP

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: Dev Ext PHP

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: Dev Ext PHP

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: Dev Ext PHP

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: Dev Ext PHP

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: Dev Ext PHP

orientação a objetos

Page 70: Dev Ext PHP

estudo de caso: extensão augeas

Page 71: Dev Ext PHP

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: Dev Ext PHP

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: Dev Ext PHP

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: Dev Ext PHP

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: Dev Ext PHP

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: Dev Ext PHP

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: Dev Ext PHP

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: Dev Ext PHP

mas... e os métodos?

Page 79: Dev Ext PHP

quase igual funções...

Page 80: Dev Ext PHP
Page 81: Dev Ext PHP

AUGEAS_FROM_OBJECT ???getThis() ???

Page 82: Dev Ext PHP

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

Page 83: Dev Ext PHP

estamos de volta

Page 84: Dev Ext PHP

quer aprender mais?

Page 85: Dev Ext PHP

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

Page 86: Dev Ext PHP

leia o código alheio

Page 87: Dev Ext PHP

http://lxr.php.net/

php cross-referenced source code

Page 88: Dev Ext PHP

dúvidas?

Page 89: Dev Ext PHP

obrigado =)


Top Related