PHP的C/C++扩展(二)

书接上文,如果要是想编译C++而不是纯C语言的代码,还需要做一些必要的修改。

一、我们用上文中的步骤,运行命令./ext_skel--extname=edutest3,创建edutest3。

 zhangxuefeng@zhangxuefengs-MacBook-Pro  ~/Developer/php-5.6.24/ext/edutest3  ll
total 56
-rw-r--r--  1 zhangxuefeng  staff     9B Aug  1 11:23 CREDITS
-rw-r--r--  1 zhangxuefeng  staff     0B Aug  1 11:23 EXPERIMENTAL
-rw-r--r--  1 zhangxuefeng  staff   2.1K Aug  1 11:23 config.m4
-rw-r--r--  1 zhangxuefeng  staff   310B Aug  1 11:23 config.w32
-rw-r--r--  1 zhangxuefeng  staff   5.0K Aug  1 11:23 edutest3.c
-rw-r--r--  1 zhangxuefeng  staff   508B Aug  1 11:23 edutest3.php
-rw-r--r--  1 zhangxuefeng  staff   2.6K Aug  1 11:23 php_edutest3.h
drwxr-xr-x  3 zhangxuefeng  staff   102B Aug  1 11:23 tests
  1. 先将edutest3.c重命名为edutest3.cc,让编译可以编译C++。
  2. 修改config.m4,除了上文中说到的内容,还需要修改修改文件名,这里我们在添加一个想要一起编译的代码文件:
 59   PHP_REQUIRE_CXX()
 60   PHP_SUBST(EDUTEST3_SHARED_LIBADD)
 61   PHP_ADD_LIBRARY(stdc++, 1, EDUTEST3_SHARED_LIBADD)
 62   PHP_NEW_EXTENSION(edutest3, edutest3.cc wenku.cc, $ext_shared)

简要说明:
59行,要求系统使用C++编译器。
61行,引入C++标准库libstdc++
62行,重命名成.cc文件,并添加一个wenku.cc

  1. php_edutest3.h,添加一些信息和头文件:
 27 #define PHP_EDUTEST3_EXTNAME "edutest3"
 28 #define PHP_EDUTEST3_VERSION "0.1.0" /* Replace with version number for your extension */
 29
 30 #ifdef HAVE_CONFIG_H
 31 #include "config.h"
 32 #endif
 33
 34 extern "C" {
 35 #include "php.h"
 36 }

二、创建wenku类(完全从国外的代码里抄来的例子,以后再修改成自己的),我们将实现和头文件分开放置:

  1. 实现wenku.cc:
  1 #include "wenku.h"
  2
  3 Wenku::Wenku(int maxGear) {
  4     this->maxGear = maxGear;
  5     this->currentGear = 1;
  6     this->speed = 0;
  7 }
  8
  9 void Wenku::shift(int gear) {
 10     if (gear < 1 || gear > maxGear) {
 11         return;
 12     }
 13     currentGear = gear;
 14 }
 15
 16 void Wenku::accelerate() {
 17     speed += (5 * this->getCurrentGear());
 18 }
 19
 20 void Wenku::brake() {
 21     speed -= (5 * this->getCurrentGear());
 22 }
 23
 24 int Wenku::getCurrentSpeed() {
 25     return speed;
 26 }
 27
 28 int Wenku::getCurrentGear() {
 29     return currentGear;
 30 }
  1. 头文件wenku.h
  1 #ifndef EDUTEST3_WENKU_H
  2 #define EDUTEST3_WENKU_H
  3
  4 // A very simple wenku class
  5 class Wenku {
  6 public:
  7     Wenku(int maxGear);
  8     void shift(int gear);
  9     void accelerate();
 10     void brake();
 11     int getCurrentSpeed();
 12     int getCurrentGear();
 13 private:
 14     int maxGear;
 15     int currentGear;
 16     int speed;
 17 };
 18
 19 #endif /* EDUTEST3_WENKU_H */

三、修改主文件edutest3.cc,将上面类中的函数声明进来、头文件引入,使PHP运行时会初始化:

 21 #ifdef HAVE_CONFIG_H
 22 #include "config.h"
 23 #endif
 24
 25 #include "php.h"
 26 #include "php_ini.h"
 27 #include "ext/standard/info.h"
 28 #include "php_edutest3.h"
 29 #include "wenku.h"
……
 38 zend_object_handlers wenku_object_handlers;
 39
 40 struct wenku_object {
 41     zend_object std;
 42     Wenku *wenku;
 43 };
 44
 45 zend_class_entry *wenku_ce;
 46
 47 void wenku_free_storage(void *object TSRMLS_DC)
 48 {
 49     wenku_object *obj = (wenku_object *)object;
 50     delete obj->wenku;
 51
 52     zend_hash_destroy(obj->std.properties);
 53     FREE_HASHTABLE(obj->std.properties);
 54
 55     efree(obj);
 56 }
 57
 58 zend_object_value wenku_create_handler(zend_class_entry *type TSRMLS_DC)
 59 {
 60     zval *tmp;
 61     zend_object_value retval;
 62
 63     wenku_object *obj = (wenku_object *)emalloc(sizeof(wenku_object));
 64     memset(obj, 0, sizeof(wenku_object));
 65     obj->std.ce = type;
 66
 67     ALLOC_HASHTABLE(obj->std.properties);
 68     zend_hash_init(obj->std.properties, 0, NULL, ZVAL_PTR_DTOR, 0);
 69     //zend_hash_copy(obj->std.properties, &type->default_properties, (copy_ctor_func_t)zval_add_ref, (void *)&tmp, sizeof(zval *));
 70     object_properties_init(&obj->std, type);
 71
 72     retval.handle = zend_objects_store_put(obj, NULL, wenku_free_storage, NULL TSRMLS_CC);
 73     retval.handlers = &wenku_object_handlers;
 74
 75     return retval;
 76 }
 77
 78
 79 PHP_METHOD(Wenku, __construct)
 80 {
 81     long maxGear;
 82     Wenku *wenku = NULL;
 83     zval *object = getThis();
 84
 85     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &maxGear) == FAILURE) {
 86         RETURN_NULL();
 87     }
 88
 89     wenku = new Wenku(maxGear);
 90     wenku_object *obj = (wenku_object *)zend_object_store_get_object(object TSRMLS_CC);
 91     obj->wenku = wenku;
 92 }
 93 PHP_METHOD(Wenku, p_shift)
 94 {
 95     long gear;
 96
 97     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &gear) == FAILURE) {
 98         RETURN_NULL();
 99     }
100
101     Wenku *wenku;
102     wenku_object *obj = (wenku_object *)zend_object_store_get_object(getThis() TSRMLS_CC);
103     wenku = obj->wenku;
104     if (wenku != NULL) {
105         wenku->shift(gear);
106     }
107 }
108 PHP_METHOD(Wenku, p_accelerate)
109 {
110     Wenku *wenku;
111     wenku_object *obj = (wenku_object *)zend_object_store_get_object(getThis() TSRMLS_CC);
112     wenku = obj->wenku;
113     if (wenku != NULL) {
114         wenku->accelerate();
115     }
116 }
117 PHP_METHOD(Wenku, p_brake)
118 {
119     Wenku *wenku;
120     wenku_object *obj = (wenku_object *)zend_object_store_get_object(getThis() TSRMLS_CC);
121     wenku = obj->wenku;
122     if (wenku != NULL) {
123         wenku->brake();
124     }
125 }
126 PHP_METHOD(Wenku, p_getCurrentSpeed)
127 {
128     Wenku *wenku;
129     wenku_object *obj = (wenku_object *)zend_object_store_get_object(getThis() TSRMLS_CC);
130     wenku = obj->wenku;
131     if (wenku != NULL) {
132         RETURN_LONG(wenku->getCurrentSpeed());
133     }
134     RETURN_NULL();
135 }
136 PHP_METHOD(Wenku, p_getCurrentGear)
137 {
138     Wenku *wenku;
139     wenku_object *obj = (wenku_object *)zend_object_store_get_object(getThis() TSRMLS_CC);
140     wenku = obj->wenku;
141     if (wenku != NULL) {
142         RETURN_LONG(wenku->getCurrentGear());
143     }
144     RETURN_NULL();
145 }
146
147 zend_function_entry wenku_methods[] = {
148     PHP_ME(Wenku,  __construct,     NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
149     PHP_ME(Wenku,  p_shift,           NULL, ZEND_ACC_PUBLIC)
150     PHP_ME(Wenku,  p_accelerate,      NULL, ZEND_ACC_PUBLIC)
151     PHP_ME(Wenku,  p_brake,           NULL, ZEND_ACC_PUBLIC)
152     PHP_ME(Wenku,  p_getCurrentSpeed, NULL, ZEND_ACC_PUBLIC)
153     PHP_ME(Wenku,  p_getCurrentGear,  NULL, ZEND_ACC_PUBLIC)
154     {NULL, NULL, NULL}
155 };
156

四、在模块初始化方法中注册wenku类:

206 /* {{{ PHP_MINIT_FUNCTION
207  */
208 PHP_MINIT_FUNCTION(edutest4)
209 {
210         /* If you have INI entries, uncomment these lines
211         REGISTER_INI_ENTRIES();
212         */
213         zend_class_entry ce;
214         INIT_CLASS_ENTRY(ce, "Wenku", wenku_methods);
215         wenku_ce = zend_register_internal_class(&ce TSRMLS_CC);
216         wenku_ce->create_object = wenku_create_handler;
217         memcpy(&wenku_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
218         wenku_object_handlers.clone_obj = NULL;
219         return SUCCESS;
220 }

PHP_MINIT_FUNCTION()函数的简要说明:
当HTTP服务启动的时候,它就启动PHP的解释器。PHP会调用每一个扩展的MINIT函数,可以通过查看php.ini文件来看哪些扩展模块是激活的。MINIT就是Module Initialization,即模块初始化方法的简称,在每一个模块初始化方法里,会定义并初始化一系列在以后的页面请求中需要用到的函数、类、变量等。

*没看懂上面代码的同学可以先这么干,后续我再补充相关说明。 *

五、配置、编译、安装,只需要按照上文所述步骤进行即可。

六、编写一个PHP的测试脚本:

  1 p_getCurrentSpeed(); // prints '0'
  5 echo "\n";
  6 $wenku->p_accelerate();
  7 print $wenku->p_getCurrentSpeed(); // prints '5'

输出结果0、5正确:

 zhangxuefeng@zhangxuefengs-MacBook-Pro  ~/Developer  php wenku-cpp.php
0
5%

你可能感兴趣的:(PHP的C/C++扩展(二))