PHP C++ 扩展教程

提要

因为网络上没有一篇完整的详细的php c++扩展教程。自己曾经写过php c++扩展,但是时间一久就忘了,然后上网找教程一点点地记忆起来,有点浪费时间浪费生命的感觉,所以现在就写下这一遍文章,详细地记录下来(纯手写)。

环境的准备

本教程的环境是centos6.5、centos7,先安装依赖:

#添加组
groupadd www
#添加php-fpm用户
useradd -c php-fpm-user -g www -M php-fpm
# c和c++编译器
yum install -y gcc gcc-c++
# PHP扩展依赖
yum install -y libxml2-devel openssl-devel libcurl-devel libjpeg-devel libpng-devel libicu-devel openldap-devel

然后下载php的源码,并解压

wget  php-5.6.23.tar.gz
tar -xzvf php-5.6.23.tar.gz

先编译安装PHP

./configure --prefix=/usr/local/php\
 --with-config-file-path=/usr/local/php/etc\
 --with-libdir=lib64\
 --enable-fpm\
 --with-fpm-user=php-fpm\
 --with-fpm-group=www\
 --enable-mysqlnd\
 --with-mysql=mysqlnd\
 --with-mysqli=mysqlnd\
 --with-pdo-mysql=mysqlnd\
 --enable-opcache\
 --enable-pcntl\
 --enable-mbstring\
 --enable-soap\
 --enable-zip\
 --enable-calendar\
 --enable-bcmath\
 --enable-exif\
 --enable-ftp\
 --enable-intl\
 --with-openssl\
 --with-zlib\
 --with-curl\
 --with-gd\
 --with-zlib-dir=/usr/lib\
 --with-png-dir=/usr/lib\
 --with-jpeg-dir=/usr/lib\
 --with-gettext\
 --with-mhash\
 --with-ldap

 make 
 make install

回到上级目录

cd ../

创建 helloworld.proto 文件,该文件包含了要实现的函数列表,内容如下

string helloworld(string arg1, int arg2)

生成骨架

cd php-5.6.23/ext/
./ext_skel --extname=helloworld --proto=../../helloworld.proto

修改config.m4

cd helloworld/
vim config.m4

config.m4 修改前是这样子的:

dnl $Id$
dnl config.m4 for extension helloworld

dnl Comments in this file start with the string 'dnl'.
dnl Remove where necessary. This file will not work
dnl without editing.

dnl If your extension references something external, use with:

dnl PHP_ARG_WITH(helloworld, for helloworld support,
dnl Make sure that the comment is aligned:
dnl [  --with-helloworld             Include helloworld support])

dnl Otherwise use enable:

dnl PHP_ARG_ENABLE(helloworld, whether to enable helloworld support,
dnl Make sure that the comment is aligned:
dnl [  --enable-helloworld           Enable helloworld support])

if test "$PHP_HELLOWORLD" != "no"; then
  dnl Write more examples of tests here...

  dnl # --with-helloworld -> check with-path
  dnl SEARCH_PATH="/usr/local /usr"     # you might want to change this
  dnl SEARCH_FOR="/include/helloworld.h"  # you most likely want to change this
  dnl if test -r $PHP_HELLOWORLD/$SEARCH_FOR; then # path given as parameter
  dnl   HELLOWORLD_DIR=$PHP_HELLOWORLD
  dnl else # search default path list
  dnl   AC_MSG_CHECKING([for helloworld files in default path])
  dnl   for i in $SEARCH_PATH ; do
  dnl     if test -r $i/$SEARCH_FOR; then
  dnl       HELLOWORLD_DIR=$i
  dnl       AC_MSG_RESULT(found in $i)
  dnl     fi
  dnl   done
  dnl fi
  dnl
  dnl if test -z "$HELLOWORLD_DIR"; then
  dnl   AC_MSG_RESULT([not found])
  dnl   AC_MSG_ERROR([Please reinstall the helloworld distribution])
  dnl fi

  dnl # --with-helloworld -> add include path
  dnl PHP_ADD_INCLUDE($HELLOWORLD_DIR/include)

  dnl # --with-helloworld -> check for lib and symbol presence
  dnl LIBNAME=helloworld # you may want to change this
  dnl LIBSYMBOL=helloworld # you most likely want to change this 

  dnl PHP_CHECK_LIBRARY($LIBNAME,$LIBSYMBOL,
  dnl [
  dnl   PHP_ADD_LIBRARY_WITH_PATH($LIBNAME, $HELLOWORLD_DIR/$PHP_LIBDIR, HELLOWORLD_SHARED_LIBADD)
  dnl   AC_DEFINE(HAVE_HELLOWORLDLIB,1,[ ])
  dnl ],[
  dnl   AC_MSG_ERROR([wrong helloworld lib version or lib not found])
  dnl ],[
  dnl   -L$HELLOWORLD_DIR/$PHP_LIBDIR -lm
  dnl ])
  dnl
  dnl PHP_SUBST(HELLOWORLD_SHARED_LIBADD)

  PHP_NEW_EXTENSION(helloworld, helloworld.c, $ext_shared)
fi

config.m4 修改后(修改前后对比一下就知道我改了哪里,怎样对比?用 Beyond compare这个软件, 或命令行工具 diff)

dnl $Id$
dnl config.m4 for extension helloworld

dnl Comments in this file start with the string 'dnl'.
dnl Remove where necessary. This file will not work
dnl without editing.

dnl If your extension references something external, use with:

dnl PHP_ARG_WITH(helloworld, for helloworld support,
dnl Make sure that the comment is aligned:
dnl [  --with-helloworld             Include helloworld support])

dnl Otherwise use enable:

PHP_ARG_ENABLE(helloworld, whether to enable helloworld support,
Make sure that the comment is aligned:
[  --enable-helloworld           Enable helloworld support])

if test "$PHP_HELLOWORLD" != "no"; then
  dnl Write more examples of tests here...

  dnl # --with-helloworld -> check with-path
  dnl SEARCH_PATH="/usr/local /usr"     # you might want to change this
  dnl SEARCH_FOR="/include/helloworld.h"  # you most likely want to change this
  dnl if test -r $PHP_HELLOWORLD/$SEARCH_FOR; then # path given as parameter
  dnl   HELLOWORLD_DIR=$PHP_HELLOWORLD
  dnl else # search default path list
  dnl   AC_MSG_CHECKING([for helloworld files in default path])
  dnl   for i in $SEARCH_PATH ; do
  dnl     if test -r $i/$SEARCH_FOR; then
  dnl       HELLOWORLD_DIR=$i
  dnl       AC_MSG_RESULT(found in $i)
  dnl     fi
  dnl   done
  dnl fi
  dnl
  dnl if test -z "$HELLOWORLD_DIR"; then
  dnl   AC_MSG_RESULT([not found])
  dnl   AC_MSG_ERROR([Please reinstall the helloworld distribution])
  dnl fi

  dnl # --with-helloworld -> add include path
  dnl PHP_ADD_INCLUDE($HELLOWORLD_DIR/include)

  dnl # --with-helloworld -> check for lib and symbol presence
  dnl LIBNAME=helloworld # you may want to change this
  dnl LIBSYMBOL=helloworld # you most likely want to change this 

  dnl PHP_CHECK_LIBRARY($LIBNAME,$LIBSYMBOL,
  dnl [
  dnl   PHP_ADD_LIBRARY_WITH_PATH($LIBNAME, $HELLOWORLD_DIR/$PHP_LIBDIR, HELLOWORLD_SHARED_LIBADD)
  dnl   AC_DEFINE(HAVE_HELLOWORLDLIB,1,[ ])
  dnl ],[
  dnl   AC_MSG_ERROR([wrong helloworld lib version or lib not found])
  dnl ],[
  dnl   -L$HELLOWORLD_DIR/$PHP_LIBDIR -lm
  dnl ])
  dnl
  dnl PHP_SUBST(HELLOWORLD_SHARED_LIBADD)
  PHP_REQUIRE_CXX()    dnl 通知Make使用g++
  PHP_ADD_LIBRARY(stdc++, 1, EXTRA_LDFLAGS)    dnl 加入C++标准库
  PHP_NEW_EXTENSION(helloworld, helloworld.cc, $ext_shared)
fi

helloworld.c 文件改名为 helloworld.cc

mv helloworld.c helloworld.cc

修改 helloworld.cc, (只需修改一下内容,其他内容不用修改)修改前的内容是:

PHP_FUNCTION(helloworld)
{
        char *arg1 = NULL;
        int argc = ZEND_NUM_ARGS();
        int arg1_len;
        long arg2;

        if (zend_parse_parameters(argc TSRMLS_CC, "sl", &arg1, &arg1_len, &arg2) == FAILURE)
                return;

        php_error(E_WARNING, "helloworld: not yet implemented");
}

然后修改,简单地修改,完全就是用c/c++了

PHP_FUNCTION(helloworld)
{
        char *arg1 = NULL;
        int argc = ZEND_NUM_ARGS();
        int arg1_len;
        long arg2;

        if (zend_parse_parameters(argc TSRMLS_CC, "sl", &arg1, &arg1_len, &arg2) == FAILURE)
                return;

       //实现在这里开始写
       std::string str = "Hello world!";
       str += arg1 ;
       // 参数2我就不用了
       RETURN_STRINGL(str.c_str(), str.length(), 1);   // 返回值是怎么样子的?zend有规定,后面说
        
       //php_error(E_WARNING, "helloworld: not yet implemented");
}

表3.14 从函数直接返回值的宏(zend规定的返回这样子的)

说明
RETURN_RESOURCE(resource) 返回一个资源。
RETURN_BOOL(bool) 返回一个布尔值。
RETURN_NULL() 返回一个空值。
RETURN_LONG(long) 返回一个长整数。
RETURN_DOUBLE(double) 返回一个双精度浮点数。
RETURN_STRING(string, duplicate) 返回一个字符串。duplicate 表示这个字符是否使用 estrdup() 进行复制。
RETURN_STRINGL(string, length, duplicate) 返回一个定长的字符串。其余跟 RETURN_STRING 相同。这个宏速度更快而且是二进制安全的。
RETURN_EMPTY_STRING() 返回一个空字符串。
RETURN_FALSE 返回一个布尔值假。
RETURN_TRUE 返回一个布尔值真。

表3.15 设置函数返回值的宏

说明
RETVAL_RESOURCE(resource) 设定返回值为指定的一个资源。
RETVAL_BOOL(bool) 设定返回值为指定的一个布尔值。
RETVAL_NULL 设定返回值为空值
RETVAL_LONG(long) 设定返回值为指定的一个长整数。
RETVAL_DOUBLE(double) 设定返回值为指定的一个双精度浮点数。
RETVAL_STRING(string, duplicate) 设定返回值为指定的一个字符串,duplicate 含义同 RETURN_STRING。
RETVAL_STRINGL(string, length, duplicate) 设定返回值为指定的一个定长的字符串。其余跟 RETVAL_STRING 相同。这个宏速度更快而且是二进制安全的。
RETVAL_EMPTY_STRING 设定返回值为空字符串。
RETVAL_FALSE 设定返回值为布尔值假。
RETVAL_TRUE 设定返回值为布尔值真。

如果是想直接编到php里面

如果是想以动态扩展库的方式。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

  • PHP 学习目录 ├─PHP视频教程 1 LAMP网站构建 │ ├─PHP教程 1.1.1 新版视频形式介绍│ ...
    曹渊说创业阅读 16,147评论 29 417
  • 为什么要用到php扩展?因为php扩展使用C语言编写,而C语言是静待编译的,所以执行效率要高于php很多,这里我来...
    人在码途阅读 1,454评论 2 1
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,401评论 25 707
  • 我是乔安,是一个特别矫情,特别小资的魔都女子。 我经常说我的人生乐趣是咖啡和马卡龙,高跟鞋和手链。这四样东西仿佛占...
    Joanne暖暖阅读 369评论 0 0