©
本文档使用
php中文网手册 发布
It is important to remember that a mysqlnd plugin is itself a PHP extension.
The following code shows the basic structure of the MINIT function that will be used in the typical mysqlnd plugin:
static PHP_MINIT_FUNCTION(mysqlnd_plugin) {
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);
}
enum_func_status MYSQLND_METHOD(mysqlnd_plugin_conn, query)() {
}
enum_func_status MYSQLND_METHOD(mysqlnd_plugin_conn, connect)() {
}
Task analysis: from C to userspace
class proxy extends mysqlnd_plugin_connection {
public function connect($host, ...) { .. }
}
mysqlnd_plugin_set_conn_proxy(new proxy());
Process:
PHP: user registers plugin callback
PHP: user calls any PHP MySQL API to connect to MySQL
C: extMYSQLND_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) { ret = MY_ZEND_CALL_METHOD_WRAPPER(global_user_conn_proxy, host, ); } else { ret = org_methods.connect(conn, host, user, passwd, passwd_len, db, db_len, port, socket, mysql_flags TSRMLS_CC); } return ret; }
Calling userspace: simple arguments
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);
}
}
Calling userspace: structs as arguments
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);
}
}
The first argument of many mysqlnd methods is a C "object". For example, the first argument of the connect() method is a pointer to MYSQLND. The struct MYSQLND represents a mysqlnd connection object.
The mysqlnd connection object pointer can be compared to a standard I/O file handle. Like a standard I/O file handle a mysqlnd connection object shall be linked to the userspace using the PHP resource variable type.
From C to userspace and back
class proxy extends mysqlnd_plugin_connection {
public function connect($conn, $host, ...) {
printf("Connecting to host = '%s'\n", $host);
debug_print_backtrace();
return parent::connect($conn);
} public function query($conn, $query) {
$ret = parent::query($conn, $query);
printf("Query = '%s'\n", $query);
return $ret;
}
}
mysqlnd_plugin_set_conn_proxy(new proxy());
PHP users must be able to call the parent implementation of an overwritten method.
As a result of subclassing it is possible to refine only selected methods and you can choose to have "pre" or "post" hooks.
Buildin class: mysqlnd_plugin_connection::connect()
PHP_METHOD("mysqlnd_plugin_connection", connect) {
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 Connection", le_mysqlnd_plugin_conn);
if (PASS == org_methods.connect(conn, host, TSRMLS_CC))
RETVAL_TRUE;
else
RETVAL_FALSE;
}