:: Interfaces de scripting para librerías en C ::

:: CIISA 2008 ::

Interfaces de scripting para librerías en C
Moisés H. Silva

CIISA 2008

1
:: Interfaces de scripting para librerías en C ::

1. Lenguajes de scripting

:: CIISA 2008 ::

Agenda para C en PHP
2. Interfaces

* Funcionamiento.

* ¿Por qué?

* Ventajas y desventajas.

* Extensiones.

* PHP, PERL, Python.

* Zend Engine.

3. Construcción de una Extensión PHP
* Estructuras de registro.
* Variables.
* Funciones.
* Clases.
* Compilación.

2
:: Interfaces de scripting para librerías en C ::

:: CIISA 2008 ::

Agenda
4. SWIG (Simplified Wrapper and Interface Generator)
* Funcionamiento general

3
:: Interfaces de scripting para librerías en C ::

:: CIISA 2008 ::

[Lenguajes de scripting]

Funcionamiento
:: Los lenguajes de scripting son comunmente conocidos como interpretados.
:: El intérprete es un programa que se encarga de parsear y ejecutar las instrucciones
indicadas en el script (código del programa).
:: A diferencia de los lenguajes compilados, el lenguaje de scripting siempre depende
de su interprete para poder ser ejecutado.
:: Comunmente son menos estrictos con los tipos de datos y las operaciones que se
pueden realizar entre los distintos tipos de variables. Son dinámicos.

4
:: Interfaces de scripting para librerías en C ::

:: CIISA 2008 ::

[Lenguajes de scripting]

Funcionamiento

5
:: Interfaces de scripting para librerías en C ::

:: CIISA 2008 ::

[Lenguajes de scripting]

Ventajas
:: Manejo de memoria automático.
:: Tiempo de desarrollo mucho menor comparado con lenguajes compilados.
:: La curva de aprendizaje es menos pronunciada.
:: Amplio espectro de bibliotecas/librerías usualmente disponibles con el interprete.
:: Alto nivel de portabilidad.

6
:: Interfaces de scripting para librerías en C ::

:: CIISA 2008 ::

[Lenguajes de scripting]

Desventajas
:: Baja eficiencia. (Tiempo de ejecución prolongado)
:: Usualmente limitados al universo de funcionalidad proveido por el intérprete y
sus extensiones.
:: Bugs que usualmente pueden ser encontrados en tiempo de compilación ahora
pueden esconderse hasta su ejecución.
:: Código fuente usualmente expuesto (no necesariamente una desventaja).

7
:: Interfaces de scripting para librerías en C ::

:: CIISA 2008 ::

[Lenguajes de scripting]

PHP, PERL y Python
:: Son 3 de los lenguajes de scripting más usados, particularmente en Linux.
:: Sus intérpretes son de fuente abierta (open source).
:: Todos han sido usados para aplicaciones web con éxito.
:: Soportan orientación a objetos.
:: Se encuentran soportados por el generador de interfaces SWIG.

8
:: Interfaces de scripting para librerías en C ::

:: CIISA 2008 ::

[Lenguajes de scripting]

PHP
:: Creado por Rasmus Lerdof a mediados de los 90.
:: Inicio como una serie de CGIs en C para generar páginas web de forma dinámica.
:: PHP evolucionó de forma desorganizada por mucho tiempo.
:: La compañia Zend le ha dado forma al lenguaje para ser más robusto.
:: Soporta código estructurado y orientado a objetos.
:: Su sintaxis es muy similar a C++ con algunas ideas tomadas de Java.
:: Aunque su fuerte es la creación de sitios web, puede ser usado como de
propósito general.
9
:: Interfaces de scripting para librerías en C ::

:: CIISA 2008 ::

[Lenguajes de scripting]

PERL
:: Creado por Larry Wall a finales de los 80.
:: Lenguaje de scripting de propósito general.
:: Muy popular sobre todo en Linux para la automatización de tareas en servidores.
:: Al igual que PHP ha ido evolucionando y agregando nuevas características como
la orientación a objetos.
:: Siempre expone muchas formas de hacer la misma tarea.
:: La sintaxis puede llegar a ser muy extraña.

10
:: Interfaces de scripting para librerías en C ::

:: CIISA 2008 ::

[Lenguajes de scripting]

Python
:: Escrito por Guido van Rossum a principios de los 90.
:: Su modelo de programación es principalmente orientado a objetos.
:: Programación estructurada y funcional también soportadas en menor medida.
:: Curiosamente usa los “tabs” para definir bloques de código.

11
:: Interfaces de scripting para librerías en C ::

:: CIISA 2008 ::

[Interfaces en C para PHP]

¿Por qué?
:: Soportar funcionalidad solo disponible en librerías en C/C++
:: Exponer interfaces mas simples y/u orientadas a objetos a los usuarios.
:: Mejorar el performance de tus scripts.
:: Distribuir módulos de funcionalidad sin código fuente.

12
:: Interfaces de scripting para librerías en C ::

:: CIISA 2008 ::

[Interfaces en C para PHP]

Extensiones
:: Las extensiones de PHP son shared object's o DLL's que exponen funcionalidad
no disponible en el core de PHP.
:: Al iniciar, el core de PHP carga las extensiones requeridas por el script de entrada.
:: Las extensiones proveen de su funcionalidad a través de funciones, clases,
constantes etc.
:: Cada extensión es responsable de sus recursos. El usuario de la extensión
no tiene porque preocuparse de la liberación de recursos.

13
:: Interfaces de scripting para librerías en C ::

:: CIISA 2008 ::

[Interfaces en C para PHP]

Extensiones

14
:: Interfaces de scripting para librerías en C ::

:: CIISA 2008 ::

[Interfaces en C para PHP]

Zend Engine
:: El Zend Engine es lo que se conoce como el core de PHP.
:: Se encarga del manejo de memoria y toda la funcionalidad básica
de un intérprete.
:: Las extensiones pueden ser cargadas por el ZE ó compiladas de forma interna.
:: El ZE lleva a cabo el manejo de los ciclos de vida de las extensiones y
los scripts.

15
:: Interfaces de scripting para librerías en C ::

:: CIISA 2008 ::

[Interfaces en C para PHP]

Zend Engine
:: El ciclo de vida de una extensión de PHP se compone de 5 etapas:
-> Inicialización: El proceso donde habita el core es iniciado.
-> Activación: Cada vez que la extensión es usada por un nuevo script.
-> Ejecución: El script hace uso de la funcionalidad de la extensión.
-> Desactivación: El script finalizó.
-> Finalización: El proceso donde habita el core está siendo terminado.

16
:: Interfaces de scripting para librerías en C ::

:: CIISA 2008 ::

[Interfaces en C para PHP]

Zend Engine
:: El ZE expone APIs a sus extensiones para:
-> Manejo de memoria.
-> Creación y manipulación de variables.
-> Reference counting.
-> Consulta de las configuraciones del INI.
-> Registro de clases y funciones.
-> Obtención y retorno de variables de “user space”
17
:: Interfaces de scripting para librerías en C ::

:: CIISA 2008 ::

[Interfaces en C para PHP]

Zend Engine
:: Dentro de ambiente del ZE, existen 2 tipos de memoria:
-> Memoria persistente o no manejada.
-> Memoria de request o manejada.
:: La memoria persistente es aquella no manejada por el ZE, como
aquella memoria solicitada via malloc y por funciones ajenas al ZE.
:: La memoria de request o manejada es aquella solicitada por APIs
del ZE como emalloc(), ecalloc(), erealloc(), estrdup() etc.
:: La memoria de request o manejada solo persiste durante un hit de
una página web.
18
:: Interfaces de scripting para librerías en C ::

:: CIISA 2008 ::

[Interfaces en C para PHP]

Zend Engine
:: El I/O de datos también es controlado por el ZE.
:: El ZE expone algunas API para la salida de datos:
-> PHP_API int printf(const char *format, ...)
-> PHP_API int php_body_write(const char *str, uint str_length TSRMLS_DC)
-> ZEND_API int zend_print_variable(zval *var)
:: El uso directo de stdout debe ser evitado, sobretodo cuando php está corriendo
en un ambiente web debido a que la salida en realidad la salida usualmente
es dirigida por el ZE a la interfaz del servidor web.

19
:: Interfaces de scripting para librerías en C ::

:: CIISA 2008 ::

[Construcción de una extensión PHP]

Estructuras de registro
:: El ZE carga las extensiones usando información obtenida de una
estructura llamada zend_module_entry.
:: zend_module_entry define datos generales de la extensión:
-> Nombre de la extensión.
-> Lista de funciones y sus manejadores.
-> Apuntadores a funciones de inicialización y destrucción.
-> Versión del módulo.
-> Otras propiedades generales ...
20
:: Interfaces de scripting para librerías en C ::

:: CIISA 2008 ::

[Construcción de una extensión PHP]

Estructuras de registro

21
:: Interfaces de scripting para librerías en C ::

:: CIISA 2008 ::

[Construcción de una extensión PHP]

Estructuras de registro
:: Las funciones de inicialización (MINIT) y destrucción (MSHUTDOWN)
de módulo son llamadas una sola vez en la vida de la extensión.
:: Durante MINIT se deben registrar las clases, constantes y demás
funcionalidad que será expuesta al usuario.
:: Durante MSHUTDOWN deben liberarse los recursos que pudieran
haber sido solicitados en MINIT.
:: La declaración de MINIT y MSHUTDOWN se hace a través de macros:
PHP_MINIT_FUNCTION(helloext){}
PHP_MSHUTDOWN_FUNCTION(helloext){}
:: Los macros generan el prototipo apropiado, como:
int zm_startup_helloext(int type, int module_number TSRMLS_DC)

22
:: Interfaces de scripting para librerías en C ::

:: CIISA 2008 ::

[Construcción de una extensión PHP]

Estructuras de registro
:: Las funciones de inicialización (RINIT) y destrucción (RSHUTDOWN)
de request son llamadas una vez por request.
:: Durante RINIT se deben solicitar los recursos que no permanecen
durante requests.
:: Durante RSHUTDOWN deben liberarse los recursos que fueron
solicitados durante la ejecución del script, como conexiones a BD no
persistentes.
:: La declaración de RINIT y RSHUTDOWN se hace a través de macros:
PHP_RINIT_FUNCTION(helloext){}
PHP_RSHUTDOWN_FUNCTION(helloext){}
:: Los macros generan el prototipo apropiado, como:
int zm_activate_helloext(int type, int module_number TSRMLS_DC)

23
:: Interfaces de scripting para librerías en C ::

:: CIISA 2008 ::

[Construcción de una extensión PHP]

Variables
:: Para los usuarios de PHP una variable puede cambiar de tipo
de forma dinámica sin problema alguno.
$variable = array('uno', 'dos');
print $variable[0];
$variable = 10;
print $variable;
:: PHP soporta los tipos Integer, Float, String, Boolean, Array, Object,
Resource y NULL
:: Internamente una variable es representada por la estructura zval.
:: zval contiene la información necesaria para determinar el tipo de
la variable, su valor, si es una referencia y cuantas referencias
hay hacia la variable (reference counting).
24
:: Interfaces de scripting para librerías en C ::

:: CIISA 2008 ::

[Construcción de una extensión PHP]

Variables

25
:: Interfaces de scripting para librerías en C ::

:: CIISA 2008 ::

[Construcción de una extensión PHP]

Variables
:: Internamente, un statement como $var = “valor”; resulta en un zval con:
.type = 6; /* macro IS_STRING */
.value.str = { val = “valor”; len = 5; }
.is_ref = 0;
.refcount = 1;
:: Al reasignar $var = array(“valor”);, el mismo zval se usa y se modifica su tipo:
.type = 4; /* macro IS_ARRAY */
.value.ht = <direccion de memoria de un hash table>
:: Las propiedades del zval cambian conforme al flujo del script.
:: Todas las extensiones recibirán zvals representando variables del usuario.
26
:: Interfaces de scripting para librerías en C ::

:: CIISA 2008 ::

[Construcción de una extensión PHP]

Funciones
:: Las funciones de PHP internamente son prefijadas con zif_ y
reciben parámetros estandar.
:: El macro PHP_FUNCTION ayuda en la definición del prototipo.
:: La definición resultante es:
void zif_nombrefuncion(int ht, zval *return_value,
zval **return_value_ptr,
zval *this_ptr,
int return_value_used TSRMLS_DC,
void ***tsrm_ls);

27
:: Interfaces de scripting para librerías en C ::

:: CIISA 2008 ::

[Construcción de una extensión PHP]

Funciones
:: El macro PHP_FUNCTION recibe como argumento el nombre
de la función que deseamos exportar.
PHP_FUNCTION(suma)
:: El cuerpo de la función usualmente consta de:
-> Recepción y parseo de argumentos con zend_parse_parameters()
-> Proceso específico de la función.
-> Retorno de un valor mediante los macros RETURN_XXX()

28
:: Interfaces de scripting para librerías en C ::

:: CIISA 2008 ::

[Construcción de una extensión PHP]

Funciones
:: zend_parse_parameters es necesario para tomar los argumentos
del stack del ZE.
:: zend_parse_parameters recibe el número de argumentos a parsear, sus
tipos (mediante una cadena de formato) y los apuntadores a la memoria
a utilizar para guardarlos.
int op1, op2;
zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
“ll”, &op1, &op2);
:: El valor de retorno FAILURE significa que el parseo falló y usualmente
debe ser causal para mandar un error con zend_throw_exception o
WRONG_PARAM_COUNT

29
:: Interfaces de scripting para librerías en C ::

:: CIISA 2008 ::

[Construcción de una extensión PHP]

Funciones
:: La cadena de formato puede contener los valores:
s -> el valor esperado es un string. Debemos proveer char ** e int*
b -> booleano. Proveer zend_bool*
l -> long. Proveer long*
r, a, o, z -> resource, array, object, opaco. Proveer zval*

30
:: Interfaces de scripting para librerías en C ::

:: CIISA 2008 ::

[Construcción de una extensión PHP]

Funciones
:: Para regresar un valor de la función debe usarse:
RETURN_RESOURCE, RETURN_LONG, RETURN_BOOL etc.
:: RETURN_STRING es especial, debe indicarse si el buffer del string
debe ser duplicado o no por el ZE. El segundo parámetro del macro
lo indica.
RETURN_STRING(“Buffer Permanente”, 1);
RETURN_STRING(variable_local, 0);

31
:: Interfaces de scripting para librerías en C ::

:: CIISA 2008 ::

[Construcción de una extensión PHP]

Funciones
PHP_FUNCTION(suma)
{
long op1; op2;
if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
"ll", &op1, &op2)) {
return;
}
RETURN_LONG((op1 + op2));
}

32
:: Interfaces de scripting para librerías en C ::

:: CIISA 2008 ::

[Construcción de una extensión PHP]

Funciones

:: TSRMLS == Thread Safe Resource Manager Local Storage
:: Necesario para crear scope “global” por thread.
:: Existen muchos macros variantes para facilitar pasar este
storage de un lado a otro.

33
:: Interfaces de scripting para librerías en C ::

:: CIISA 2008 ::

[Construcción de una extensión PHP]

Clases
:: El ZE está escrito en C por lo que internamente las clases
de PHP están definidas como estructuras y apuntadores
a funciones.
:: Una declaración en user space de una clase tiene la forma:
class ClaseEnPhp {}
:: Internamente tal clase tendría que registrarse usando una estructura
zend_class_entry y la función zend_register_internal_class.
:: El equivalente a una declaración de clase en user space es:
zend_class_entry ce;
INIT_CLASS_ENTRY(ce, “ClaseEnPhp”, NULL);
zend_register_internal_class(&ce TSRML_CC);
:: El registro de clases desde una extensión debe ser hecho en MINIT

34
:: Interfaces de scripting para librerías en C ::

:: CIISA 2008 ::

[Construcción de una extensión PHP]

Clases
:: La implementación de un método de una varía poco de la de una
función común.
:: El macro PHP_METHOD es usado en lugar de PHP_FUNCTION.
PHP_METHOD(PrimerMetodo)
{
// cuerpo del método
}
:: Características adicionales para el método como visibilidad y
definición de argumentos son especificadas a través de la
estructura zend_function_entry y el macro PHP_ME
zend_function_entry ClaseEnPhp_methods[] = {
PHP_ME(ClaseEnPhp, PrimerMetodo, NULL, ZEND_ACC_PUBLIC);
};
35
:: Interfaces de scripting para librerías en C ::

:: CIISA 2008 ::

[Construcción de una extensión PHP]

Clases
:: La implementación de un método de una varía poco de la de una
función común.
:: El macro PHP_METHOD es usado en lugar de PHP_FUNCTION.
PHP_METHOD(PrimerMetodo)
{
// cuerpo del método
}
:: Características adicionales para el método como visibilidad y
definición de argumentos son especificadas a través de la
estructura zend_function_entry y el macro PHP_ME
zend_function_entry ClaseEnPhp_methods[] = {
PHP_ME(ClaseEnPhp, PrimerMetodo, NULL, ZEND_ACC_PUBLIC);
};
36
:: Interfaces de scripting para librerías en C ::

:: CIISA 2008 ::

[Construcción de una extensión PHP]

Compilación
:: La compilación en Linux se lleva a cabo mediante un comando
incluido con la distribución de PHP: “phpize”
:: Antes de correr phpize se necesita crear config.m4, un script que
determinará opciones de tiempo de compilación como la ubicación
de librerías externas.
:: Una vez creado config.m4 se procede a ejecutar phpize
# phpize
:: Finalmente igual que cualquier otro paquete basado en GNU autotools
se instala mediante:
# ./configure
# make && make install
37
:: Interfaces de scripting para librerías en C ::

:: CIISA 2008 ::

[SWIG]

Funcionamiento General
:: SWIG es un generador del pegamento necesario para juntar
código en C/C++ con lenguajes de más alto nivel como PHP,
PERL, Python, Java etc.
:: SWIG recibe como entrada un archivo especial que define las
interfaces en C/C++ para generar código fuente que puede ser
compilado para crear módulos del lenguaje deseado.
:: Una archivo de interfaz puede ser facilmente escrito incluyendo
el header donde declaras tus funciones C/C++:
%module milibreria
%{
#include “milibreria.h”
%}
38
:: Interfaces de scripting para librerías en C ::

:: CIISA 2008 ::

[SWIG]

Funcionamiento General
:: El archivo de interfaz se usa como entrada para SWIG.
# swig -perl milibreria.i
:: SWIG genera un archivo milibreria_wrap.c que funcionará
como interfaz hacia PERL.
:: Se compila la interfaz.
# gcc -c milibreria.c milibreria_wrap.c `perl -MextUtils::Embed -e ccopts`
:: Se enlaza la libreria con el wrapper de perl.
# ld -G milibreria.o milibreria_wrap.o -o milibreriaperl.so

39
:: Interfaces de scripting para librerías en C ::

:: CIISA 2008 ::

Referencias.
http://www.hardened-php.net/
http://devzone.zend.com/
http://www.php.net/
http://www.swig.org/
http://www.php.net/internals2.ze1.zendapi

40
:: Interfaces de scripting para librerías en C ::

:: CIISA 2008 ::

Gracias.
Moisés Humberto Silva Salmerón
http://www.moythreads.com//
moises.silva@gmail.com
moyhu@mx1.ibm.commoyhu@mx1.ibm.com

41

Interfaces de Scripting para librerias en C

  • 1.
    :: Interfaces descripting para librerías en C :: :: CIISA 2008 :: Interfaces de scripting para librerías en C Moisés H. Silva CIISA 2008 1
  • 2.
    :: Interfaces descripting para librerías en C :: 1. Lenguajes de scripting :: CIISA 2008 :: Agenda para C en PHP 2. Interfaces * Funcionamiento. * ¿Por qué? * Ventajas y desventajas. * Extensiones. * PHP, PERL, Python. * Zend Engine. 3. Construcción de una Extensión PHP * Estructuras de registro. * Variables. * Funciones. * Clases. * Compilación. 2
  • 3.
    :: Interfaces descripting para librerías en C :: :: CIISA 2008 :: Agenda 4. SWIG (Simplified Wrapper and Interface Generator) * Funcionamiento general 3
  • 4.
    :: Interfaces descripting para librerías en C :: :: CIISA 2008 :: [Lenguajes de scripting] Funcionamiento :: Los lenguajes de scripting son comunmente conocidos como interpretados. :: El intérprete es un programa que se encarga de parsear y ejecutar las instrucciones indicadas en el script (código del programa). :: A diferencia de los lenguajes compilados, el lenguaje de scripting siempre depende de su interprete para poder ser ejecutado. :: Comunmente son menos estrictos con los tipos de datos y las operaciones que se pueden realizar entre los distintos tipos de variables. Son dinámicos. 4
  • 5.
    :: Interfaces descripting para librerías en C :: :: CIISA 2008 :: [Lenguajes de scripting] Funcionamiento 5
  • 6.
    :: Interfaces descripting para librerías en C :: :: CIISA 2008 :: [Lenguajes de scripting] Ventajas :: Manejo de memoria automático. :: Tiempo de desarrollo mucho menor comparado con lenguajes compilados. :: La curva de aprendizaje es menos pronunciada. :: Amplio espectro de bibliotecas/librerías usualmente disponibles con el interprete. :: Alto nivel de portabilidad. 6
  • 7.
    :: Interfaces descripting para librerías en C :: :: CIISA 2008 :: [Lenguajes de scripting] Desventajas :: Baja eficiencia. (Tiempo de ejecución prolongado) :: Usualmente limitados al universo de funcionalidad proveido por el intérprete y sus extensiones. :: Bugs que usualmente pueden ser encontrados en tiempo de compilación ahora pueden esconderse hasta su ejecución. :: Código fuente usualmente expuesto (no necesariamente una desventaja). 7
  • 8.
    :: Interfaces descripting para librerías en C :: :: CIISA 2008 :: [Lenguajes de scripting] PHP, PERL y Python :: Son 3 de los lenguajes de scripting más usados, particularmente en Linux. :: Sus intérpretes son de fuente abierta (open source). :: Todos han sido usados para aplicaciones web con éxito. :: Soportan orientación a objetos. :: Se encuentran soportados por el generador de interfaces SWIG. 8
  • 9.
    :: Interfaces descripting para librerías en C :: :: CIISA 2008 :: [Lenguajes de scripting] PHP :: Creado por Rasmus Lerdof a mediados de los 90. :: Inicio como una serie de CGIs en C para generar páginas web de forma dinámica. :: PHP evolucionó de forma desorganizada por mucho tiempo. :: La compañia Zend le ha dado forma al lenguaje para ser más robusto. :: Soporta código estructurado y orientado a objetos. :: Su sintaxis es muy similar a C++ con algunas ideas tomadas de Java. :: Aunque su fuerte es la creación de sitios web, puede ser usado como de propósito general. 9
  • 10.
    :: Interfaces descripting para librerías en C :: :: CIISA 2008 :: [Lenguajes de scripting] PERL :: Creado por Larry Wall a finales de los 80. :: Lenguaje de scripting de propósito general. :: Muy popular sobre todo en Linux para la automatización de tareas en servidores. :: Al igual que PHP ha ido evolucionando y agregando nuevas características como la orientación a objetos. :: Siempre expone muchas formas de hacer la misma tarea. :: La sintaxis puede llegar a ser muy extraña. 10
  • 11.
    :: Interfaces descripting para librerías en C :: :: CIISA 2008 :: [Lenguajes de scripting] Python :: Escrito por Guido van Rossum a principios de los 90. :: Su modelo de programación es principalmente orientado a objetos. :: Programación estructurada y funcional también soportadas en menor medida. :: Curiosamente usa los “tabs” para definir bloques de código. 11
  • 12.
    :: Interfaces descripting para librerías en C :: :: CIISA 2008 :: [Interfaces en C para PHP] ¿Por qué? :: Soportar funcionalidad solo disponible en librerías en C/C++ :: Exponer interfaces mas simples y/u orientadas a objetos a los usuarios. :: Mejorar el performance de tus scripts. :: Distribuir módulos de funcionalidad sin código fuente. 12
  • 13.
    :: Interfaces descripting para librerías en C :: :: CIISA 2008 :: [Interfaces en C para PHP] Extensiones :: Las extensiones de PHP son shared object's o DLL's que exponen funcionalidad no disponible en el core de PHP. :: Al iniciar, el core de PHP carga las extensiones requeridas por el script de entrada. :: Las extensiones proveen de su funcionalidad a través de funciones, clases, constantes etc. :: Cada extensión es responsable de sus recursos. El usuario de la extensión no tiene porque preocuparse de la liberación de recursos. 13
  • 14.
    :: Interfaces descripting para librerías en C :: :: CIISA 2008 :: [Interfaces en C para PHP] Extensiones 14
  • 15.
    :: Interfaces descripting para librerías en C :: :: CIISA 2008 :: [Interfaces en C para PHP] Zend Engine :: El Zend Engine es lo que se conoce como el core de PHP. :: Se encarga del manejo de memoria y toda la funcionalidad básica de un intérprete. :: Las extensiones pueden ser cargadas por el ZE ó compiladas de forma interna. :: El ZE lleva a cabo el manejo de los ciclos de vida de las extensiones y los scripts. 15
  • 16.
    :: Interfaces descripting para librerías en C :: :: CIISA 2008 :: [Interfaces en C para PHP] Zend Engine :: El ciclo de vida de una extensión de PHP se compone de 5 etapas: -> Inicialización: El proceso donde habita el core es iniciado. -> Activación: Cada vez que la extensión es usada por un nuevo script. -> Ejecución: El script hace uso de la funcionalidad de la extensión. -> Desactivación: El script finalizó. -> Finalización: El proceso donde habita el core está siendo terminado. 16
  • 17.
    :: Interfaces descripting para librerías en C :: :: CIISA 2008 :: [Interfaces en C para PHP] Zend Engine :: El ZE expone APIs a sus extensiones para: -> Manejo de memoria. -> Creación y manipulación de variables. -> Reference counting. -> Consulta de las configuraciones del INI. -> Registro de clases y funciones. -> Obtención y retorno de variables de “user space” 17
  • 18.
    :: Interfaces descripting para librerías en C :: :: CIISA 2008 :: [Interfaces en C para PHP] Zend Engine :: Dentro de ambiente del ZE, existen 2 tipos de memoria: -> Memoria persistente o no manejada. -> Memoria de request o manejada. :: La memoria persistente es aquella no manejada por el ZE, como aquella memoria solicitada via malloc y por funciones ajenas al ZE. :: La memoria de request o manejada es aquella solicitada por APIs del ZE como emalloc(), ecalloc(), erealloc(), estrdup() etc. :: La memoria de request o manejada solo persiste durante un hit de una página web. 18
  • 19.
    :: Interfaces descripting para librerías en C :: :: CIISA 2008 :: [Interfaces en C para PHP] Zend Engine :: El I/O de datos también es controlado por el ZE. :: El ZE expone algunas API para la salida de datos: -> PHP_API int printf(const char *format, ...) -> PHP_API int php_body_write(const char *str, uint str_length TSRMLS_DC) -> ZEND_API int zend_print_variable(zval *var) :: El uso directo de stdout debe ser evitado, sobretodo cuando php está corriendo en un ambiente web debido a que la salida en realidad la salida usualmente es dirigida por el ZE a la interfaz del servidor web. 19
  • 20.
    :: Interfaces descripting para librerías en C :: :: CIISA 2008 :: [Construcción de una extensión PHP] Estructuras de registro :: El ZE carga las extensiones usando información obtenida de una estructura llamada zend_module_entry. :: zend_module_entry define datos generales de la extensión: -> Nombre de la extensión. -> Lista de funciones y sus manejadores. -> Apuntadores a funciones de inicialización y destrucción. -> Versión del módulo. -> Otras propiedades generales ... 20
  • 21.
    :: Interfaces descripting para librerías en C :: :: CIISA 2008 :: [Construcción de una extensión PHP] Estructuras de registro 21
  • 22.
    :: Interfaces descripting para librerías en C :: :: CIISA 2008 :: [Construcción de una extensión PHP] Estructuras de registro :: Las funciones de inicialización (MINIT) y destrucción (MSHUTDOWN) de módulo son llamadas una sola vez en la vida de la extensión. :: Durante MINIT se deben registrar las clases, constantes y demás funcionalidad que será expuesta al usuario. :: Durante MSHUTDOWN deben liberarse los recursos que pudieran haber sido solicitados en MINIT. :: La declaración de MINIT y MSHUTDOWN se hace a través de macros: PHP_MINIT_FUNCTION(helloext){} PHP_MSHUTDOWN_FUNCTION(helloext){} :: Los macros generan el prototipo apropiado, como: int zm_startup_helloext(int type, int module_number TSRMLS_DC) 22
  • 23.
    :: Interfaces descripting para librerías en C :: :: CIISA 2008 :: [Construcción de una extensión PHP] Estructuras de registro :: Las funciones de inicialización (RINIT) y destrucción (RSHUTDOWN) de request son llamadas una vez por request. :: Durante RINIT se deben solicitar los recursos que no permanecen durante requests. :: Durante RSHUTDOWN deben liberarse los recursos que fueron solicitados durante la ejecución del script, como conexiones a BD no persistentes. :: La declaración de RINIT y RSHUTDOWN se hace a través de macros: PHP_RINIT_FUNCTION(helloext){} PHP_RSHUTDOWN_FUNCTION(helloext){} :: Los macros generan el prototipo apropiado, como: int zm_activate_helloext(int type, int module_number TSRMLS_DC) 23
  • 24.
    :: Interfaces descripting para librerías en C :: :: CIISA 2008 :: [Construcción de una extensión PHP] Variables :: Para los usuarios de PHP una variable puede cambiar de tipo de forma dinámica sin problema alguno. $variable = array('uno', 'dos'); print $variable[0]; $variable = 10; print $variable; :: PHP soporta los tipos Integer, Float, String, Boolean, Array, Object, Resource y NULL :: Internamente una variable es representada por la estructura zval. :: zval contiene la información necesaria para determinar el tipo de la variable, su valor, si es una referencia y cuantas referencias hay hacia la variable (reference counting). 24
  • 25.
    :: Interfaces descripting para librerías en C :: :: CIISA 2008 :: [Construcción de una extensión PHP] Variables 25
  • 26.
    :: Interfaces descripting para librerías en C :: :: CIISA 2008 :: [Construcción de una extensión PHP] Variables :: Internamente, un statement como $var = “valor”; resulta en un zval con: .type = 6; /* macro IS_STRING */ .value.str = { val = “valor”; len = 5; } .is_ref = 0; .refcount = 1; :: Al reasignar $var = array(“valor”);, el mismo zval se usa y se modifica su tipo: .type = 4; /* macro IS_ARRAY */ .value.ht = <direccion de memoria de un hash table> :: Las propiedades del zval cambian conforme al flujo del script. :: Todas las extensiones recibirán zvals representando variables del usuario. 26
  • 27.
    :: Interfaces descripting para librerías en C :: :: CIISA 2008 :: [Construcción de una extensión PHP] Funciones :: Las funciones de PHP internamente son prefijadas con zif_ y reciben parámetros estandar. :: El macro PHP_FUNCTION ayuda en la definición del prototipo. :: La definición resultante es: void zif_nombrefuncion(int ht, zval *return_value, zval **return_value_ptr, zval *this_ptr, int return_value_used TSRMLS_DC, void ***tsrm_ls); 27
  • 28.
    :: Interfaces descripting para librerías en C :: :: CIISA 2008 :: [Construcción de una extensión PHP] Funciones :: El macro PHP_FUNCTION recibe como argumento el nombre de la función que deseamos exportar. PHP_FUNCTION(suma) :: El cuerpo de la función usualmente consta de: -> Recepción y parseo de argumentos con zend_parse_parameters() -> Proceso específico de la función. -> Retorno de un valor mediante los macros RETURN_XXX() 28
  • 29.
    :: Interfaces descripting para librerías en C :: :: CIISA 2008 :: [Construcción de una extensión PHP] Funciones :: zend_parse_parameters es necesario para tomar los argumentos del stack del ZE. :: zend_parse_parameters recibe el número de argumentos a parsear, sus tipos (mediante una cadena de formato) y los apuntadores a la memoria a utilizar para guardarlos. int op1, op2; zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, “ll”, &op1, &op2); :: El valor de retorno FAILURE significa que el parseo falló y usualmente debe ser causal para mandar un error con zend_throw_exception o WRONG_PARAM_COUNT 29
  • 30.
    :: Interfaces descripting para librerías en C :: :: CIISA 2008 :: [Construcción de una extensión PHP] Funciones :: La cadena de formato puede contener los valores: s -> el valor esperado es un string. Debemos proveer char ** e int* b -> booleano. Proveer zend_bool* l -> long. Proveer long* r, a, o, z -> resource, array, object, opaco. Proveer zval* 30
  • 31.
    :: Interfaces descripting para librerías en C :: :: CIISA 2008 :: [Construcción de una extensión PHP] Funciones :: Para regresar un valor de la función debe usarse: RETURN_RESOURCE, RETURN_LONG, RETURN_BOOL etc. :: RETURN_STRING es especial, debe indicarse si el buffer del string debe ser duplicado o no por el ZE. El segundo parámetro del macro lo indica. RETURN_STRING(“Buffer Permanente”, 1); RETURN_STRING(variable_local, 0); 31
  • 32.
    :: Interfaces descripting para librerías en C :: :: CIISA 2008 :: [Construcción de una extensión PHP] Funciones PHP_FUNCTION(suma) { long op1; op2; if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ll", &op1, &op2)) { return; } RETURN_LONG((op1 + op2)); } 32
  • 33.
    :: Interfaces descripting para librerías en C :: :: CIISA 2008 :: [Construcción de una extensión PHP] Funciones :: TSRMLS == Thread Safe Resource Manager Local Storage :: Necesario para crear scope “global” por thread. :: Existen muchos macros variantes para facilitar pasar este storage de un lado a otro. 33
  • 34.
    :: Interfaces descripting para librerías en C :: :: CIISA 2008 :: [Construcción de una extensión PHP] Clases :: El ZE está escrito en C por lo que internamente las clases de PHP están definidas como estructuras y apuntadores a funciones. :: Una declaración en user space de una clase tiene la forma: class ClaseEnPhp {} :: Internamente tal clase tendría que registrarse usando una estructura zend_class_entry y la función zend_register_internal_class. :: El equivalente a una declaración de clase en user space es: zend_class_entry ce; INIT_CLASS_ENTRY(ce, “ClaseEnPhp”, NULL); zend_register_internal_class(&ce TSRML_CC); :: El registro de clases desde una extensión debe ser hecho en MINIT 34
  • 35.
    :: Interfaces descripting para librerías en C :: :: CIISA 2008 :: [Construcción de una extensión PHP] Clases :: La implementación de un método de una varía poco de la de una función común. :: El macro PHP_METHOD es usado en lugar de PHP_FUNCTION. PHP_METHOD(PrimerMetodo) { // cuerpo del método } :: Características adicionales para el método como visibilidad y definición de argumentos son especificadas a través de la estructura zend_function_entry y el macro PHP_ME zend_function_entry ClaseEnPhp_methods[] = { PHP_ME(ClaseEnPhp, PrimerMetodo, NULL, ZEND_ACC_PUBLIC); }; 35
  • 36.
    :: Interfaces descripting para librerías en C :: :: CIISA 2008 :: [Construcción de una extensión PHP] Clases :: La implementación de un método de una varía poco de la de una función común. :: El macro PHP_METHOD es usado en lugar de PHP_FUNCTION. PHP_METHOD(PrimerMetodo) { // cuerpo del método } :: Características adicionales para el método como visibilidad y definición de argumentos son especificadas a través de la estructura zend_function_entry y el macro PHP_ME zend_function_entry ClaseEnPhp_methods[] = { PHP_ME(ClaseEnPhp, PrimerMetodo, NULL, ZEND_ACC_PUBLIC); }; 36
  • 37.
    :: Interfaces descripting para librerías en C :: :: CIISA 2008 :: [Construcción de una extensión PHP] Compilación :: La compilación en Linux se lleva a cabo mediante un comando incluido con la distribución de PHP: “phpize” :: Antes de correr phpize se necesita crear config.m4, un script que determinará opciones de tiempo de compilación como la ubicación de librerías externas. :: Una vez creado config.m4 se procede a ejecutar phpize # phpize :: Finalmente igual que cualquier otro paquete basado en GNU autotools se instala mediante: # ./configure # make && make install 37
  • 38.
    :: Interfaces descripting para librerías en C :: :: CIISA 2008 :: [SWIG] Funcionamiento General :: SWIG es un generador del pegamento necesario para juntar código en C/C++ con lenguajes de más alto nivel como PHP, PERL, Python, Java etc. :: SWIG recibe como entrada un archivo especial que define las interfaces en C/C++ para generar código fuente que puede ser compilado para crear módulos del lenguaje deseado. :: Una archivo de interfaz puede ser facilmente escrito incluyendo el header donde declaras tus funciones C/C++: %module milibreria %{ #include “milibreria.h” %} 38
  • 39.
    :: Interfaces descripting para librerías en C :: :: CIISA 2008 :: [SWIG] Funcionamiento General :: El archivo de interfaz se usa como entrada para SWIG. # swig -perl milibreria.i :: SWIG genera un archivo milibreria_wrap.c que funcionará como interfaz hacia PERL. :: Se compila la interfaz. # gcc -c milibreria.c milibreria_wrap.c `perl -MextUtils::Embed -e ccopts` :: Se enlaza la libreria con el wrapper de perl. # ld -G milibreria.o milibreria_wrap.o -o milibreriaperl.so 39
  • 40.
    :: Interfaces descripting para librerías en C :: :: CIISA 2008 :: Referencias. http://www.hardened-php.net/ http://devzone.zend.com/ http://www.php.net/ http://www.swig.org/ http://www.php.net/internals2.ze1.zendapi 40
  • 41.
    :: Interfaces descripting para librerías en C :: :: CIISA 2008 :: Gracias. Moisés Humberto Silva Salmerón http://www.moythreads.com// moises.silva@gmail.com moyhu@mx1.ibm.commoyhu@mx1.ibm.com 41