|
Esta sección se encuentra bastante desactualizada y demuestra el modo de extender PHP 3. Si está interesado en PHP 4, por favor lea la sección sobre la interfaz de programación Zend. Así mismo, usted querrá leer varios archivos encontrados en el código fuente de PHP, archivos como README.SELF-CONTAINED-EXTENSIONS y README.EXT_SKEL.
Todas las funciones lucen de este modo:
void php3_foo(INTERNAL_FUNCTION_PARAMETERS) { } |
Los argumentos son siempre de tipo pval. Este tipo posee una unión que contiene el tipo real del argumento. Así que, si su función recibe dos argumentos, usted haría algo como lo siguiente al comienzo de su función:
Cuando usted modifica cualquiera de los parámetros pasados, ya sea que hayan sido enviados por referencia o por valor, puede o bien comenzar con el parámetro llamando pval_destructor sobre él, o si es un ARRAY al que desea agregar valores, puede usar funciones similares a aquellas en internal_functions.h que manipulan return_value como un ARRAY.
También, si modifica un parámetro a IS_STRING asegúrese de asignar primero la nueva cadena mediante estrdup() y la longitud de la cadena, y sólo después modifique el tipo a IS_STRING. Si modifica la cadena de un parámetro que ya es IS_STRING o IS_ARRAY, debe ejecutar pval_destructor sobre éste primero.
Una función puede recibir un número variable de argumentos. Si su función puede recibir ya sea 2 o 3 argumentos, use lo siguiente:
El tipo de cada argumento es almacenado en el campo type de pval. Este tipo puede ser cualquiera de los siguientes:
Tabla F-1. Tipos Internos de PHP
IS_STRING | Cadena |
IS_DOUBLE | Punto flotante de doble precisión |
IS_LONG | Entero largo |
IS_ARRAY | Matriz |
IS_EMPTY | Ninguno |
IS_USER_FUNCTION | ?? |
IS_INTERNAL_FUNCTION | ?? (si alguno de éstos no puede ser pasado a una función - eliminar) |
IS_CLASS | ?? |
IS_OBJECT | ?? |
Si recibe un argumento de un tipo y quisiera usarlo como otro, o si tan sólo desea obligar al argumento a que sea de un cierto tipo, puede usar una de las siguientes funciones de conversión:
convert_to_long(arg1); convert_to_double(arg1); convert_to_string(arg1); convert_to_boolean_long(arg1); /* Si la cadena es "" o "0" se convierte a 0, 1 de lo contrario */ convert_string_to_number(arg1); /* Convierte una cadena a un LONG o DOUBLE, dependiendo de la cadena */ |
Estas funciones todas realizan conversión en-el-lugar. No devuelven nada.
El argumento como tal es almacenado en una unión; los miembros son:
IS_STRING: arg1->value.str.val
IS_LONG: arg1->value.lval
IS_DOUBLE: arg1->value.dval
Cualquier segmento de memoria necesitado por una función debe ser reservado ya sea con emalloc() o estrdup(). Estas son funciones que abstraen la gestión de memoria y lucen y huelen como las funciones normales malloc() y strdup(). La memoria debe ser liberada con efree().
Hay dos tipos de memoria en este programa: la memoria que es devuelta al intérprete en una variable, y la memoria que necesita para el almacenamiento temporal en su función interna. Cuando asigna una cadena a una variable que es devuelta al intérprete, necesita asegurarse de reservar primero la memoria con emalloc() o estrdup(). Esta memoria no debería ser liberada por usted NUNCA, a menos que más adelante en la misma función sobrescriba su asignación original (aunque este tipo de práctica no se considera apropiada).
Para cualquier segmento de memoria temporal/permanente que necesite en sus funciones/bibliotecas, usted debería usar las tres funciones emalloc(), estrdup(), y efree(). Éstas se comportan EXACTAMENTE como sus contrapartes. Cualquier cosa que reserve con emalloc() o estrdup() debe liberarla con efree() en alguno u otro punto, a menos que espere que permanezca hasta el final del programa; de otro modo, habrá una fuga de memoria. El significado de "las funciones se comportan exactamente como sus contrapartes" es: si usted usa efree() sobre algo que no fue reservado con emalloc() ni estrdup(), puede que reciba un fallo de segmentación. De modo que, por favor, tenga cuidado y libere toda su memoria desperdiciada.
Si compila con "-DDEBUG", PHP imprimirá una lista de toda la memoria que fue reservada usando emalloc() y estrdup() y nunca liberada con efree() una vez termina la ejecución el script especificado.
Un número de macros se encuentra a su disposición para facilitar la definición de una variable en la tabla de símbolos:
SET_VAR_STRING(nombre,valor)
SET_VAR_DOUBLE(nombre,valor)
SET_VAR_LONG(nombre,valor)
Aviso |
Tenga cuidado con SET_VAR_STRING. La parte del valor debe ser reservada manualmente con malloc, ya que el código de gestión de memoria intentará liberar este apuntador más adelante. No pase memoria reservada estáticamente a un llamado a SET_VAR_STRING. |
Las tablas de símbolos en PHP se encuentran implementadas como tablas asociativas. En cualquier momento dado, &symbol_table es un apuntador a la tabla de símbolos 'principal', y active_symbol_table apunta a la tabla de símbolos activa actualmente (éstas pueden ser idénticas, como al arranque, o diferentes, si se encuentra en el interior de una función).
Los siguientes ejemplos usan 'active_symbol_table'. Debe reemplazar este valor con &symbol_table si desea trabajar específicamente con la tabla de símbolos 'principal'. Asimismo, las mismas funciones pueden ser aplicadas sobre matrices, como se explica más adelante.
Si desea definir una nueva matriz en una tabla de símbolos, debe hacer lo siguiente.
Primero, puede que desee chequear si existe, y abortar la ejecución apropiadamente, usando hash_exists() o hash_find().
A continuación, inicialice la matriz:
Este es el modo de agregar entradas en ella:
hash_next_index_insert() usa más o menos la misma lógica que $foo[] = bar; en PHP 2.0.
Si está construyendo una matriz para devolverla desde una función, puede inicializar la matriz tal y como se ha indicado, haciendo:
if (array_init(return_value) == FAILURE) { fallo...; } |
...y luego agregar valores con las funciones de ayuda:
add_next_index_long(valor_retorno,valor_long); add_next_index_double(valor_retorno,valor_double); add_next_index_string(valor_retorno,estrdup(valor_string)); |
Por supuesto, si la adición no es realizada correctamente luego de la inicialización de la matriz, probablemente tenga que verificar la existencia de la matriz primero:
pval *arr; if (hash_find(active_symbol_table,"foo",sizeof("foo"),(void **)&arr)==FAILURE) { no se pudo encontrar... } else { use arr->value.ht... } |
Note que hash_find recibe un apuntador a un apuntador pval, y no un apuntador pval.
Prácticamente toda función de matriz asociativa devuelve SUCCESS o FAILURE (excepto por hash_exists(), que devuelve un valor booleano de verdad).
Un número de macros se encuentra a su disposición para facilitar la devolución de valores desde una función.
Las macros RETURN_* todas establecen el valor de retorno y generan una devolución desde la función:
RETURN
RETURN_FALSE
RETURN_TRUE
RETURN_LONG(l)
RETURN_STRING(s,dup) Si dup es TRUE, duplica la cadena
RETURN_STRINGL(s,l,dup) Devuelve una cadena (s) especificando la longitud (l).
RETURN_DOUBLE(d)
Las macros RETVAL_* establecen el valor de retorno, pero no devuelven.
RETVAL_FALSE
RETVAL_TRUE
RETVAL_LONG(l)
RETVAL_STRING(s,dup) Si dup es TRUE, duplica la cadena
RETVAL_STRINGL(s,l,dup) Devuelve una cadena (s) especificando la longitud (l).
RETVAL_DOUBLE(d)
Todas las macros de cadena anteriores aplicarán estrdup() sobre el argumento 's' pasado, de modo que puede liberar de forma segura el argumento después de llamar la macro, o alternativamente puede usar memoria reservada estáticamente.
Si su función devuelve repuesteas booleanas de éxito/error, use siempre RETURN_TRUE y RETURN_FALSE respectivamente.
Su función también puede devolver un tipo de datos complejo como un objeto o una matriz.
Devolución de un objeto:
Llame object_init(valor_retorno).
Llénelo con valores. Las funciones disponibles para este propósito se listan más adelante.
Posiblemente, registre funciones para este objeto. Para obtener valores del objeto, la función tendría que recuperar "this" desde active_symbol_table. Su tipo debe ser IS_OBJECT, y es básicamente una tabla asociativa regular (esto quiere decir, puede usar las funciones de matrices asociativas regulares sobre .value.ht). El registro como tal de la función puede realizarse usando:
add_method( valor_retorno, nombre_funcion, apuntador_funcion ); |
Las funciones usadas para poblar el objeto son:
add_property_long( valor_retorno, nombre_propiedad, l ) - Agregar una propiedad llamada 'nombre_propiedad', de tipo long, igual a 'l'
add_property_double( valor_retorno, nombre_propiedad, d ) - Igual, sólo agrega un double
add_property_string( valor_retorno, nombre_propiedad, str ) - Igual, sólo agrega una cadena
add_property_stringl( valor_retorno, nombre_propiedad, str, l ) - Igual, sólo agrega una cadena de longitud 'l'
Devolución de una matriz:
Llame array_init(valor_retorno).
Llénela con valores. Las funciones disponibles para este propósito se listan más adelante.
Las funciones usadas para poblar una matriz son:
add_assoc_long(valor_retorno,clave,l) - agregar una matriz asociativa con la clave 'clave' y el valor largo 'l'
add_assoc_double(valor_retorno,clave,d)
add_assoc_string(valor_retorno,clave,cadena,duplicar)
add_assoc_stringl(valor_retorno,clave,cadena,longitud,duplicar) especifica la longitud de la cadena
add_index_long(valor_retorno,indice,l) - agregar una entrada en el indice 'indice' con el valor long 'l'
add_index_double(valor_retorno,indice,d)
add_index_string(valor_retorno,indice,cadena)
add_index_stringl(valor_retorno,indice,cadena,length) - especificar la longitud de la cadena
add_next_index_long(valor_retorno,l) - agregar una entrada de la matriz en la siguiente ubicación libre con el valor long 'l'
add_next_index_double(valor_retorno,d)
add_next_index_string(valor_retorno,cadena)
add_next_index_stringl(valor_retorno,cadena,length) - especificar la longitud de la cadena
PHP posee una forma estándar de tratar con los varios tipos de recursos. Esto reemplaza todas las listas enlazadas locales usadas en PHP 2.0.
Funciones disponibles:
php3_list_insert(apuntador, tipo) - devuelve el 'id' del recurso recién insertado
php3_list_delete(id) - eliminar el recurso con el id especificado
php3_list_find(id,*tipo) - devuelve el apuntador del recurso con el id especificado, actualiza 'tipo' al tipo del recurso
Un listado de código típico luciría de la siguiente forma:
Ejemplo F-8. Uso de un recurso existente
|
PHP posee una forma estándar de almacenar recursos persistentes (es decir, recursos que son conservados entre peticiones). El primer módulo en usar esta característica fue el módulo MySQL, y mSQL a continuación, de modo que puede obtener una idea general de cómo debe ser usado un recurso persistente leyendo mysql.c. Las funciones que debe consultar son:
php3_mysql_do_connect |
php3_mysql_connect() |
php3_mysql_pconnect() |
La idea general de los módulos de persistencia es la siguiente:
Escriba todo el código de su módulo para que trabaje con la lista de recursos normales mencionada en la sección (9).
Escriba el código de funciones de conexión extra que revisen si el recurso ya existe en la lista de recursos persistentes. Si es así, regístrelo en la lista de recursos normal como un apuntador a la lista de recursos persistentes (debido a 1., el resto del código debe funcionar inmediatamente). Si no existe, entonces créelo, agréguelo a la lista de recursos persistentes Y agregue un apuntador hacia él desde la lista normal de recursos, de modo que todo el código pueda funcionar; esto ya que se encuentra en la lista de recursos regulares, pero, en la siguiente conexión, el recurso sería encontrado en la lista de recursos persistentes y usado sin tener que crearlo de nuevo. Debe registrar éstos recursos con un tipo diferente (p.ej. LE_MYSQL_LINK para un enlace no-persistente y LE_MYSQL_PLINK para un enlace persistente).
Si lee mysql.c, notará que, con la excepción de la función de conexión más compleja, nada del resto del módulo tiene que ser modificado.
La misma interfaz existe para la lista de recursos regulares y la lista de recursos persistentes, tan sólo 'list' se reemplaza por 'plist':
php3_plist_insert(apuntador, tipo) - devuelve el 'id' del recurso recién insertado
php3_plist_delete(id) - eliminar el recurso con el id especificado
php3_plist_find(id,*tipo) - devuelve el apuntador del recurso con el id especificado, actualiza 'tipo' al tipo del recurso
Sin embargo, es más que probable que estas funciones le resulten inútiles cuando intente implementar un módulo persistente. Típicamente, es deseable aprovechar el hecho de que la lista de recursos persistentes es realmente una tabla asociativa. Por ejemplo, en los módulos MySQL/mSQL, cuando hay un llamado a pconnect() (conexión persistente), la función crea una cadena a partir de los valores de host/usuario/contraseña que fueron pasados a la función, y asocia el enlace SQL con ésta cadena como clave. La siguiente vez que alguien haga un llamado a pconnect() con la misma información de host/usuario/contraseña, se generará la misma clave, y la función encontrará el enlace SQL en la lista persistente.
Hasta que sea documentado más a fondo, debería echarle un vistazo a mysql.c o msql.c para ver cómo pueden usarse las capacidades de tabla asociativa de una lista plist.
Una cosa importante a notar: los recursos que van a la lista de recursos persistentes *NO* debe ser reservada con el gestor de memoria de PHP, es decir, NO debe ser creada con emalloc(), estrdup(), etc. En su lugar, deben ser usadas las funciones normales malloc(), strdup(), etc. La razón de esto es simple - al final de la petición (final de cada visita), cada trozo de memoria que fue ubicado usando el gestor de memoria de PHP es eliminado. Ya que la lista persistente no se supone que deba ser eliminada el final de cada petición, no debe utilizarse el gestor de memoria de PHP para reservar recursos que vayan a la lista.
Cuando registra un recurso que va a ser usado en la lista persistente, debe agregar destructores para ésta tanto en la lista no-persistente como en la persistente. El destructor en la lista no-persistente no debería hacer nada. Aquel en la lista persistente debería liberar apropiadamente cualquier recurso obtenido por ese tipo (p.ej. memoria, enlaces SQL, etc). Tal como con los recursos no-persistentes, usted *DEBE* agregar destructores para cada recurso, incluso si no requieren ser destruidos y el destructor puede estar vacío. Recuerde, ya que emalloc() y amigos no deben ser usados junto con la lista persistente, tampoco debe usar efree() aquí.
Muchas de las características de PHP pueden ser configuradas en tiempo de ejecución. Estas directivas de configuración pueden aparecer en el archivo php3.ini designado, o, en el caso de la versión módulo de Apache, en los archivos .conf de Apache. La ventaja de tenerlas en los archivos .conf de Apache es que pueden ser configuradas por cada directorio. Esto quiere decir que un directorio puede tener cierto valor para safemodeexecdir, por ejemplo, mientras que otro directorio puede tener otro. Esta especificidad en la configuración es especialmente útil cuando un servidor soporta múltiples hosts virtuales.
Los pasos requeridos para agregar una nueva directiva:
Agregar la directiva a la estructura php3_ini_structure en mod_php3.h.
En main.c, editar la función php3_module_startup y agregar la llamada apropiada a cfg_get_string() o cfg_get_long().
Agregar la directiva, restricciones y un comentario a la estructura php3_commands en mod_php3.c. Fíjese en la parte de restricciones. RSRC_CONF son directivas que pueden estar presentes sólo en las archivos .conf de Apache, Cualquier directiva OR_OPTIONS puede estar presente en cualquier parte, incluyendo archivos .htaccess normales.
Agregue la entrada apropiada para su directiva en php3take1handler() o en php3flaghandler().
En la sección de configuración de la función _php3_info() en functions/info.c necesita agregar su nueva directiva.
Y, por último, debe por supuesto usar su directiva en alguna parte. Esta será asequible como php3_ini.directiva.
Hosting by: hurra.com
Generated: 2007-01-26 18:00:58