-
Notifications
You must be signed in to change notification settings - Fork 49
/
plugin.xml
1479 lines (1460 loc) · 48 KB
/
plugin.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision$ -->
<!-- EN-Revision: cd09fab47b40563cb8b2316d817efc973d991713 Maintainer: seros Status: ready -->
<!-- Reviewed: no -->
<chapter xml:id="mysqlnd.plugin" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>API de Complementos del Controlador Nativo de MySQL</title>
<para>
La API de Complementos del Controlador Nativo de MySQL es una característica del Controlador
Nativo de MySQL, o <literal>mysqlnd</literal>. Los complementos de
<literal>mysqlnd</literal> operan en la capa que hay entre las aplicaciones de PHP y el
servidor MySQL. Es comparable al Proxy de MySQL. El Proxy de MySQL opera sobre una
capa entre cualquier aplicación cliente de MySQL, por ejemplo, una aplicación
de PHP, y el servidor de MySQL. Los complementos de <literal>mysqlnd</literal>
can undertake typical MySQL Proxy tasks such as load balancing,
monitorizan y optimizan el rendimiento. A causa de la arquitectura
y ubicación diferentes, los complementos de <literal>mysqlnd</literal> no
tienen algunas de las desventajas del Proxy de MySQL. Por ejemplo, con los complementos
no existe un único punto de fallo, ni un servidor proxy para el
despliegue, y no hace falta aprender un nuevo lenguaje de programación (Lua).
</para>
<para>
Se puede pensar en un complemento de <literal>mysqlnd</literal> como una extensión
de <literal>mysqlnd</literal>. Los complementos pueden interceptar la mayoría de las
funciones de <literal>mysqlnd</literal>. Las funciones de
<literal>mysqlnd</literal> son llamadas por las extensiones de MySQl de PHP, como
<literal>ext/mysql</literal>, <literal>ext/mysqli</literal>, y
<literal>PDO_MYSQL</literal>. Como resultado, es posible que un complemento de
<literal>mysqlnd</literal> intercepte todas las llamadas hechas a estas
extensiones desde la apliacación cliente.
</para>
<para>
Las llamadas a funciones internas de <literal>mysqlnd</literal> también pueden ser
interceptadas o reemplazadas. No existen restricciones en la manipulación
de tablas de funciones internas de <literal>mysqlnd</literal>. Es posible
configurar cosas, y así cuando ciertas funciones de
<literal>mysqlnd</literal> son llamadas por extensiones que utilizan
<literal>mysqlnd</literal>, la llamada es dirigida a la función
apropiada del complemento de <literal>mysqlnd</literal>. La capacidad de
manipular tablas de funciones internas de <literal>mysqlnd</literal> de esta manera
permite una flexibilidad máxima para los complementos.
</para>
<para>
Los complementos de <literal>mysqlnd</literal> son de hecho Extensiones de PHP, escritos
en C, que utilizan la API de complementos de <literal>mysqlnd</literal> (la cual está
construida dentro del Controlador Nativo de MySQL, <literal>mysqlnd</literal>). Los complementos
se pueden hacer 100% transparentes a las aplicaciones de PHP. No es necesario hacer ningún
cambio a las aplicaciones ya que los complementos operan en una capa diferente. Se puede
pensar en los complementos de <literal>mysqlnd</literal> como en una operación en una
capa por debajo de <literal>mysqlnd</literal>.
</para>
<para>
La siguiente lista representa algunas aplicaciones posibles de los
complementos de <literal>mysqlnd</literal>.
</para>
<itemizedlist>
<listitem>
<para>
Equilibrio de Carga
</para>
<itemizedlist>
<listitem>
<para>
División de Lectura/Escritura. Un ejemplo de esto es la extensión
PECL/mysqlnd_ms (Maestro Esclavo). Esta extensión divide las consultas de lectura/escritura
para una configuración de réplica.
</para>
</listitem>
<listitem>
<para>
Tolerancia a fallos
</para>
</listitem>
<listitem>
<para>
Rotación de servidores para evitar la sobrecarga ("Round-Robin")
</para>
</listitem>
</itemizedlist>
</listitem>
<listitem>
<para>
Monitorización
</para>
<itemizedlist>
<listitem>
<para>
Registro de Consultas
</para>
</listitem>
<listitem>
<para>
Análisis de Consultas
</para>
</listitem>
<listitem>
<para>
Audición de Consultas. Un ejemplo de esto es la extensión PECL/mysqlnd_sip (Protección
contra la Inyección SQL). Esta extensión inspecciona las consultas
y ejecuta únicamente aquellas que están permitidas según un cojunto de reglas.
</para>
</listitem>
</itemizedlist>
</listitem>
<listitem>
<para>
Rendimiento
</para>
<itemizedlist>
<listitem>
<para>
Almacenamiento en Caché. Un ejemplo de esto es la extenión PECL/mysqlnd_qc
(Caché de Consultas).
</para>
</listitem>
<listitem>
<para>
Estrangulamiento ("Throttling")
</para>
</listitem>
<listitem>
<para>
Fragmentación. Un ejemplo de esto es la extensión PECL/mysqlnd_mc
(Multiconexión). Esta extensión intentará dividir una sentencia SELECT
en n partes, usando SELECT ... LIMIT parte_1, SELECT
LIMIT parte_n. Envía las consultas a diferentes servidores MySQL y
combina el resultado en el cliente.
</para>
</listitem>
</itemizedlist>
</listitem>
</itemizedlist>
<para>
<emphasis role="bold">Complementos del Controlador Nativo de MySQL disponibles</emphasis>
</para>
<para>
Hay varios complementos de mysqlnd ya disponibles. Estos
incluyen:
</para>
<itemizedlist>
<listitem>
<para>
<emphasis role="bold">PECL/mysqlnd_mc</emphasis> - Complemento de
Multiconexión.
</para>
</listitem>
<listitem>
<para>
<emphasis role="bold">PECL/mysqlnd_ms</emphasis> - Complemento
Maestro Esclavo.
</para>
</listitem>
<listitem>
<para>
<emphasis role="bold">PECL/mysqlnd_qc</emphasis> - Complemento de
Caché de Consultas.
</para>
</listitem>
<listitem>
<para>
<emphasis role="bold">PECL/mysqlnd_pscache</emphasis> - Complemento de
Caché de Gestores de Sentencias Preparadas.
</para>
</listitem>
<listitem>
<para>
<emphasis role="bold">PECL/mysqlnd_sip</emphasis> - Complemento de
Protección contra Inyección SQL.
</para>
</listitem>
<listitem>
<para>
<emphasis role="bold">PECL/mysqlnd_uh</emphasis> - Complemento de
Gestor de Usuarios.
</para>
</listitem>
</itemizedlist>
<section xml:id="mysqlnd.plugin.mysql-proxy">
<title>Una comparación de los complementos de mysqlnd y el Proxy de MySQL</title>
<para>
Los complementos de <literal>mysqlnd</literal> y el Proxy de MySQL son diferentes
tecnologías que utilizan diferentes enfoques. Ambos son herramientas válidas para
resolver una variedad de tareas comunes tales como el equilibrio de carga, monitorización,
y mejoras en el rendimiento. Una diferencia importante es que el Proxy de
MySQL funciona con todos los clientes de MySQL, mientras que los
complementos de <literal>mysqlnd</literal> son específicos de aplicaciones de PHP.
</para>
<para>
Al igual que una Extensión de PHP, un complemento de <literal>mysqlnd</literal> se
instala en el servidor de aplicaciones de PHP, junto con el resto de PHP.
El Proxy de MySQL puede ejecutarse sobre el servidor de aplicaciones de PHP o ser
instalado en una máquina dedicada para manejar múltiples servidores de aplicaciones
de PHP.
</para>
<para>
El despliegue del Proxy de MySQL sobre un servidor de aplicaciones tiene dos ventajas:
</para>
<orderedlist>
<listitem>
<para>
No tiene un único punto de fallo
</para>
</listitem>
<listitem>
<para>
Fácil escalabilidad (escalabilidad horizontal, escalabilidad por cliente)
</para>
</listitem>
</orderedlist>
<para>
El Proxy de MySQL (y los complementos de <literal>mysqlnd</literal>) pueden resolver
problemas fácilmente que de otro modo requerirían cambios en las
aplicaciones existentes.
</para>
<para>
Sin embargo, el Proxy de MySQL tiene algunas desventajas:
</para>
<itemizedlist>
<listitem>
<para>
El Proxy de MySQL es un componente y una tecnología nuevos que son necesarios llegar a dominar y desplegar.
</para>
</listitem>
<listitem>
<para>
El Proxy de MySQL requiere conocimientos del lenguaje de scripts Lua.
</para>
</listitem>
</itemizedlist>
<para>
El Proxy de MySQL puede ser personalizado con programación en C y Lua. Lua es el
lenguaje de scripts preferido del Proxy de MySQL. Para la mayoría de los expertos en PHP, Lua
es un nuevo lenguaje que aprender. Un complemento de <literal>mysqlnd</literal> puede
ser escrito en C. También es posible escribir complementos en PHP usando
<link xlink:href="http://pecl.php.net/package/mysqlnd_uh">PECL/mysqlnd_uh</link>.
</para>
<para>
El Proxy de MySQL se ejecuta como un demonio - un proceso en segundo plano. El Proxy de MySQL puede
recordar decisiones anteriores, ya que todos los estados pueden ser guardados. Sin embargo, un
complemento de <literal>mysqlnd</literal> está vinculado al ciclo de vida basado en
peticiones de PHP. El Proxy de MySQL también comparte resultados computados una única
vez entre múltiples servidores de aplicaciones. Un
complemento de <literal>mysqlnd</literal> necesitaría almacenar los datos en un
medio persistente para poder hacer esto. Sería necesario otro demonio
para este propósito, tal como Memcache. Esto otorga al Proxy de MySQL una
ventaja en este caso.
</para>
<para>
El Proxy de MySQL funciona en lo más alto del protocolo de cable. Con el Proxy de MySQL se
ha de analizar y usar ingenierá inversa con el Protocolo Cliente Servidor de MySQL.
Las acciones están limitadas a aquellas que pueden realizarse manipulando el
protocolo de comunicación. Si el protocolo de calbe cambia (lo que ocurre
muy raramente), los scripts del Proxy de MySQL necesitarían cambiarse también.
</para>
<para>
Los complementos de <literal>Mysqlnd</literal> funcionan en lo más alto de la API en C, la cual
refleja el cliente <literal>libmysqlclient</literal> y las APIs Connector/C.
ESta API en C es básicamente una envoltura sobre el protocolo Cliente Servidor de
MySQL, o protocolo de cable, como es llamado a veces. Se pueden
interceptar todas las llamadas a la API en C. PHP hace uso de la API en C, por lo que se
pueden enganchar todas las llamadas de PHP, sin necesidad de programar en el nivel del
protocolo de cable.
</para>
<para>
<literal>Mysqlnd</literal> implementa el protocolo de cable. Los complementos pueden,
por lo tanto, analizar, usar ingeniería inversa, manipular e incluso reemplazar el
protocolo de comunicación. Sin embargo, esto normalmente no es necesario.
</para>
<para>
Ya que los complementos permiten crear implementaciones que utilizan dos niveles (la API
en C y el protocolo de cable), tienen más flexibilidad que el Proxy de
MySQL. Si un complemento de <literal>mysqlnd</literal> es implementado usando
la API en C, cualquier cambio subsiguiente al protocolo de cable no requerirá
cambios en el complemento en sí.
</para>
</section>
<section xml:id="mysqlnd.plugin.obtaining">
<title>Obtener la API de complementos de mysqlnd</title>
<para>
La API de complementos de <literal>mysqlnd</literal> es sencillamente parte de la extensión del
Controlador Nativo de MySQL de PHP, <literal>ext/mysqlnd</literal>.
El desarrollo de la API de complementos de <literal>mysqlnd</literal> comenzó en
diciembre de 2009. Está desarrollado como parte del repositorio fuente de PHP,
y como tal está disponible al público vía Git, o a través de
las descargas de instantáneas del código fuente.
</para>
<para>
La siguiente tabla muestra las versiones de PHP y la versión correspondiente
de <literal>mysqlnd</literal> contenida dentro.
</para>
<table>
<title>La versión incluída de mysqlnd por versión de PHP</title>
<tgroup cols="2">
<thead>
<row>
<entry>Versión de PHP</entry>
<entry>Versión del Controlador Nativo de MySQL</entry>
</row>
</thead>
<tbody>
<row>
<entry>5.3.0</entry>
<entry>5.0.5</entry>
</row>
<row>
<entry>5.3.1</entry>
<entry>5.0.5</entry>
</row>
<row>
<entry>5.3.2</entry>
<entry>5.0.7</entry>
</row>
<row>
<entry>5.3.3</entry>
<entry>5.0.7</entry>
</row>
<row>
<entry>5.3.4</entry>
<entry>5.0.7</entry>
</row>
</tbody>
</tgroup>
</table>
<para>
Los desarrolladores de complementos pueden determinar la versión de <literal>mysqlnd</literal>
accediendo a <literal>MYSQLND_VERSION</literal>, que
es una cadena en el formato <quote>mysqlnd 5.0.7-dev - 091210 -
$Revision: 300535</quote>, o a través de
<literal>MYSQLND_VERSION_ID</literal>, que es un valor integer tal como
50007. Los desarrolladores pueden calcular el número de versión como sigue:
</para>
<table>
<title>Tabla de cálculo de MYSQLND_VERSION_ID</title>
<tgroup cols="2">
<thead>
<row>
<entry>Versión (parte)</entry>
<entry>Ejemplo</entry>
</row>
</thead>
<tbody>
<row>
<entry>Mayor*10000</entry>
<entry>5*10000 = 50000</entry>
</row>
<row>
<entry>Menor*100</entry>
<entry>0*100 = 0</entry>
</row>
<row>
<entry>Parche</entry>
<entry>7 = 7</entry>
</row>
<row>
<entry>MYSQLND_VERSION_ID</entry>
<entry>50007</entry>
</row>
</tbody>
</tgroup>
</table>
<para>
Durante el desarrollo, los desarroladores deberían consultar el
número de versión de <literal>mysqlnd</literal> por compatibilidad y
pruebas de versión, ya que varias iteraciones de <literal>mysqlnd</literal>
podrían ocurrir durante el ciclo de vida de una rama de desarrollo de PHP con un
número de versión de PHP único.
</para>
</section>
<section xml:id="mysqlnd.plugin.architecture">
<title>Arquitectura de los Complementos del Controlador Nativo de MySQL</title>
<para>
Esta sección proporciona información general de la arquitectura de los
complementos de <literal>mysqlnd</literal>.
</para>
<para>
<emphasis role="bold">Información general del Controlador Nativo de MySQL</emphasis>
</para>
<para>
Antes de desarrollar complementos de <literal>mysqlnd</literal>, es útil
conocer un poco cómo <literal>mysqlnd</literal> está organizado.
<literal>Mysqlnd</literal> consiste en los siguientes módulos:
</para>
<table>
<title>La gráfica de organización de mysqlnd, por módulo</title>
<tgroup cols="2">
<tbody>
<row>
<entry>Módulos de estadísticas</entry>
<entry>mysqlnd_statistics.c</entry>
</row>
<row>
<entry>Conexión</entry>
<entry>mysqlnd.c</entry>
</row>
<row>
<entry>Conjunto de resultados</entry>
<entry>mysqlnd_result.c</entry>
</row>
<row>
<entry>Metadatos de conjuntos de resultados</entry>
<entry>mysqlnd_result_meta.c</entry>
</row>
<row>
<entry>Sentencia</entry>
<entry>mysqlnd_ps.c</entry>
</row>
<row>
<entry>Red</entry>
<entry>mysqlnd_net.c</entry>
</row>
<row>
<entry>Protocolo de cable</entry>
<entry>mysqlnd_wireprotocol.c</entry>
</row>
</tbody>
</tgroup>
</table>
<para>
<emphasis role="bold">Paradigma de la orientación a objetos de C</emphasis>
</para>
<para>
A nivel de código, <literal>mysqlnd</literal> utiliza un patrón de C para
implementar la orientación a objetos.
</para>
<para>
En C se utiliza una estrucutra (<literal>struct</literal>) para representar un objeto.
Los miembros de la estructura representan las propiedades del objeto. Los miembros de la estrucutra
que apuntan a funciones representan los métodos.
</para>
<para>
A diferencia de otros lenguajes como C++ o Java, no existen reglas fijas
sobre herencia en el paradigma de la orientación a objetos de C. Sin embargo,
existen algunas convenciones que se han de seguir y serán discutidas
más tarde.
</para>
<para>
<emphasis role="bold">El ciclo de vida de PHP</emphasis>
</para>
<para>
Al considerar el ciclo de vida de PHP existen dos ciclos básicos:
</para>
<itemizedlist>
<listitem>
<para>
El ciclo de inicio y cierre del motor de PHP
</para>
</listitem>
<listitem>
<para>
El ciclo de peticiones
</para>
</listitem>
</itemizedlist>
<para>
Cuando se inicia el motor de PHP, éste llamará a la función de inicialización de
módulos (MINIT) para cada extensión registrada. Esto permite a cada
módulo establecer variables y asignar recursos que existirán durante
el tiempo de vida del proceso del motor de PHP. Al cerrar el motor de PHP,
éste llamará a las funciones de cierre de módulos (MSHUTDOWN) para cada
extensión.
</para>
<para>
Durante el tiempo de vida del motor de PHP, éste recibirá varias
peticiones. Cada petición constituye otro ciclo de vida. En cada
petición, el motor de PHP llamará a la función de inicialización de peticiones
para cada extensión. La extensión puede realizar cualquier establecimiento de variables y
asignación de recursos necesarios para el proceso de petición. Al finalizar el ciclo
de peticiones, el motor llama a la función de cierre de peticiones (RSHUTDOWN)
de cada extensión, por lo que la extensión puede realizar cualquier limpieza necesaria.
</para>
<para>
<emphasis role="bold">Cómo funciona un complemento</emphasis>
</para>
<para>
Un complemento de <literal>mysqlnd</literal> funciona interceptando llamada realizadas
a <literal>mysqlnd</literal> por extensiones que utilizan
<literal>mysqlnd</literal>. Esto se lleva a cabo obteniendo la
tabla de funciones de <literal>mysqlnd</literal>, haciendo una copia de seguridad de ella, y
reemplazándola por una tabla de funciones personalizada, la cual llamará a las funciones del
complemento cuando sea necesario.
</para>
<para>
El siguiente código muestra cómo se reemplaza la tabla de
funciones de <literal>mysqlnd</literal>:
</para>
<programlisting>
<![CDATA[
/* un lugar para almacenar la tabla de funciones original */
struct st_mysqlnd_conn_methods org_methods;
void minit_register_hooks(TSRMLS_D) {
/* activar la tabla de funciones */
struct st_mysqlnd_conn_methods * current_methods
= mysqlnd_conn_get_methods();
/* copiar la tabla de funciones original */
memcpy(&org_methods, current_methods,
sizeof(struct st_mysqlnd_conn_methods);
/* instalar nuevos métodos */
current_methods->query = MYSQLND_METHOD(my_conn_class, query);
}
]]>
</programlisting>
<para>
La manipulación de la tabla de funciones de conexión debe hacerse durante la
Inicialización de Módulos (MINIT). La tabla de funciones es un recurso global
compartido. En un entorno multihilo, con un TSRM construido, la
manipulación de un recurso global compartido durante el proceso de
peticiones resultará en conflictos casi con toda seguridad.
</para>
<note>
<para>
No utilice cualquier lógica de tamaña fijo al manipular la
tablas de funciones de <literal>mysqlnd</literal>: los métodos nuevos se pueden añadir
al final de la tabla de funciones. La tabla de funciones puede cambiar en
cualquier momento en el futuro.
</para>
</note>
<para>
<emphasis role="bold">Llamar a métodos padre</emphasis>
</para>
<para>
Si las entradas de la tabla de funciones original está copiada, aún es
posible llamar a las entradas de la tabla de funciones original - los métodos
padre.
</para>
<para>
En algunos casos, como en
<literal>Connection::stmt_init()</literal>, es vital llamar al
método padre antes de realizar cualquier otra actividad en el método derivado.
</para>
<programlisting>
<![CDATA[
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 */
}
]]>
</programlisting>
<para>
<emphasis role="bold">Extender propiedades</emphasis>
</para>
<para>
Un objeto <literal>mysqlnd</literal> está representado por una estrucutra de C.
No es posible añadir un miembro a una estructura de C en tiempo de ejecución. Los usuarios de
objetos <literal>mysqlnd</literal> no pueden simplemente añadir propiedades a
los objetos.
</para>
<para>
Se pueden añadir datos arbitrarios (propiedades) a
objetos <literal>mysqlnd</literal> usando la función apropiada
de la familia de
<literal>mysqlnd_plugin_get_plugin_<object>_data()</literal>.
Cuando se asigna un objeto, <literal>mysqlnd</literal> reserva
espacio al final del objeto para que contenga un puntero
<literal>void *</literal> a datos arbitrarios. <literal>mysqlnd</literal> reserva espacio
para un puntero <literal>void *</literal> por complemento.
</para>
<para>
La siguiente tabla muestra cómo calcular la posición del
puntero para un complemento específico:
</para>
<table>
<title>Cálculos de puntero para mysqlnd</title>
<tgroup cols="2">
<tbody>
<row>
<entry>Dirección de memoria</entry>
<entry>Contenido</entry>
</row>
<row>
<entry>0</entry>
<entry>Inicio de la estructura de C del objeto mysqlnd</entry>
</row>
<row>
<entry>n</entry>
<entry>Fin de la estructura de C del objeto mysqlnd</entry>
</row>
<row>
<entry>n + (m x sizeof(void*))</entry>
<entry>void* a los datos del objeot del complemento m-ésimo</entry>
</row>
</tbody>
</tgroup>
</table>
<para>
Si se planea usar cualquier constructor de objetos <literal>mysqlnd</literal>
en subclases, lo cual está permitido, ¡se debe tener esto en cuenta!
</para>
<para>
El siguiente código muestra la extensión de propiedades:
</para>
<programlisting>
<![CDATA[
/* cualquier dato que queramos asociar */
typedef struct my_conn_properties {
unsigned long query_counter;
} MY_CONN_PROPERTIES;
/* id del complemento */
unsigned int my_plugin_id;
void minit_register_hooks(TSRMLS_D) {
/* obtener un ID único para el complemento */
my_plugin_id = mysqlnd_plugin_register();
/* recorte - véase Extender conexiones: 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;
}
]]>
</programlisting>
<para>
El desarrollador del complemento es responsable de la gestión de memoria de lo datos
del complemento.
</para>
<para>
Se recomienda el uso del asignador de memoria de <literal>mysqlnd</literal>
para los datos del complemento. Estas funciones son nombradas usando la convención:
<literal>mnd_*loc()</literal>. El asignador de <literal>mysqlnd</literal>
tiene algunas características útiles, como la capacidad de usar un
asignador de depuración en una construcción de no depuración.
</para>
<table>
<title>Cuándo y cómo usar subclases</title>
<tgroup cols="4">
<tbody>
<row>
<entry></entry>
<entry>¿Cuándo usar subclases?</entry>
<entry>¿Cada instancia tiene su propia tabla de funciones privada?</entry>
<entry>¿Cómo usar subclases?</entry>
</row>
<row>
<entry>Conexión (MYSQLND)</entry>
<entry>MINIT</entry>
<entry>No</entry>
<entry>mysqlnd_conn_get_methods()</entry>
</row>
<row>
<entry>Conjunto de resultados (MYSQLND_RES)</entry>
<entry>MINIT o después</entry>
<entry>Sí</entry>
<entry>mysqlnd_result_get_methods() o manipulación de la tabla de funciones
de métodos de objetos</entry>
</row>
<row>
<entry>Metadatos de conjunto de resultados (MYSQLND_RES_METADATA)</entry>
<entry>MINIT</entry>
<entry>No</entry>
<entry>mysqlnd_result_metadata_get_methods()</entry>
</row>
<row>
<entry>Sentencia (MYSQLND_STMT)</entry>
<entry>MINIT</entry>
<entry>No</entry>
<entry>mysqlnd_stmt_get_methods()</entry>
</row>
<row>
<entry>Red (MYSQLND_NET)</entry>
<entry>MINIT o después</entry>
<entry>Sí</entry>
<entry>mysqlnd_net_get_methods() o manipulación de la tabla de funciones de métodos de objetos</entry>
</row>
<row>
<entry>Protocolo de cable (MYSQLND_PROTOCOL)</entry>
<entry>MINIT o después</entry>
<entry>Sí</entry>
<entry>mysqlnd_protocol_get_methods() o manipulación de la tabla de funciones
de métodos de objetos</entry>
</row>
</tbody>
</tgroup>
</table>
<para>
No se deben manipular las tablas de funciones en ningún momento posterior a MINIT
si no está permitido según la tabla de arriba.
</para>
<para>
Algunas clases contienen un puntero a la tabla de funciones de métodos. Todas
las instancias de esas clases compartirán la misma tabla de funciones. Para
evitar el caos, en particular en entornos de hilos, tales tablas de
funciones deben ser manipuladas solamente durante MINIT.
</para>
<para>
Otras clases usan copias de una tabla de funciones compartida globalmente. La
copia de la tabla de funciones de la clase se crea junto con el objeto. Cada
objeto usa su propia tabla de funciones. Esto proporciona dos opciones:
se puede manipular la tabla de funciones predetermiada de un objeto durante MINIT, y
además se pueden perfeccionar métodos de un objeto sin impactar
otras instancias de la misma clase.
</para>
<para>
La ventaja del enfoque de la tabla de funciones compartida es el rendimiento.
No hay necesidad de copiar una tabla de funciones para cada objeto.
</para>
<table>
<title>Estado del constructor</title>
<tgroup cols="4">
<tbody>
<row>
<entry></entry>
<entry>Asignación, construcción, reinicio</entry>
<entry>¿Se puede modificar?</entry>
<entry>Llamador</entry>
</row>
<row>
<entry>Conexión (MYSQLND)</entry>
<entry>mysqlnd_init()</entry>
<entry>No</entry>
<entry>mysqlnd_connect()</entry>
</row>
<row>
<entry>Conjunto de resultados (MYSQLND_RES)</entry>
<entry><para>
Asignación:
</para>
<itemizedlist>
<listitem>
<para>
Connection::result_init()
</para>
</listitem>
</itemizedlist>
<para>
Reinicio y reinicialización durante:
</para>
<itemizedlist>
<listitem>
<para>
Result::use_result()
</para>
</listitem>
<listitem>
<para>
Result::store_result
</para>
</listitem>
</itemizedlist></entry>
<entry>Sí, ¡pero se ha de llamar al padre!</entry>
<entry><itemizedlist>
<listitem>
<para>
Connection::list_fields()
</para>
</listitem>
<listitem>
<para>
Statement::get_result()
</para>
</listitem>
<listitem>
<para>
Statement::prepare() (Solamente metadatos)
</para>
</listitem>
<listitem>
<para>
Statement::resultMetaData()
</para>
</listitem>
</itemizedlist></entry>
</row>
<row>
<entry>Metadatos de conjunto de resultados (MYSQLND_RES_METADATA)</entry>
<entry>Connection::result_meta_init()</entry>
<entry>Sí, ¡pero se ha de llamar al padre!</entry>
<entry>Result::read_result_metadata()</entry>
</row>
<row>
<entry>Sentecia (MYSQLND_STMT)</entry>
<entry>Connection::stmt_init()</entry>
<entry>Sí, ¡pero se ha de llamar al padre!</entry>
<entry>Connection::stmt_init()</entry>
</row>
<row>
<entry>Red (MYSQLND_NET)</entry>
<entry>mysqlnd_net_init()</entry>
<entry>No</entry>
<entry>Connection::init()</entry>
</row>
<row>
<entry>Protocolo de cable (MYSQLND_PROTOCOL)</entry>
<entry>mysqlnd_protocol_init()</entry>
<entry>No</entry>
<entry>Connection::init()</entry>
</row>
</tbody>
</tgroup>
</table>
<para>
Se recomienda encarecidamente que no se reemplace completamente un
constructor. Los constructores realizan asignaciones de memoria. Las asignaciones
de memoria son vitales para la API de complementos de <literal>mysqlnd</literal>
y la lógida de objetos de <literal>mysqlnd</literal>. Si no se tiene
cuidado con las advertencias y se insiste en enganchar los constructores, se
debería, al menos, llamar al constructor padre antes de hacer nada en el
constructor derivado.
</para>
<para>
A pesar de todas las advertencias, puede ser útil usar subclases para
los constructores. Éstos son el lugar perfecto para modificar las
tablas de funciones de objetos con tablas de objetos no compartidas, como
Conjunto de resultados, Red, Protocolo de cable.
</para>
<table>
<title>Estado de la destrucción</title>
<tgroup cols="3">
<tbody>
<row>
<entry></entry>
<entry>¿Debe el método derivado llamar al padre?</entry>
<entry>Destructor</entry>
</row>
<row>
<entry>Conexión</entry>
<entry>sí, después de la ejecución del método</entry>
<entry>free_contents(), end_psession()</entry>
</row>
<row>
<entry>Conjunto de resultados</entry>
<entry>sí, después de la ejecución del método</entry>
<entry>free_result()</entry>
</row>
<row>
<entry>Metadatos del conjunto de resultados</entry>
<entry>sí, después de la ejecución del método</entry>
<entry>free()</entry>
</row>
<row>
<entry>Sentencia</entry>
<entry>sí, después de la ejecución del método</entry>
<entry>dtor(), free_stmt_content()</entry>
</row>
<row>
<entry>Red</entry>
<entry>sí, después de la ejecución del método</entry>
<entry>free()</entry>
</row>
<row>
<entry>Protocolo de cable</entry>
<entry>sí, después de la ejecución del método</entry>
<entry>free()</entry>
</row>
</tbody>
</tgroup>
</table>
<para>
Los destructores son los lugares apropiados para liberar propiedades
<literal>mysqlnd_plugin_get_plugin_<replaceable><objeto></replaceable>_data()</literal>.
</para>
<para>
Los destructores listados podrían no ser equivalentes a los métodos reales de
<literal>mysqlnd</literal> que liberan el objeto en sí. Sin embargo,
son el mejor lugar posible para enganchar y liberar los datos
de los complementos. Como sucede con los constructores se pueden reemplazar los
métodos completamente, pero no se recomienda. Si se listan múltiles métodos
en la tabla de arriba, se necesitará enganchar todos esos métodos
y liberar los datos del complemento en el método correspondiente que sea llamado primero por
<literal>mysqlnd</literal>.
</para>
<para>
El método recomendado para los complementos es simplemente enganchar los métodos,
liberar la memoria y llamar a la implementación padre inmediatamente
después de esto.
</para>
<caution>
<para>
Debido a un error en las versiones de PHP 5.3.0 hasta 5.3.3, los complementos no
asocian los datos de los complementos con una conexión persistente. Esto es debido a que
<literal>ext/mysql</literal> y <literal>ext/mysqli</literal>
no desencadenan las llamadas necesarias al método <literal>end_psession()</literal>
de <literal>mysqlnd</literal>, y el complemento podría,
por lo tanto, perder memoria. Esto ha sido corregido en PHP 5.3.4.
</para>
</caution>
</section>
<section xml:id="mysqlnd.plugin.api">
<title>La API de complementos de mysqlnd</title>
<para>
La siguiente es una lista de funciones proporcionadas en la
API de complementos de <literal>mysqlnd</literal>:
</para>
<itemizedlist>
<listitem>
<para>
mysqlnd_plugin_register()
</para>
</listitem>
<listitem>
<para>
mysqlnd_plugin_count()
</para>
</listitem>
<listitem>
<para>
mysqlnd_plugin_get_plugin_connection_data()
</para>
</listitem>
<listitem>
<para>
mysqlnd_plugin_get_plugin_result_data()
</para>
</listitem>
<listitem>
<para>
mysqlnd_plugin_get_plugin_stmt_data()
</para>
</listitem>
<listitem>
<para>
mysqlnd_plugin_get_plugin_net_data()
</para>
</listitem>
<listitem>
<para>
mysqlnd_plugin_get_plugin_protocol_data()
</para>
</listitem>
<listitem>
<para>
mysqlnd_conn_get_methods()
</para>
</listitem>
<listitem>
<para>
mysqlnd_result_get_methods()
</para>
</listitem>
<listitem>
<para>
mysqlnd_result_meta_get_methods()
</para>
</listitem>
<listitem>
<para>
mysqlnd_stmt_get_methods()
</para>
</listitem>
<listitem>
<para>
mysqlnd_net_get_methods()
</para>
</listitem>
<listitem>
<para>
mysqlnd_protocol_get_methods()
</para>
</listitem>
</itemizedlist>
<para>
No existe una definción formal de lo que es un complemento y cómo funciona el
mecanismo de un complemento.
</para>
<para>
Los componentes que se encuentran a menudo en los mecanismos de los complementos son:
</para>
<itemizedlist>
<listitem>
<para>
Un gestor de complemento
</para>
</listitem>
<listitem>
<para>
Una API de complemento
</para>
</listitem>
<listitem>
<para>
Servicios de aplicación (o módulos)
</para>
</listitem>
<listitem>
<para>
APIs de servicios de aplicación (o APIs de módulos)
</para>
</listitem>
</itemizedlist>
<para>
El concepto de complemento de <literal>mysqlnd</literal> emplea estas características,
y además disgruta de una arquitectura abierta.
</para>
<para>
<emphasis role="bold">Sin restricciones</emphasis>
</para>