第一层pdo:static PHP_METHOD(PDO, beginTransaction)
第二层pdo:beginTransaction 内部调用各 pdo driver 自定义的函数
if (dbh->methods->begin(dbh TSRMLS_CC)) {//使用函数指针,例如pg,此处调用的就是 pgsql_handle_begin
dbh->in_txn = 1;
RETURN_TRUE;
}
第三层pdo_pgsql:执行 pgsql_handle_begin
第四层libpq:PQ*()
pdo_pgsql 的内部实现:
// 初始化 pdo_pgsql
static int pdo_pgsql_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_DC) /* {{{ */
{
...
dbh->methods = &pgsql_methods;
...
}
pdo_driver_t pdo_pgsql_driver = {
PDO_DRIVER_HEADER(pgsql),
pdo_pgsql_handle_factory
}; // ?? 怎么用的?下面是此机构的定义
/* This structure is registered with PDO when a PDO driver extension is
* initialized */
typedef struct {
const char *driver_name;
unsigned long driver_name_len;
unsigned long api_version; /* needs to be compatible with PDO */
#define PDO_DRIVER_HEADER(name) \
#name, sizeof(#name)-1, \
PDO_DRIVER_API
/* create driver specific portion of the database handle and stash it into
* the dbh. dbh contains the data source string and flags for this
* instance. You MUST respect dbh->is_persistent and pass that flag to
* pemalloc() for all allocations that are stored in the dbh or your instance
* data in the db, otherwise you will crash PHP when persistent connections
* are used.
*/
int (*db_handle_factory)(pdo_dbh_t *dbh, zval *driver_options TSRMLS_DC);
} pdo_driver_t;
//下面是 pdo_pgsql 的函数指针组成的结构体
static struct pdo_dbh_methods pgsql_methods = {
pgsql_handle_closer,
pgsql_handle_preparer,
pgsql_handle_doer,
pgsql_handle_quoter,
pgsql_handle_begin,
pgsql_handle_commit,
pgsql_handle_rollback,
pdo_pgsql_set_attr,
pdo_pgsql_last_insert_id,
pdo_pgsql_fetch_error_func,
pdo_pgsql_get_attribute,
pdo_pgsql_check_liveness, /* check_liveness */
pdo_pgsql_get_driver_methods /* get_driver_methods */
};
从上面的代码中大体可以看出 pdo 的实现机制:
虚拟一个数据访问抽象层,各厂商的 pdo driver 都要先使用此抽象层,这样 PHP 就统一了各数据库接口,类似 ODBC 的实现机制。
抽象层通过实例化pdo_*sql_handle_factory(),初始化pdo_*sql API 指针结构体,然后调用。这样 pdo 接口的名称就与 pdo_pgsql 提供的函数名称无关了(这样 pdo 在名称上统一了各数据库的 pdo driver)。