Este documento apresenta uma palestra sobre desenvolvimento de extensões para o PHP. Resume os tópicos principais: 1) Ciclo de vida de uma requisição PHP; 2) Estrutura interna de variáveis ZVAL; 3) Ambiente de desenvolvimento para extensões no Linux; 4) Esqueleto básico de uma extensão PHP com arquivos e estrutura necessários.
3. 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 (builtin 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...)
5. 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 ser instalada:
Libcursesdev, libxmldev, etc...
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 $ */
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 */
}
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);
}