Es ist wichtig zu bedenken, dass ein mysqlnd-Plugin
   selbst eine PHP-Erweiterung ist.
  
   Der folgende Code zeigt die grundlegende Struktur der MINIT-Funktion, die
   in einem typischen mysqlnd-Plugin verwendet wird:
  
/* my_php_mysqlnd_plugin.c */
 static PHP_MINIT_FUNCTION(mysqlnd_plugin) {
  /* Globals, ini-Einträge, Ressourcen, Klassen */
  /* Registrieren des mysqlnd-Plugins */
  mysqlnd_plugin_id = mysqlnd_plugin_register();
  conn_m = mysqlnd_get_conn_methods();
  memcpy(org_conn_m, conn_m,
    sizeof(struct st_mysqlnd_conn_methods));
  conn_m->query = MYSQLND_METHOD(mysqlnd_plugin_conn, query);
  conn_m->connect = MYSQLND_METHOD(mysqlnd_plugin_conn, connect);
}
/* my_mysqlnd_plugin.c */
 enum_func_status MYSQLND_METHOD(mysqlnd_plugin_conn, query)(/* ... */) {
  /* ... */
}
enum_func_status MYSQLND_METHOD(mysqlnd_plugin_conn, connect)(/* ... */) {
  /* ... */
}
Analyse der Aufgaben: von C zum Userspace
 class proxy extends mysqlnd_plugin_connection {
  public function connect($host, ...) { .. }
}
mysqlnd_plugin_set_conn_proxy(new proxy());
Ablauf:
PHP: Benutzer registriert den Plugin-Callback
PHP: Benutzer ruft eine beliebige PHP-MySQL-API auf, um sich mit MySQL zu verbinden
C: ext/*mysql* ruft die mysqlnd-Methode auf
C: mysqlnd endet in ext/mysqlnd_plugin
C: ext/mysqlnd_plugin
Ruft einen benutzerdefinierten Callback auf
        oder die ursprüngliche mysqlnd-Methode, wenn der
        Userspace-Callback nicht definiert ist
       
Folgende Aufgaben sind dafür auszuführen:
In C eine Klasse namens "mysqlnd_plugin_connection" erstellen
Ein Proxy-Objekt mittels "mysqlnd_plugin_set_conn_proxy()" annehmen und registrieren
Userspace-Proxy-Methoden aus C aufrufen (Optimierung - zend_interfaces.h)
   Die Methoden von Userspace-Objekten können entweder mittels
   call_user_function() aufgerufen werden oder auf einer
   Ebene näher an der Zend Engine mittels
   zend_call_method().
  
Optimierung: Aufruf von Methoden aus C mit zend_call_method
   Der folgende Codeschnipsel zeigt den Prototyp für die Funktion
   zend_call_method und stammt aus
   zend_interfaces.h.
  
ZEND_API zval* zend_call_method( zval **object_pp, zend_class_entry *obj_ce, zend_function **fn_proxy, char *function_name, int function_name_len, zval **retval_ptr_ptr, int param_count, zval* arg1, zval* arg2 TSRMLS_DC );
Die Zend-API erlaubt nur zwei Parameter. Eventuell werden mehr benötigt, zum Beispiel:
enum_func_status (*func_mysqlnd_conn__connect)( MYSQLND *conn, const char *host, const char * user, const char * passwd, unsigned int passwd_len, const char * db, unsigned int db_len, unsigned int port, const char * socket, unsigned int mysql_flags TSRMLS_DC );
   Um dieses Problem zu umgehen, muss eine Kopie von
   zend_call_method() erzeugt werden, die mit zusätzlichen
   Parametern versehen werden kann. Dafür kann eine Reihe von
   MY_ZEND_CALL_METHOD_WRAPPER-Makros erstellt werden.
  
Aufruf des PHP-Userspaces
Dieser Codeschnipsel zeigt die optimierte Methode für den Aufruf einer Userspace-Funktion von C aus:
/* my_mysqlnd_plugin.c */
MYSQLND_METHOD(my_conn_class,connect)(
  MYSQLND *conn, const char *host /* ... */ TSRMLS_DC) {
  enum_func_status ret = FAIL;
  zval * global_user_conn_proxy = fetch_userspace_proxy();
  if (global_user_conn_proxy) {
    /* Aufrufen eines Userspace-Proxys */
    ret = MY_ZEND_CALL_METHOD_WRAPPER(global_user_conn_proxy, host, /*...*/);
  } else {
    /* oder die ursprüngliche mysqlnd-Methode = nichts tun, transparent sein */
    ret = org_methods.connect(conn, host, user, passwd,
          passwd_len, db, db_len, port,
          socket, mysql_flags TSRMLS_CC);
  }
  return ret;
}
Aufruf des Userspaces: einfache Argumente
/* my_mysqlnd_plugin.c */
 MYSQLND_METHOD(my_conn_class,connect)(
  /* ... */, const char *host, /* ...*/) {
  /* ... */
  if (global_user_conn_proxy) {
    /* ... */
    zval* zv_host;
    MAKE_STD_ZVAL(zv_host);
    ZVAL_STRING(zv_host, host, 1);
    MY_ZEND_CALL_METHOD_WRAPPER(global_user_conn_proxy, zv_retval, zv_host /*, ...*/);
    zval_ptr_dtor(&zv_host);
    /* ... */
  }
  /* ... */
}
Aufruf des Userspaces: Strukturen als Argumente
/* my_mysqlnd_plugin.c */
MYSQLND_METHOD(my_conn_class, connect)(
  MYSQLND *conn, /* ...*/) {
  /* ... */
  if (global_user_conn_proxy) {
    /* ... */
    zval* zv_conn;
    ZEND_REGISTER_RESOURCE(zv_conn, (void *)conn, le_mysqlnd_plugin_conn);
    MY_ZEND_CALL_METHOD_WRAPPER(global_user_conn_proxy, zv_retval, zv_conn, zv_host /*, ...*/);
    zval_ptr_dtor(&zv_conn);
    /* ... */
  }
  /* ... */
}
   Bei vielen mysqlnd-Methoden ist das erste Argument ein
   C-"Objekt". Zum Beispiel ist das erste Argument der Methode connect() ein
   Zeiger auf MYSQLND. Die Struktur MYSQLND stellt ein
   mysqlnd-Verbindungsobjekt dar.
  
   Der Zeiger auf das mysqlnd-Verbindungsobjekt kann mit
   einem Standard-I/O-Dateihandle verglichen werden. Genau wie ein
   Standard-I/O-Dateihandle muss ein
   mysqlnd-Verbindungsobjekt mit Hilfe einer PHP-Variablen
   vom Typ Ressource mit dem Userspace verbunden werden.
  
Von C zum Userspace und zurück
 class proxy extends mysqlnd_plugin_connection {
  public function connect($conn, $host, ...) {
    /* vor der Implementierung ("pre"-Hook) */
    printf("Verbinden mit dem Host '%s'\n", $host);
    debug_print_backtrace();
    return parent::connect($conn);
  }
  public function query($conn, $query) {
    /* nach der Implementierung ("post"-Hook) */
    $ret = parent::query($conn, $query);
    printf("Abfrage = '%s'\n", $query);
    return $ret;
  }
}
mysqlnd_plugin_set_conn_proxy(new proxy());
PHP-Benutzer müssen die Möglichkeit haben, die übergeordnete Implementierung einer überschriebenen Methode aufzurufen.
Durch Vererbung ist es möglich, nur ausgewählte Methoden zu "verfeinern", und man kann wählen, wann der eigene Code ausgeführt werden soll, vor oder nach der übergeordneten Methode ("pre"- oder "post"-Hook).
Eingebaute Klasse: mysqlnd_plugin_connection::connect()
/*  my_mysqlnd_plugin_classes.c */
 PHP_METHOD("mysqlnd_plugin_connection", connect) {
  /* ... vereinfacht! ... */
  zval* mysqlnd_rsrc;
  MYSQLND* conn;
  char* host; int host_len;
  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs",
    &mysqlnd_rsrc, &host, &host_len) == FAILURE) {
    RETURN_NULL();
  }
  ZEND_FETCH_RESOURCE(conn, MYSQLND* conn, &mysqlnd_rsrc, -1,
    "Mysqlnd-Verbindung", le_mysqlnd_plugin_conn);
  if (PASS == org_methods.connect(conn, host, /* simplified! */ TSRMLS_CC))
    RETVAL_TRUE;
  else
    RETVAL_FALSE;
}
