En esta segunda parte incluiremos el código necesario para que nuestra función haga su trabajo. Invertir una cadena o devolverla tal y como le ha llegado.
Una implementación en C para invertir una cadena podría ser esta (el código se presenta así con el proposito de ser claro, no óptimo)
#include
#include
char* reverseString(const char* str)
{
char* buffer;
int i=0;
buffer = (char*)malloc(strlen(str)*sizeof(char));
while(str[i]) buffer[strlen(str)-i++-1] = str[i];
return buffer;
}
int main(int argc,char** argv)
{
char* rstr;
rstr = (char*)reverseString("Hola mundo");
printf("%s\n",rstr);
free(rstr);
return(0);
}
Pues bien, habíamos dejado nuestra extensión en el directorio ext/dummy/ en donde podemos encontrar varios ficheros
config.m4 - reglas de configuración para \*nix
config.w32 - reglas de configuración para Güindow$
CREDITS - para meter el nombre de la extensión y tu nombre
EXPERIMENTAL - indica que la extensión es experimental
dummy.c - el código fuente de tu extensión
dummy.php - código de pruebas para tu extensión
Makefile.in - plantilla para el makefile
php_dummy.h - Cabecera para tu extensión
test/ - Directorio con las pruebas de regresión
Pasemos a editar dummy.c. Aunque esté lleno de código y marcaciones que pueden resultar extraños sólo debemos fijarnos en la estructura zend_module_entry llamada dummy_module_entry. Debemos sustituir PHP_RINIT(dummy) y PHP_RSHUTDOWN(dummy) por NULL pues no son necesarias para nuestra extensión. Se trata de código para inicializar o finalizar peticiones a la extensión. El código de la estructura se debe parecer a:
zend_module_entry dummy_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
STANDARD_MODULE_HEADER,
#endif
"dummy",
dummy_functions,
PHP_MINIT(dummy),
PHP_MSHUTDOWN(dummy),
NULL, /* Replace with NULL if there's nothing to do at request start */
NULL, /* Replace with NULL if there's nothing to do at request end */
PHP_MINFO(dummy),
#if ZEND_MODULE_API_NO >= 20010901
"0.1", /* Replace with version number for your extension */
#endif
STANDARD_MODULE_PROPERTIES
};
A continuación aparece comentado código para emplear valores propios de la extensión en las entradas de php.ini. Lo dejaremos como está, comentado, pues no las necesitaremos. Más abajo aparecen las implementaciones de MINIT(), MSHUTDOWN(), RINIT(), RSHUTDOWN() y MINFO(). Para MINIT() y MSHUTDOWN() sólo añadimos el código return SUCCESS; pues no queremos que hagan nada más. RINIT() y RSHUTDOWN() pueden ser borradas pero recuerda borrarlas también en el archivo de cabecera php_dummy.h
La función MINFO() se llama en la llamada a phpinfo() y en ella puedes añadir cualquier información que consideres relevante para la extensión.
Finalmente tenemos la función principal PHP_FUNCTION(dummy) donde agregaremos nuestro código adaptado:
/* {{{ proto string dummy(string msg, bool inv)
Devuelve la misma cadena enviada en orden normal o invertido */
PHP_FUNCTION(dummy)
{
char *msg = NULL;
int argc = ZEND_NUM_ARGS();
int msg_len;
zend_bool inv;
char *buffer = NULL;
int i=0;
if (zend_parse_parameters(argc TSRMLS_CC, "sb", &msg, &msg_len, &inv) == FAILURE)
return;
if(!inv) RETURN_STRINGL(msg, msg_len, 1);
buffer = (char*)malloc(strlen(msg)*sizeof(char));
while(msg[i]) buffer[strlen(msg)-i++-1] = msg[i];
RETURN_STRINGL(buffer, strlen(buffer), 1);
// php_error(E_WARNING, "dummy: not yet implemented");
}
/* }}} */
Antes de construir nuestra extensión debemos editar config.m4 para indicar como el usuario especificará que el módulo debe ser compilado en PHP. Estas líneas, comentadas por defecto, hacen justamente esto:
PHP_ARG_ENABLE(dummy, whether to enable dummy support,
[ --enable-dummy Enable dummy support])
Ahora existen 2 opciones a la hora de construir la extensión puedes hacerlo completamente independiente (standalone) y tu extensión será un módulo compartido cuya compilación será más rápida pero que necesitará ser habilitad desde php.ini para su carga o compilarla directamente en PHP que lleva más tiempo.
Para el modo independiente (standalone) debes ejecutar en el directorio de tu extensión el script phpsize que generará unos ficheros para configurar y construir tu extensión independientemente de PHP.
Luego sólo debes ejecutar:
$ ./configure
$ make
# make install
La extensión generada debería llamarse dummy.so y deberías copiarla al directorio donde php busca sus extensiones externas. Ahora debes precargar tu extensión desde php.ini mediante
extension=dummy.so
O desde el código de php directamente como:
dl('dummy.so');
Para la compilación dentro de PHP debes ejecutar en la raiz del código de PHP5
$ ./buildconf
Esto añadirá la opción --enable-dummy al script ./configure. Para probarlo ejecuta
$ ./configure --help
Ahora puedes construir PHP con:
$ ./configure --enable-dummy --enable-mysql=/usr/ ...
También puedes usar --enable-dummy=shared para forzar la compilación como librería compartida
¡Ya puedes probar tu extensión en tus scripts php!
<?php
var_dump(dummy('hola mundo',true));
?>
Una última consideración sobre memoria
La asignación de memoria dinámica es la causa principal de las perdidas de memoria (memory leaks). PHP dispone de funciones propias para la gestión de memoria dinámica. Estas funciones son:
emalloc()
efree()
estrdup()
estrndup()
ecalloc()
erealloc()
Que funcionan exactamente igual que sus contrapartidas en C. Estas funciones son seguras para evitar perdidas de memoria. Así que nuestra extensión tiene que sustituir la llama a malloc por emalloc. También debe ejecutar un efree por cada zona de memoria asignada con emalloc.





27/05/09 02:43:33
Extendiendo PHP (I)
Aunque la inmensa mayoría de las necesidades que plantea la programación en PHP se pueden resolver directamente con este lenguaje podemos encontrarnos con alguna necesidad muy especifica que nos obligue a extender las capacidades de PHP bien para agregar