<?php
include_once $_SERVER['DOCUMENT_ROOT'] . '/include/shared-manual.inc';
$TOC = array();
$TOC_DEPRECATED = array();
$PARENTS = array();
include_once dirname(__FILE__) ."/toc/mysqlnd.plugin.inc";
$setup = array (
  'home' => 
  array (
    0 => 'index.php',
    1 => 'PHP Manual',
  ),
  'head' => 
  array (
    0 => 'UTF-8',
    1 => 'es',
  ),
  'this' => 
  array (
    0 => 'mysqlnd.plugin.architecture.php',
    1 => 'Arquitectura del plugin del controlador nativo',
    2 => 'Arquitectura del plugin del controlador nativo',
  ),
  'up' => 
  array (
    0 => 'mysqlnd.plugin.php',
    1 => 'API del plugin del controlador nativo MySQL',
  ),
  'prev' => 
  array (
    0 => 'mysqlnd.plugin.obtaining.php',
    1 => 'Obtener la API del plugin mysqlnd',
  ),
  'next' => 
  array (
    0 => 'mysqlnd.plugin.api.php',
    1 => 'La API del plugin mysqlnd',
  ),
  'alternatives' => 
  array (
  ),
  'source' => 
  array (
    'lang' => 'es',
    'path' => 'reference/mysqlnd/plugin.xml',
  ),
  'history' => 
  array (
  ),
);
$setup["toc"] = $TOC;
$setup["toc_deprecated"] = $TOC_DEPRECATED;
$setup["parents"] = $PARENTS;
manual_setup($setup);

contributors($setup);

?>
<div id="mysqlnd.plugin.architecture" class="section">
  <h2 class="title">Arquitectura del plugin del controlador nativo</h2>
  <p class="simpara">
   Esta sección proporciona una visión general de la arquitectura del plugin
   <code class="literal">mysqlnd</code>.
  </p>
  <p class="simpara">
   <strong>Visión general del controlador nativo MySQL</strong>
  </p>
  <p class="simpara">
   Antes de desarrollar plugins <code class="literal">mysqlnd</code>,
   es útil tener un conocimiento mínimo sobre la organización
   de <code class="literal">mysqlnd</code>. <code class="literal">Mysqlnd</code> está compuesto
   por los siguientes módulos:
  </p>
  <table id="mysqlnd.plugin.orgchart" class="doctable table">
   <caption><strong>Esquema de la organización mysqlnd, por módulo</strong></caption>
   
    <thead>
     <tr>
      <th>Módulos de estadísticas</th>
      <th>mysqlnd_statistics.c</th>
     </tr>

    </thead>

    <tbody class="tbody">
     <tr>
      <td>Conexión</td>
      <td>mysqlnd.c</td>
     </tr>

     <tr>
      <td>Juego de resultados</td>
      <td>mysqlnd_result.c</td>
     </tr>

     <tr>
      <td>Datos méta del juego de resultados</td>
      <td>mysqlnd_result_meta.c</td>
     </tr>

     <tr>
      <td>Consulta</td>
      <td>mysqlnd_ps.c</td>
     </tr>

     <tr>
      <td>Red</td>
      <td>mysqlnd_net.c</td>
     </tr>

     <tr>
      <td>Capa física</td>
      <td>mysqlnd_wireprotocol.c</td>
     </tr>

    </tbody>
   
  </table>

  <p class="simpara">
   <strong>Objeto C orientado a paradigma</strong>
  </p>
  <p class="simpara">
   A nivel de código, <code class="literal">mysqlnd</code> utiliza una máscara C
   para implementar la orientación al objeto.
  </p>
  <p class="simpara">
   En C, se utiliza una estructura (<code class="literal">struct</code>)
   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.
  </p>
  <p class="simpara">
   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.
  </p>
  <p class="simpara">
   <strong>El ciclo de vida PHP</strong>
  </p>
  <p class="simpara">
   El ciclo de vida de PHP consta de 2 ciclos básicos:
  </p>
  <ul class="itemizedlist">
   <li class="listitem">
    <span class="simpara">
     El ciclo de inicio y parada del motor PHP
    </span>
   </li>
   <li class="listitem">
    <span class="simpara">
     El ciclo de una petición
    </span>
   </li>
  </ul>
  <p class="simpara">
   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.
  </p>
  <p class="simpara">
   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.
  </p>
  <p class="simpara">
   <strong>Cómo funciona un plugin</strong>
  </p>
  <p class="simpara">
   Un plugin <code class="literal">mysqlnd</code> funciona interceptando las llamadas
   realizadas a <code class="literal">mysqlnd</code> por las extensiones que utilizan
   <code class="literal">mysqlnd</code>. Esto es posible obteniendo la tabla
   de función <code class="literal">mysqlnd</code>, guardándola, y reemplazándola por una tabla
   de función personalizada, que llama a las funciones del plugin.
  </p>
  <p class="simpara">
   El código siguiente muestra cómo se reemplaza la tabla de función
   <code class="literal">mysqlnd</code>:
  </p>
  <div class="example-contents">
<div class="cdata"><pre>
/* 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(&amp;org_methods, current_methods,
    sizeof(struct st_mysqlnd_conn_methods));

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

  <p class="simpara">
   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.
  </p>
  <blockquote class="note"><p><strong class="note">Nota</strong>: 
   <span class="simpara">
    No utilice ninguna lógica de tamaño fijo al manipular
    la tabla de función <code class="literal">mysqlnd</code>: 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.
   </span>
  </p></blockquote>
  <p class="simpara">
   <strong>Llamada a métodos padres</strong>
  </p>
  <p class="simpara">
   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.
  </p>
  <p class="simpara">
   En este caso, al igual que <code class="literal">Connection::stmt_init()</code>,
   es vital llamar al método padre antes de cualquier otra actividad
   en el método derivado.
  </p>
  <div class="example-contents">
<div class="cdata"><pre>
MYSQLND_METHOD(my_conn_class, query)(MYSQLND *conn,
  const char *query, unsigned int query_len TSRMLS_DC) {

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

  query = &quot;SELECT &#039;query rewritten&#039; FROM DUAL&quot;;
  query_len = strlen(query);

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

  <p class="simpara">
   <strong>Extender propiedades</strong>
  </p>
  <p class="simpara">
   Un objeto <code class="literal">mysqlnd</code> 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 <code class="literal">mysqlnd</code>
   no pueden simplemente añadir propiedades a los objetos.
  </p>
  <p class="simpara">
   Datos arbitrarios (propiedades) pueden ser añadidos a los objetos
   <code class="literal">mysqlnd</code> utilizando una función apropiada de la
   familia <code class="literal">mysqlnd_plugin_get_plugin_&lt;object&gt;_data()</code>.
   Durante la asignación de un objeto, <code class="literal">mysqlnd</code> reserva
   un espacio al final del objeto para alojar un puntero
   <code class="literal">void *</code> hacia datos arbitrarios.
   <code class="literal">mysqlnd</code> reserva un espacio para un puntero
   <code class="literal">void *</code> por plugin.
  </p>
  <p class="simpara">
   La tabla siguiente muestra cómo calcular la posición de un puntero
   para un plugin específico:
  </p>
  <table id="mysqlnd.plugin.pointercalc" class="doctable table">
   <caption><strong>Cálculo de punteros para mysqlnd</strong></caption>
   
    <thead>
     <tr>
      <th>Dirección de memoria</th>
      <th>Contenido</th>
     </tr>

    </thead>

    <tbody class="tbody">
     <tr>
      <td>0</td>
      <td>Inicio de la estructura C del objeto mysqlnd</td>
     </tr>

     <tr>
      <td>n</td>
      <td>Fin de la estructura C del objeto mysqlnd</td>
     </tr>

     <tr>
      <td>n + (m x sizeof(void*))</td>
      <td>void* hacia los datos del objeto del plugin m-ésimo</td>
     </tr>

    </tbody>
   
  </table>

  <p class="simpara">
   Si planea hacer subclases de los constructores
   de los objetos <code class="literal">mysqlnd</code>, lo cual está permitido,
   debe tener esto en cuenta.
  </p>
  <p class="simpara">
   El código siguiente muestra cómo se extienden propiedades:
  </p>
  <div class="example-contents">
<div class="cdata"><pre>
/* 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-&gt;persistent);
    (*props)-&gt;query_counter = 0;
  }
  return props;
}
</pre></div>
  </div>

  <p class="simpara">
   El desarrollador del plugin es responsable de la gestión de la memoria
   asociada a los datos del plugin.
  </p>
  <p class="simpara">
   Se recomienda el uso del asignador de memoria <code class="literal">mysqlnd</code>
   para los datos del plugin. Estas funciones son nombradas
   utilizando la siguiente convención: <code class="literal">mnd_*loc()</code>.
   El asignador <code class="literal">mysqlnd</code> tiene algunas características muy útiles,
   como la posibilidad de utilizar un asignador de depuración en una compilación
   no depurada.
  </p>
  <table id="mysqlnd.plugin.subclass" class="doctable table">
   <caption><strong>Cuándo y cómo hacer una subclase</strong></caption>
   
    <thead>
     <tr>
      <th class="empty">&nbsp;</th>
      <th>¿Cuándo hacer una subclase?</th>
      <th>¿Cada instancia tiene su propia tabla de funciones privada?</th>
      <th>¿Cómo hacer una subclase?</th>
     </tr>

    </thead>

    <tbody class="tbody">
     <tr>
      <td>Conexión (MYSQLND)</td>
      <td>MINIT</td>
      <td>No</td>
      <td>mysqlnd_conn_get_methods()</td>
     </tr>

     <tr>
      <td>Juego de resultados (MYSQLND_RES)</td>
      <td>MINIT o después</td>
      <td>Sí</td>
      <td>mysqlnd_result_get_methods() o método del objeto de manipulación de la tabla de funciones</td>
     </tr>

     <tr>
      <td>Meta del juego de resultados (MYSQLND_RES_METADATA)</td>
      <td>MINIT</td>
      <td>No</td>
      <td>mysqlnd_result_metadata_get_methods()</td>
     </tr>

     <tr>
      <td>Consulta (MYSQLND_STMT)</td>
      <td>MINIT</td>
      <td>No</td>
      <td>mysqlnd_stmt_get_methods()</td>
     </tr>

     <tr>
      <td>Red (MYSQLND_NET)</td>
      <td>MINIT o después</td>
      <td>Sí</td>
      <td>mysqlnd_net_get_methods() o método del objeto de manipulación de la tabla de funciones</td>
     </tr>

     <tr>
      <td>Capa física (MYSQLND_PROTOCOL)</td>
      <td>MINIT o después</td>
      <td>Sí</td>
      <td>mysqlnd_protocol_get_methods() o método del objeto de manipulación de la tabla de funciones</td>
     </tr>

    </tbody>
   
  </table>

  <p class="simpara">
   No debe manipular las tablas de funciones después de MINIT si
   no está permitido según la tabla anterior.
  </p>
  <p class="simpara">
   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.
  </p>
  <p class="simpara">
   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.
  </p>
  <p class="simpara">
   La ventaja del enfoque con una tabla de funciones compartida es
   el rendimiento. No es necesario copiar una tabla de funciones
   para cada objeto.
  </p>
  <table id="mysqlnd.plugin.constatus" class="doctable table">
   <caption><strong>Estado del constructor</strong></caption>
   
    <thead>
     <tr>
      <th>Tipo</th>
      <th>Asignación, construcción, reinicialización</th>
      <th>¿Puede ser modificado?</th>
      <th>Llamante</th>
     </tr>

    </thead>

    <tbody class="tbody">
     <tr>
      <td>Conexión (MYSQLND)</td>
      <td>mysqlnd_init()</td>
      <td>No</td>
      <td>mysqlnd_connect()</td>
     </tr>

     <tr>
      <td>Juego de resultados (MYSQLND_RES)</td>
      <td><span class="simpara">
       Asignación:
       </span>
       <ul class="itemizedlist">
        <li class="listitem">
         <span class="simpara">
          Connection::result_init()
         </span>
        </li>
       </ul>
       <span class="simpara">
        Reinicio y reinicialización durante:
       </span>
       <ul class="itemizedlist">
        <li class="listitem">
         <span class="simpara">
          Result::use_result()
         </span>
        </li>
        <li class="listitem">
         <span class="simpara">
          Result::store_result
         </span>
        </li>
       </ul></td>
      <td>Sí, pero llamada al padre.</td>
      <td><ul class="itemizedlist">
       <li class="listitem">
        <span class="simpara">
         Connection::list_fields()
        </span>
       </li>
       <li class="listitem">
        <span class="simpara">
         Statement::get_result()
        </span>
       </li>
       <li class="listitem">
        <span class="simpara">
         Statement::prepare() (Meta-datos únicamente)
        </span>
       </li>
       <li class="listitem">
        <span class="simpara">
         Statement::resultMetaData()
        </span>
       </li>
       </ul></td>
     </tr>

     <tr>
      <td>Meta del juego de resultados (MYSQLND_RES_METADATA)</td>
      <td>Connection::result_meta_init()</td>
      <td>Sí, pero llamada al padre.</td>
      <td>Result::read_result_metadata()</td>
     </tr>

     <tr>
      <td>Consulta (MYSQLND_STMT)</td>
      <td>Connection::stmt_init()</td>
      <td>Sí, pero llamada al padre.</td>
      <td>Connection::stmt_init()</td>
     </tr>

     <tr>
      <td>Red (MYSQLND_NET)</td>
      <td>mysqlnd_net_init()</td>
      <td>No</td>
      <td>Connection::init()</td>
     </tr>

     <tr>
      <td>Capa física (MYSQLND_PROTOCOL)</td>
      <td>mysqlnd_protocol_init()</td>
      <td>No</td>
      <td>Connection::init()</td>
     </tr>

    </tbody>
   
  </table>

  <p class="simpara">
   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 <code class="literal">mysqlnd</code>
   así como para la lógica del objeto <code class="literal">mysqlnd</code>. 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.
  </p>
  <p class="simpara">
   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.
  </p>
  <table id="mysqlnd.plugin.deststatus" class="doctable table">
   <caption><strong>Estado del destructor</strong></caption>
   
    <thead>
     <tr>
      <th>Tipo</th>
      <th>¿El método derivado debe llamar al padre?</th>
      <th>Destructor</th>
     </tr>

    </thead>

    <tbody class="tbody">
     <tr>
      <td>Conexión</td>
      <td>Sí, después de la ejecución del método</td>
      <td>free_contents(), end_psession()</td>
     </tr>

     <tr>
      <td>Juego de resultados</td>
      <td>Sí, después de la ejecución del método</td>
      <td>free_result()</td>
     </tr>

     <tr>
      <td>Meta del juego de resultados</td>
      <td>Sí, después de la ejecución del método</td>
      <td>free()</td>
     </tr>

     <tr>
      <td>Consulta</td>
      <td>Sí, después de la ejecución del método</td>
      <td>dtor(), free_stmt_content()</td>
     </tr>

     <tr>
      <td>Red</td>
      <td>Sí, después de la ejecución del método</td>
      <td>free()</td>
     </tr>

     <tr>
      <td>Capa física</td>
      <td>Sí, después de la ejecución del método</td>
      <td>free()</td>
     </tr>

    </tbody>
   
  </table>

  <p class="simpara">
   Los destructores son los lugares perfectos para liberar propiedades,
   <code class="literal">mysqlnd_plugin_get_plugin_<span class="replaceable">&lt;object&gt;</span>_data()</code>.
  </p>
  <p class="simpara">
   Los destructores listados pueden no ser los equivalentes a
   los métodos actuales <code class="literal">mysqlnd</code> 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 <code class="literal">mysqlnd</code>.
  </p>
  <p class="simpara">
   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.
  </p>
 </div><?php manual_footer($setup); ?>