用C语言扩展PHP功能

2021-03-22 10:52:10 浏览数 (1)

用C语言扩展PHP功能    PHP经过最近几年的发展已经非常的流行,而且PHP也提供了各种各样非常丰富的函数。 但有时候我们还是需要来扩展PHP。比如:我们自己开发了一个数据库系统,而且有自己的 库函数来操作数据库,这时候,如果想在PHP中来操作我们自己的数据库的话,就必须自己 扩展PHP了,像mysql,postgresql,之所以PHP能够提供这些数据库操作函数,也都是扩展了 PHP的结果。     先看看PHP的源代码结构:     $ cd php-4.4.2/ext     $ ls     会显示出目前该PHP发行版本中所有的扩展模块。     如果想深入学习的话,可以去看看mysql或者postgresql的PHP扩展实现。     下面,我们通过一个简单的模块(mypg)来实现对postgresql的数据库操作。     $ cd php-4.4.2/ext     $ ./ext_skel –extname=mypg     该程序会自动生成mypg目录     $ cd mypg     $ ls     config.m4  CREDITS  EXPERIMENTAL  mypg.c  mypg.php  php_mypg.h  tests     PHP已经自动为我们生成了一些必要的文件和示范代码。     我们需要作一些修改才能正常的编译和使用该mypg模块。     $ vi config.m4     修改成如下内容:

代码语言:javascript复制

 PHP_ARG_ENABLE(mypg, whether to enable mypg support,
                [  –enable-mypg           Enable mypg support])
if test “$PHP_MYPG” != “no”; then
   dnl Write more examples of tests here…
SEARCH_PATH ; do   dnl     if test -r i/SEARCH_FOR; then   dnl       MYPG_DIR=
  dnl # –with-mypg -> add include path
   dnl PHP_ADD_INCLUDE($MYPG_DIR/include)
  dnl # –with-mypg -> check for lib and symbol presence
   dnl LIBNAME=mypg # you may want to change this
   dnl LIBSYMBOL=mypg # you most likely want to change this
  dnl PHP_CHECK_LIBRARY(LIBNAME,LIBSYMBOL,   dnl [   dnl   PHP_ADD_LIBRARY_WITH_PATH(LIBNAME, MYPG_DIR/lib, MYPG_SHARED_LIBADD)   dnl   AC_DEFINE(HAVE_MYPGLIB,1,[ ])   dnl ],[   dnl   AC_MSG_ERROR([wrong mypg lib version or lib not found])   dnl ],[   dnl   -L
  PHP_NEW_EXTENSION(mypg, mypg.c, $ext_shared)
 fi

dnl开头的为注释,其实我们也只是把某些注释去掉了。

代码语言:javascript复制
   然后修改php_mypg.h,内容为:
 #ifndef PHP_MYPG_H
 #define PHP_MYPG_H
extern zend_module_entry mypg_module_entry;
 #define phpext_mypg_ptr &mypg_module_entry
#ifdef PHP_WIN32
 #define PHP_MYPG_API __declspec(dllexport)
 #else
 #define PHP_MYPG_API
 #endif
//模块初始化时调用函数
 PHP_MINIT_FUNCTION(mypg);
//我们的数据库连接函数
 PHP_FUNCTION(mypg_connect);
 //我们的数据库操作函数
 PHP_FUNCTION(mypg_execute);
 //我们的数据库关闭函数
 PHP_FUNCTION(mypg_close);
#ifdef ZTS
 #include “TSRM.h”
 #endif
#endif  /* PHP_MYPG_H */   
继续修改mypg.c,内容改为:
 #ifdef HAVE_CONFIG_H
 #include “config.h”
 #endif
#include “php.h”
 #include “php_ini.h”
 #include “ext/standard/info.h”
 #include “php_mypg.h”
 #include “libpq-fe.h”
int le_link;
 function_entry mypg_functions[] = {
         PHP_FE(mypg_connect,                                                    NULL)
         PHP_FE(mypg_execute,                                                    NULL)
         PHP_FE(mypg_close,                                                      NULL)
         {NULL, NULL, NULL}
 };
 zend_module_entry mypg_module_entry = {
         STANDARD_MODULE_HEADER,
         “mypg”, mypg_functions, PHP_MINIT(mypg), NULL, NULL, NULL,
         NULL, NO_VERSION_YET, STANDARD_MODULE_PROPERTIES
 };
ZEND_GET_MODULE(mypg)
//数据库链接关闭函数
 static void _close_mypg_link(zend_rsrc_list_entry *rsrc TSRMLS_DC)
 {
         PGconn *link = (PGconn *)rsrc->ptr;
         PQfinish(link);
 }
 PHP_MINIT_FUNCTION(mypg)
 {
     //注册资源回收函数,如果没有显示用mypg_close关闭数据库连接的化,PHP会自动调用该函数释放资源
     le_link = zend_register_list_destructors_ex(_close_mypg_link, NULL, “mypg link”, module_number);
     return SUCCESS;
}
//连接数据库
 static void php_mypg_do_connect(INTERNAL_FUNCTION_PARAMETERS)
 {
         PGconn *link;
        //只接受一个函数参数
         if(ZEND_NUM_ARGS() != 1)
         {
             WRONG_PARAM_COUNT;
         }
        zval **connect_info;
        /* get the connection information string */
         if (zend_get_parameters_ex(1, &connect_info) == FAILURE) {
             RETURN_FALSE;
         }
        /* create our resource hash key */
         convert_to_string_ex(connect_info);
        //调用libpq, 执行数据库连接
         if ((link=PQconnectdb(Z_STRVAL_PP(connect_info))) && PQstatus(link)!=CONNECTION_OK) {
             RETURN_FALSE;
         }
 
         //将return_value注册为得到的数据库连接
         /* add it to the list */
         ZEND_REGISTER_RESOURCE(return_value, link, le_link);
 }
 PHP_FUNCTION(mypg_connect)
 {
     php_mypg_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU);
 }
//我们自己定义的数据库操作函数
 PHP_FUNCTION(mypg_execute)
 {
         zval **query, **link = NULL;
         int id;
         PGconn *conn;
         PGresult *res;
        //参数为2, 1:执行的sql  2:数据库链接句柄
         switch(ZEND_NUM_ARGS()) {
                 case 2:
                         if (zend_get_parameters_ex(2, &query, &link)==FAILURE) {
                                 WRONG_PARAM_COUNT;
                         }
                         break;
                 default:
                         WRONG_PARAM_COUNT;
                         break;
         }
 
         //取得数据库链接
         ZEND_FETCH_RESOURCE(conn, PGconn *, link, -1, “mypg link”,  le_link);
        convert_to_string_ex(query);
 
         //通过libpq执行SQL
         res = PQexec(conn, Z_STRVAL_PP(query));
        if (PQresultStatus(res) != PGRES_COMMAND_OK)
         {
                 RETURN_FALSE;
         }
        PQclear(res);
 
         RETURN_TRUE;
}
 PHP_FUNCTION(mypg_close)
 {
         zval **link;
         int id;
         PGconn *conn;
        switch (ZEND_NUM_ARGS()) {
                 case 1:
                         if (zend_get_parameters_ex(1, &link)==FAILURE) {
                                 RETURN_FALSE;
                         }
                         break;
                 default:
                         WRONG_PARAM_COUNT;
                         break;
         }
         if(link == NULL)
         {
                 RETURN_FALSE;
         }
        //根据资源句柄取得资源
         ZEND_FETCH_RESOURCE(conn, PGconn *, link, -1,”mypg link”,  le_link);
 
         //删除该资源,PHP自动调用前面注册的函数来关闭数据库链接
         zend_list_delete(Z_RESVAL_PP(link));
        RETURN_TRUE;
}
     mypg模块就基本开发完成了,我们需要重新为php生成configure文件。
 
     $ cd php-4.4.2
     $ rm -rf autom4te.cache/; rm -f configure
     $ ./buildconf  –force
     此时PHP会读取所有ext/子目录下的config.m4,并集成到新生成的configure脚本中。
     如果没有意外,运行如下命令会得到如下结果:
     $ ./configure –help | grep mypg
       –enable-mypg           Enable mypg support
     编译PHP:
     $ ./configure —enable-mypg
     由于要链接libpq.so,可以vi Makefile
     在EXTRA_LIBS后面加上:-lpq 来把libpq编译进去,当然也可以通过修改mypg的config.m4来实现,
     这里不在啰嗦。
     $ make
     $ make install
 
     编写我们的模块测试脚本:testmypg.php
 /*
 * this is the sample php code
 * to invoke our module: mypg
 */
 $link = mypg_connect(”hostaddr=172.16.19.8 dbname=pgsql user=pgsql password=12345″);
 if($link)
 {
         echo “Successfully connected  to PostgreSQL.n”;
 }
 else
 {
         die(”Connect error.n”);
 }
$sql = “insert into test values(’12345′,’23145′)”;
mypg_execute(sql, link);
link2 = link;
mypg_execute(sql, link2); mypg_execute(sql, link); mypg_close(
echo “Database query ok.n”;
?>
 运行该PHP程序,如果在postgresql的pgsql库中有table: test (col1 varchar(100), col2 varchar(100))
 里面应该已经有2条记录了。

    编写php模块扩展需要很多PHP源码的知识,可以通过参考其他module或者直接阅读PHP代码来逐步提高自己 的开发能力。     php官方的站点上也有一些文章可供参考:http://cn2.php.net/manual/en/internals2.php

http://cn2.php.net/manual/zh/internals2.structure.php     希望这篇文章能够给想扩展PHP的兄弟一个大概的方向!

本文由来源 21aspnet,由 javajgs_com 整理编辑,其版权均为 21aspnet 所有,文章内容系作者个人观点,不代表 Java架构师必看 对观点赞同或支持。如需转载,请注明文章来源。

0 人点赞