Criando funções na sua extensão PHP - Parte 04
Disponibilizar novas funções e classes para o usuário no phpland é a principal função de uma nova extensão. Adicionar essas novas funções ao core do PHP seria um trabalho gigantesco e complexo. Mesmo criando módulos, sem o Zend Engine, esse trabalho ainda seria complexo. Nesse post quero mostrar a parte divertida da coisa, e começar a fazer as coisas funcionarem, além de mostrar, o quão simples é criar uma nova função no PHP.
Disponibilizar novas funções e classes para o usuário no phpland é a principal função de uma nova extensão. Adicionar essas novas funções ao core do PHP seria um trabalho gigantesco e complexo. Mesmo criando módulos, sem o Zend Engine, esse trabalho ainda seria complexo. Nesse post quero mostrar a parte divertida da coisa, e começar a fazer as coisas funcionarem, alem de mostrar, o quão simples é criar uma nova função no PHP.
Toda função precisa ser registrada, e isso é feito na estrutura
Em seguida é passado o
Logo depois é passado os parâmetros,
Em seguida as
"Caramba, e você falou que era uma estrutura simples, como que vou registrar uma função ai?" Calma, lembra que eu falei da Zend Engine? ela é maravilhosa, e nos permite registrar funções através de macros.
Então vamos criar uma função
A macro faz todo o trabalho para nós, mas para você conhecer a estrutura criada pela macro, o código ficaria algo assim:
Você até pode compilar sua extensão já, e verá que temos 2 novas funções. Basta entrar no diretório e executar
Tudo compilado, vamos criar um arquivo test.php com o seguinte conteúdo:
Pessoal, gostaria de deixar um apelo ai para darem uma força. compartilhem, comentem, deixe seu comentário no post. quem escreve ou faz vídeo, muitas vezes nem faz isso por dinheiro, mas sim para engajar a comunidade de alguma forma. não gostou da forma que eu escrevo? comenta na boa (nem eu gosto também), mas comenta algo, manda pro brodi, bora crescer e centralizar um conteúdo de qualidade
Referencias: http://www.phpinternalsbook.com/php7/extensions_design/php_functions.html, https://github.com/php/php-src/blob/master/Zend/zend_API.h
Disponibilizar novas funções e classes para o usuário no phpland é a principal função de uma nova extensão. Adicionar essas novas funções ao core do PHP seria um trabalho gigantesco e complexo. Mesmo criando módulos, sem o Zend Engine, esse trabalho ainda seria complexo. Nesse post quero mostrar a parte divertida da coisa, e começar a fazer as coisas funcionarem, alem de mostrar, o quão simples é criar uma nova função no PHP.
Toda função precisa ser registrada, e isso é feito na estrutura
zend_function_entry, que já foi apresentada na parte 2 desse tutorial. Ela é uma estrutura de complexidade baixa, descrita como:
typedef struct _zend_function_entry {
const char *fname;
void (*handler)(INTERNAL_FUNCTION_PARAMETERS);
const struct _zend_internal_arg_info *arg_info;
uint32_t num_args;
uint32_t flags;
} zend_function_entry;
O primeiro campo, o fname, é formado pelo nome da sua função.
Em seguida é passado o
handler. Aqui é passado o ponteiro para a função C que representa sua função no phpland.
Logo depois é passado os parâmetros,
arg_infosendo um vetor de argumentos, e
num_argssendo o contador/quantidade de posições do vetor (acostumado com PHP né? em C tudo quanto é função que passa um vetor, precisa passar o tamanho também)
Em seguida as
flags, se indicará como static, public, final, protected, etc. Falaremos mais delas em um outro post.
"Caramba, e você falou que era uma estrutura simples, como que vou registrar uma função ai?" Calma, lembra que eu falei da Zend Engine? ela é maravilhosa, e nos permite registrar funções através de macros.
Então vamos criar uma função
myext_helloe
myext_test. Vou manter o prefixo
myext_para diferenciar das outras funções do PHP, já que minha extensão chama myext ok?
// Cria a função myext_hello
PHP_FUNCTION(myext_hello)
{
// Meu código C
}
// Cria a função myext_test
PHP_FUNCTION(myext_test)
{
// Meu código C
}
// Registra as funções para o phpland (mundo php)
static const zend_function_entry ext_functions[] = {
PHP_FE(myext_hello, NULL) // Registra a função myext_hello sem parametro
PHP_FE(myext_test, NULL) // Registra a função myext_test sem parametro
ZEND_FE_END
};
/**
* Configuração da nossa extensão
*/
extern zend_module_entry myext_module_entry;
zend_module_entry myext_module_entry = {
STANDARD_MODULE_HEADER, // Campos size, zend_api, zend_debug, zts, ini_entry e deps
"myext", // Nome da extensão
ext_functions, // <---- Funções da nossa extensão
PHP_MINIT(myext), // Função executada ao iniciar a extensão
PHP_MSHUTDOWN(myext), // Função executada ao finalizar a extensão
PHP_RINIT(myext), // Função executada ao iniciar o processamento
PHP_RSHUTDOWN(myext), // Função executada ao finalizar o processamento
PHP_MINFO(myext), // Função executada quando alguem pede informações da extensão
"0.0.1", // Versão da extensão
PHP_MODULE_GLOBALS(myext), // Macro para o tamanho da estrutura globais
PHP_GINIT(myext), // Inicializa os globais
PHP_GSHUTDOWN(myext), // Finaliza os globais,
NULL, // Função executada após-finalização da finalização do request
STANDARD_MODULE_PROPERTIES_EX // Campos globais e de controle interno
};
O que fizemos foi criar uma função utilizando a macro PHP_FUNCTION. Ela pegará o parâmetro e criará toda a estrutura interna necessária para colocar esse parâmetro como uma função no phpland (lado do usuário no php). Então com temos
PHP_FUNCTION(myext_hello), no php o usuário terá a função
myext_hello();.
A macro faz todo o trabalho para nós, mas para você conhecer a estrutura criada pela macro, o código ficaria algo assim:
void zif_myext_hello(zend_execute_data *execute_data, zval *return_value)
{
}
void zif_myext_test(zend_execute_data *execute_data, zval *return_value)
{
}
static const zend_function_entry pib_functions[] =
{
{
"myext_hello",
zif_myext_hello,
((void *) 0),
(uint32_t) (sizeof(((void *)0))/sizeof(struct _zend_internal_arg_info)-1),
0
},
{
"myext_test",
zif_myext_test,
((void *) 0),
(uint32_t) (sizeof(((void *)0))/sizeof(struct _zend_internal_arg_info)-1),
0
},
}
Complicado né? Note que tudo passado pelo parâmetro do PHP_FUNCTION, como por exemplo *myext_hello*, começa com o prefixo
zif_. Esse é o prefixo para Zend Internal Function. Tudo internamente possui zif.
zif_printf,
zif_var_dump, etc
Você até pode compilar sua extensão já, e verá que temos 2 novas funções. Basta entrar no diretório e executar
makenovamente, não precisa fazer o
phpize,
./configuree tudo mais não, só o
makepor enquanto ja compila novamente. Se você não se lembra de como fazer isso e quer lembrar, só precisa acessar o primeiro post dessa serie.
Tudo compilado, vamos criar um arquivo test.php com o seguinte conteúdo:
<?php
myext_hello();
myext_test();
e executar:$ php -d extension=./modules/myext.so test.php
Nossas funções não fazem nada, então tudo certo. Mas como tudo tem um "mas ...", se você está executando no PHP 8 verá 2 warnings:
Warning: Missing arginfo for myext_hello() in Unknown on line 0
Warning: Missing arginfo for myext_test() in Unknown on line 0
E aqui começa algumas mudanças do PHP 8. Agora a declaração do arginfo é requisito quase que obrigatório. Quase por que ele compila, mas ele se perde e não consegue tratar os argumentos, mesmo que esse argumento não exista. Então vamos falar mais sobre argumentos de função no próximo post.Pessoal, gostaria de deixar um apelo ai para darem uma força. compartilhem, comentem, deixe seu comentário no post. quem escreve ou faz vídeo, muitas vezes nem faz isso por dinheiro, mas sim para engajar a comunidade de alguma forma. não gostou da forma que eu escrevo? comenta na boa (nem eu gosto também), mas comenta algo, manda pro brodi, bora crescer e centralizar um conteúdo de qualidade
Referencias: http://www.phpinternalsbook.com/php7/extensions_design/php_functions.html, https://github.com/php/php-src/blob/master/Zend/zend_API.h