c++ 写 php 扩展

来源:互联网 发布:网络教育学位证好拿吗 编辑:程序博客网 时间:2024/06/05 22:50

http://blog.sina.com.cn/s/blog_532f78a40100qqnr.html

此篇文章准备分2个部分来讲述:
   第一部分主要详细讲述一下怎么构建一个完成的C++应用扩展模块;
   第二部分主要讲述在PHP及Zend框架下怎么使用Zend API和C++语言来实现自己所要的功能以及项目的开发;
    此篇文章所运用的环境在Linux2.4.21-4.ELsmp(Red Hat Linux 3.2.3-20),Apache/2.2.8,gcc version3.2.3 20030502,PHP 5.2.5 (cli),Zend Engine v2.2.0下进行。

 

一、前言

以前写过一些使用C语言来扩展PHP的应用[1]。在淘宝使用C++做PHP的扩展做项目的过程中,遇到了一些问题,从Google中查找,使用C++来开发PHP的中文文章少之又少,而且没有一个手册来告诉用户怎么写m4[2]文件,怎么使用zend[3]引擎的一套api函数去写相关PHP的接口,这里就怎么用C++语言来开发PHP的一些心得介绍给大家,希望有心人能够有所收获;
二、为什么要用C++开发PHP

使用C++比用C语言开发PHP主要有2个好处:
使用C++能够很方便的操作string类型,本身的一些容器和模板[4]、以及面对对象的功能让开发者能够节省大量开发的时间,这是比较重要的一点;
C++可以直接使用C的库,只需要extern "C"{}将其C的头文件和库定义包含起来就可以,不需要太多的移植工作,可以重复利用前人的代码或者库进行后续的工作;
用C++开发PHP是快速、迅捷的,熟悉了相关的定义以及语法,相信开发PHP不是难事。

三、书写config文件

config.m4[5]或config.w32[6]文件是编译基础中最核心的文件,这个文件主要是用autoconf[7]来产生configure[8]配置文件,继而自动生成大家所熟悉的Makefile文件,以Linux系统为例:

你可以自己书写config.m4文件,也可以由Shell脚本 ext_skel[9] 来生成样板:

  [cnangel@localhost ~]$wgethttp://docs.php.net/get/php-5.2.5.tar.bz2/from/cn.php.net/mirror
  [cnangel@localhost ~]$tar -jxfphp-5.2.5.tar.bz2
  [cnangel@localhost ~]$cdphp-5.2.6/ext
  [cnangel@localhost ext]./ext_skel--extname=extern_name
接着你会发现在ext目录下多了一个叫extern_name的目录。进入该目录,会发现目录下有几个文件:

  [cnangel@localhost ext_name]$ls -l
  总计 32
  -rw-r--r-- 1 cnangel cnangel 2103 06-2919:00 config.m4
  -rw-r--r-- 1 cnangel cnangel 310 06-29 19:00 config.w32
  -rw-r--r-- 1 cnangel cnangel   8 06-29 19:00 CREDITS
  -rw-r--r-- 1 cnangel cnangel   0 06-29 19:00EXPERIMENTAL
  -rw-r--r-- 1 cnangel cnangel 5305 06-2919:00 ext_name.c
  -rw-r--r-- 1 cnangel cnangel 508 06-29 19:00 ext_name.php
  -rw-r--r-- 1 cnangel cnangel 2766 06-2919:00 php_ext_name.h
  drwxr-xr-x 2 cnangel cnangel 4096 06-2919:00 tests
然后可以根据提示来修改config.m4文件,这里有几个重要的宏命令如下:

dnl 是注释;
PHP_ARG_WITH 或者 PHP_ARG_ENABLE指定了PHP扩展模块的工作方式,前者意味着不需要第三方库,后者正好相反;
PHP_REQUIRE_CXX 用于指定这个扩展用到了C++;
PHP_ADD_INCLUDE 指定PHP扩展模块用到的头文件目录;
PHP_CHECK_LIBRARY指定PHP扩展模块PHP_ADD_LIBRARY_WITH_PATH定义以及库连接错误信息等;
PHP_ADD_LIBRARY(stdc++,"",EXTERN_NAME_LIBADD)用于将标准C++库链接进入扩展
PHP_SUBST(EXTERN_NAME_SHARED_LIBADD)用于说明这个扩展编译成动态链接库的形式;
PHP_NEW_EXTENSION 用于指定有哪些源文件应该被编译,文件和文件之间用空格隔开;
ext_skel默认生成的模块框架是针对C的,我们要使用C++进行PHP扩展, 那除以上的PHP_REQUIRE_CXX,PHP_ADD_LIBRARY两个宏必需外,还要把extern_name.c改名成extern_name.cpp。

需要注意的是,在config.m4里面可以使用类似的Makefile语法,片段如下:

  PHP_REQUIRE_CXX()
  INCLUDES="$INCLUDES `mysql_config--cflags`"
  PHP_ADD_LIBRARY(stdc++, "",EXTRA_LDFLAGS)
  EXTRA_LDFLAGS="$EXTRA_LDFLAGS `mysql_config--libs` -lmemcached"
  AC_CHECK_HEADERS([mysql/mysql.h])
  CPPFILE="ext_name.cpp antiForbitWord.cppantiBaseDict.cpp Trie.cpp Logger.cpp antiEncodeConverter.cppstrnormalize.cpp"
  PHP_NEW_EXTENSION(ext_name, $CPPFILE,$ext_shared)
四、书写.h文件

这里指修改php_ext_name.h这个头文件。

由于TSRM.h这个文件所包含的函数和类都是用纯C语言写的,故应该使用extern来说明如下:

  extern "C" {
  #ifdef ZTS
  #include "TSRM.h"
  #endif
  }
如果该php_ext_name.h头文件或者ext_name.cpp文件用到了C++语言中的一些容器或者一些函数,则需要在头文件中包含相应的c++库的头文件,否则会出现找不到相应的C++函数错误。

五、书写.cpp文件

这里指修改ext_name.cpp这个cpp文件。

由于config.h、php.h、php_ini.h和ext/standard/info.h中包含的函数和类如TSRM.h一样,都是用纯C语言写的,所以也需要用extern说明如下:

  extern "C" {
  #ifdef HAVE_CONFIG_H
  #include "config.h"
  #endif
  #include "php.h"
  #include "php_ini.h"
  #include "ext/standard/info.h"
  }
而 #include "php_ext_name.h" 这句则已经不需要包含在extern"C"内,另外,ZEND_GET_MODULE这个宏命令也是需要特别申明如下:

  #ifdef COMPILE_DL_EXT_NAME
  BEGIN_EXTERN_C()
  ZEND_GET_MODULE(ext_name)
  END_EXTERN_C()
  #endif
总之,把一些C写的库或轰用兼容的方式给解决。

六、初步执行

这里需要用到一个命令:phpize[10],命令如下:

  [cnangel@localhost ext_name]$phpize
  [cnangel@localhostext_name]$./configure 
  [cnangel@localhost ext_name]$make
注意:可以使用用phpize生成configure执行文件后,可以使用./configure--help查看帮助信息,修改config.m4文件可以修改configure的帮助信息。每次修改了config.m4文件,需要使用清除临时文件命令phpize --clean来完成消除configure。

七、初步应用

怎么应用到php上,把刚才的扩展模块当作一个普通的php函数调用呢?简单的应用直接使用命令:

  [cnangel@localhost ext_name]$sudo makeinstall
如果有多个php版本,则寻找扩展库目录显得没有那么好找了,比如,你的php执行文件的路径在/usr/local/php/bin/目录下,想知道php扩展模块所在的目录的话,那么执行(PHP5.0以上):

  [cnangel@localhostext_name]$/usr/local/php/bin/php-config | grep extension-dir | sed's/.*\[\(.*\)]/\1/'`
PHP5.0以下执行:

  [cnangel@localhostext_name]$/usr/local/php/bin/php-config --extension-dir
这样你可以发现你的扩展库的路径:

 /usr/local/php/lib/php/extensions/no-debug-non-zts-20060613
当然,你可以修改php.ini,找到php安装的配置文件,修改extension_dir的值为你想要的一个路径另外,需要将你的扩展写入php.ini,像这样: 

  extension=ext_name.so

最后,找到扩展库的路径后,将modules下面的extern_name.so文件复制到扩展库的目录下,重新启动一下Apache进程:

  [cnangel@localhost ext_name]$whichhttpd
  /usr/bin/httpd
  [cnangel@localhost ext_name]$sudo/usr/bin/httpd -k stop
  [cnangel@localhost ext_name]$sudo/usr/bin/httpd -k start
把这个样例ext_name.php复制到web路径上去,看看是否好使啦?下一节我们将详细讲一些ZendAPI的宏在ext_name.cpp中的一些复杂应用。

0 0
原创粉丝点击