Desenvolvendo Extensões
- Discute como desenvolver extensões para o PHP, incluindo como gerar o esqueleto de uma extensão, compilá-la, lidar com tipos de dados, arrays, recursos, orientação a objetos e mais.
2. Hello World
- php, pear, pecl, linux, plesk, puppet...
- pecl.php.net/augeas
- spamassassin php api
- api api api api api api api api
- wordpress
3. Por que você está aqui?
(nesta sala, não no universo)
4. pecl
- php extension community library
- dizem que se lê “pickle”
- ou no brasil: “pê” “ê” (ou “é”) “cê” “éle”
5. 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
6. 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
13. 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
14. 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
15. compilando a extensão - linux
$ cd ext/minhaextensao
$ phpize
$ ./configure
$ make
$ (sudo) make install
“extension=minhaextensao.so” no php.ini
16. 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
18. 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
19. 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)
20. minhaextensao.c – module entry
essa estrutura vai armazenar todas as
informações sobre sua extensão
21. 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)
28. 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...
29. 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
33. 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...
51. arrays – lista de funções
Fonte: http://devzone.zend.com/node/view/id/1022#Heading5
52. 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);
53. daqui a pouco vamos discutir sobre
resource e objetos, guentaí
54. 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
55. retornando valores em funções
PHP_FUNCTION(minhaextensao_bool)
{
RETURN_TRUE;
php_error_docref(NULL TSRMLS_CC, E_WARNING,
"Nunca vai chegar aqui");
}
56. 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...
58. 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", ¶m, ¶m_len) == FAILURE) {
return;
}
php_printf("Obrigado por me passar como parametro: ");
PHPWRITE(param, param_len);
php_printf("n");
}
59. 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
64. 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;
65. 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;
}
66. 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)
67. 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;
}
68. 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
73. 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;
}
74. 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;
}
75. 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);
76. 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
77. 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