PHP 8.5.0 Alpha 1 available for testing

Arquitectura del plugin del controlador nativo

Esta sección proporciona una visión general de la arquitectura del plugin mysqlnd.

Visión general del controlador nativo MySQL

Antes de desarrollar plugins mysqlnd, es útil tener un conocimiento mínimo sobre la organización de mysqlnd. Mysqlnd está compuesto por los siguientes módulos:

Esquema de la organización mysqlnd, por módulo
Módulos de estadísticas mysqlnd_statistics.c
Conexión mysqlnd.c
Juego de resultados mysqlnd_result.c
Datos méta del juego de resultados mysqlnd_result_meta.c
Consulta mysqlnd_ps.c
Red mysqlnd_net.c
Capa física mysqlnd_wireprotocol.c

Objeto C orientado a paradigma

A nivel de código, mysqlnd utiliza una máscara C para implementar la orientación al objeto.

En C, se utiliza una estructura (struct) para representar un objeto. Los miembros de esta estructura representan las propiedades del objeto. Los miembros de la estructura que apuntan hacia funciones representan los métodos.

A diferencia de otros lenguajes como C++ o Java, no hay reglas fijas sobre la herencia en los objetos C orientados a paradigma. Sin embargo, hay algunas convenciones que deben seguirse que serán abordadas posteriormente.

El ciclo de vida PHP

El ciclo de vida de PHP consta de 2 ciclos básicos:

  • El ciclo de inicio y parada del motor PHP

  • El ciclo de una petición

Cuando el motor PHP se inicia, llama a la función de inicialización del módulo (MINIT) de cada extensión registrada. Esto permite a cada módulo definir las variables y asignar los recursos que deben existir durante la vida del proceso correspondiente al motor PHP. Cuando el motor PHP se detiene, llama a la función de parada del módulo (MSHUTDOWN) para cada extensión.

Durante la vida del motor PHP, recibirá peticiones. Cada petición constituye otro ciclo de vida. Para cada petición, el motor PHP llamará a la función de inicialización de cada extensión. La extensión puede realizar todas las definiciones de variables así como las asignaciones de recursos necesarias para procesar la petición. Cuando el ciclo de la petición termina, el motor llama a la función de parada (RSHUTDOWN) para cada extensión, por lo que la extensión puede lanzar toda la limpieza necesaria.

Cómo funciona un plugin

Un plugin mysqlnd funciona interceptando las llamadas realizadas a mysqlnd por las extensiones que utilizan mysqlnd. Esto es posible obteniendo la tabla de función mysqlnd, guardándola, y reemplazándola por una tabla de función personalizada, que llama a las funciones del plugin.

El código siguiente muestra cómo se reemplaza la tabla de función mysqlnd:

/* un lugar para almacenar la tabla de función original */
struct st_mysqlnd_conn_methods org_methods;

void minit_register_hooks(TSRMLS_D) {
  /* tabla de función activa */
  struct st_mysqlnd_conn_methods * current_methods
    = mysqlnd_conn_get_methods();

  /* guardar la tabla de función original */
  memcpy(&org_methods, current_methods,
    sizeof(struct st_mysqlnd_conn_methods));

  /* instalación de las nuevas métodos */
  current_methods->query = MYSQLND_METHOD(my_conn_class, query);
}

Las manipulaciones de la tabla de función de conexión deben realizarse durante la inicialización del módulo (MINIT). La tabla de función es un recurso global compartido. En un entorno multihilo, con una compilación TSRM, la manipulación de un recurso global compartido durante un proceso de petición generalmente resultará en conflictos.

Nota:

No utilice ninguna lógica de tamaño fijo al manipular la tabla de función mysqlnd: las nuevas funciones pueden ser añadidas al final de la tabla de función. La tabla de función puede ser modificada en cualquier momento después.

Llamada a métodos padres

Si la tabla de función original se guarda, siempre es posible llamar a las entradas de la tabla de función original - los métodos padres.

En este caso, al igual que Connection::stmt_init(), es vital llamar al método padre antes de cualquier otra actividad en el método derivado.

MYSQLND_METHOD(my_conn_class, query)(MYSQLND *conn,
  const char *query, unsigned int query_len TSRMLS_DC) {

  php_printf("my_conn_class::query(query = %s)\n", query);

  query = "SELECT 'query rewritten' FROM DUAL";
  query_len = strlen(query);

  return org_methods.query(conn, query, query_len); /* retorno con llamada al padre */
}

Extender propiedades

Un objeto mysqlnd está representado por una estructura C. No es posible añadir un miembro a una estructura C en tiempo de ejecución. Los usuarios de objetos mysqlnd no pueden simplemente añadir propiedades a los objetos.

Datos arbitrarios (propiedades) pueden ser añadidos a los objetos mysqlnd utilizando una función apropiada de la familia mysqlnd_plugin_get_plugin_<object>_data(). Durante la asignación de un objeto, mysqlnd reserva un espacio al final del objeto para alojar un puntero void * hacia datos arbitrarios. mysqlnd reserva un espacio para un puntero void * por plugin.

La tabla siguiente muestra cómo calcular la posición de un puntero para un plugin específico:

Cálculo de punteros para mysqlnd
Dirección de memoria Contenido
0 Inicio de la estructura C del objeto mysqlnd
n Fin de la estructura C del objeto mysqlnd
n + (m x sizeof(void*)) void* hacia los datos del objeto del plugin m-ésimo

Si planea hacer subclases de los constructores de los objetos mysqlnd, lo cual está permitido, debe tener esto en cuenta.

El código siguiente muestra cómo se extienden propiedades:

/* todos los datos que queremos asociar */
typedef struct my_conn_properties {
  unsigned long query_counter;
} MY_CONN_PROPERTIES;

/* id del plugin */
unsigned int my_plugin_id;

void minit_register_hooks(TSRMLS_D) {
  /* obtenemos un ID único para el plugin */
  my_plugin_id = mysqlnd_plugin_register();
  /* snip - ver la extensión de la conexión: métodos */
}

static MY_CONN_PROPERTIES** get_conn_properties(const MYSQLND *conn TSRMLS_DC) {
  MY_CONN_PROPERTIES** props;
  props = (MY_CONN_PROPERTIES**)mysqlnd_plugin_get_plugin_connection_data(
    conn, my_plugin_id);
  if (!props || !(*props)) {
    *props = mnd_pecalloc(1, sizeof(MY_CONN_PROPERTIES), conn->persistent);
    (*props)->query_counter = 0;
  }
  return props;
}

El desarrollador del plugin es responsable de la gestión de la memoria asociada a los datos del plugin.

Se recomienda el uso del asignador de memoria mysqlnd para los datos del plugin. Estas funciones son nombradas utilizando la siguiente convención: mnd_*loc(). El asignador mysqlnd tiene algunas características muy útiles, como la posibilidad de utilizar un asignador de depuración en una compilación no depurada.

Cuándo y cómo hacer una subclase
  ¿Cuándo hacer una subclase? ¿Cada instancia tiene su propia tabla de funciones privada? ¿Cómo hacer una subclase?
Conexión (MYSQLND) MINIT No mysqlnd_conn_get_methods()
Juego de resultados (MYSQLND_RES) MINIT o después mysqlnd_result_get_methods() o método del objeto de manipulación de la tabla de funciones
Meta del juego de resultados (MYSQLND_RES_METADATA) MINIT No mysqlnd_result_metadata_get_methods()
Consulta (MYSQLND_STMT) MINIT No mysqlnd_stmt_get_methods()
Red (MYSQLND_NET) MINIT o después mysqlnd_net_get_methods() o método del objeto de manipulación de la tabla de funciones
Capa física (MYSQLND_PROTOCOL) MINIT o después mysqlnd_protocol_get_methods() o método del objeto de manipulación de la tabla de funciones

No debe manipular las tablas de funciones después de MINIT si no está permitido según la tabla anterior.

Algunas clases contienen un puntero hacia un método de la tabla de funciones. Todas las instancias de una clase de este tipo compartirán la misma tabla de funciones. Para evitar el caos, en particular en entornos multihilo, este tipo de tablas de funciones solo debe ser manipulado durante el MINIT.

Las otras clases utilizan una copia de la tabla de funciones global compartida. Esta copia se crea al mismo tiempo que el objeto. Cada objeto utiliza su propia tabla de funciones. Esto le da 2 opciones: puede manipular la tabla de funciones por defecto de un objeto durante el MINIT, y también puede afinar métodos de un objeto sin afectar a las otras instancias de la misma clase.

La ventaja del enfoque con una tabla de funciones compartida es el rendimiento. No es necesario copiar una tabla de funciones para cada objeto.

Estado del constructor
Tipo Asignación, construcción, reinicialización ¿Puede ser modificado? Llamante
Conexión (MYSQLND) mysqlnd_init() No mysqlnd_connect()
Juego de resultados (MYSQLND_RES)

Asignación:

  • Connection::result_init()

Reinicio y reinicialización durante:

  • Result::use_result()

  • Result::store_result

Sí, pero llamada al padre.
  • Connection::list_fields()

  • Statement::get_result()

  • Statement::prepare() (Meta-datos únicamente)

  • Statement::resultMetaData()

Meta del juego de resultados (MYSQLND_RES_METADATA) Connection::result_meta_init() Sí, pero llamada al padre. Result::read_result_metadata()
Consulta (MYSQLND_STMT) Connection::stmt_init() Sí, pero llamada al padre. Connection::stmt_init()
Red (MYSQLND_NET) mysqlnd_net_init() No Connection::init()
Capa física (MYSQLND_PROTOCOL) mysqlnd_protocol_init() No Connection::init()

Se recomienda encarecidamente no reemplazar completamente un constructor. Los constructores realizan asignaciones de memoria. Las asignaciones de memoria son vitales para la API del plugin mysqlnd así como para la lógica del objeto mysqlnd. Si no se preocupa por las advertencias e insiste en reemplazar los constructores, debería al menos llamar al constructor padre antes de hacer cualquier cosa en su constructor.

A nivel de todas las advertencias, puede ser útil hacer subclases de los constructores. Los constructores son los lugares perfectos para modificar las tablas de funciones de los objetos con tablas de objetos no compartidas, como los juegos de resultados, la red o la capa física.

Estado del destructor
Tipo ¿El método derivado debe llamar al padre? Destructor
Conexión Sí, después de la ejecución del método free_contents(), end_psession()
Juego de resultados Sí, después de la ejecución del método free_result()
Meta del juego de resultados Sí, después de la ejecución del método free()
Consulta Sí, después de la ejecución del método dtor(), free_stmt_content()
Red Sí, después de la ejecución del método free()
Capa física Sí, después de la ejecución del método free()

Los destructores son los lugares perfectos para liberar propiedades, mysqlnd_plugin_get_plugin_<object>_data().

Los destructores listados pueden no ser los equivalentes a los métodos actuales mysqlnd que liberan el objeto mismo. Sin embargo, son los mejores lugares para liberar los datos de su plugin. Al igual que los constructores, puede reemplazar métodos completos pero no se recomienda. Si varios métodos están listados en la tabla anterior, debe modificar todos los métodos listados y liberar los datos de su plugin en el método llamado primero por mysqlnd.

El método recomendado para los plugins es simplemente modificar los métodos, liberar su memoria y llamar a la implementación del padre inmediatamente después.

add a note

User Contributed Notes

There are no user contributed notes for this page.
To Top