1. 1. 变量操作(常量)
  2. 设置变量 ZVAL_*系列函数;
  3. 例:
  4. zval t;
  5. ZVAL_STRING(t,"10",2);
  6. 获取变量 Z_* 系列函数
  7. 获取变量指针 Z_*_P 系列函数
  8. 获取变量指针的指针 Z_*_PP 系列函数
  9. 例:
  10. Z_STRVAL(t);
  11. Z_STRLEN(t);
  12. 变量类型转换 convert_to_* 系列函数
  13. 例:
  14. convert_to_long_ex(t);
  15. 获取变量类型 Z_TYPE Z_TYPE_P Z_TYPE_PP 可以同 IS_* 系列常量对比
  16. 例:
  17. if(Z_TYPE_P(filehandle)!=IS_LONG)
  18. php_printf("this is long type!");
  19. 申请变量的内存 一般 ALLOC_ZVAL(zv) ,MAKE_STD_ZVAL(zv)宏,用完释放 FREE_ZVAL(zv)等宏
  20. 释放变量内存 zval_dtor(zval) zval_ptr_dtor(&zval); FREE_ZVAL(zval);
  21. 注意:FREE_ZVAL 只释放zval结构体内存,而zval_dtor会释放zval变量及value指针内存
  22. 打印普通变量 php_printf("hi function!"); 返回输出流,可以使用 PHPWRITE(str, str_len) 继续写
  23. 打印zval变量
  24. php_var_dump(zval **struc, int level TSRMLS_DC); var_dump C实现 在:ext/standard/php_var.h
  25. zend_print_zval_r(zval *expr, int indent TSRMLS_DC) print_r C实现 Zend核心里
  26. 字符串变量生成函数 spprintf(char **pbuf, size_t max_len, const char *format, ...); 用完释放efree();
  27. 申请内存并复制字符串的副本 estrdup(&a) estrndup(&a,10);
  28. 变量内存申请:emalloc(size) efree(ptr) 不要用malloc 除非你能明确释放掉
  29. 定义常量:REGISTER_*_CONSTANT(name, str, flags)系列函数 flags CONST_* 系列宏
  30. 复制变量 :MAKE_COPY_ZVAL(ppzv, pzv) 申请内存并复制 COPY_PZVAL_TO_ZVAL 复制一个zval指向同类型的zval
  31. 2. 全局C变量辅助宏:
  32. EG(v);//全局变量 executor_globals 如$_GLOBALS[EG(symbol_table),地址:EG(active_symbol_table)
  33. PG(v);//核心变量 php_core_globals 如:$_GET $_POST .. PG(http_globals)[TRACK_VARS_*],INI信息
  34. SG(v);//SAPI变量 请求数据 sapi_globals_struct 如:HTTP原始请求变量 sapi_request_info
  35. CG(v);//编译变量 compiler_globals 可以得到函数表,类表
  36. EX(v);//当前执行数据 zend_execute_data 可以获取到当前执行的函数,类,OPCODE等
  37. OG(v);//输出变量 output_globals
  38. 3. 函数,分5 ZEND_*_FUNCTION 以下为C定义内置函数
  39. 函数参数说明 FOR C:
  40. int ht, zval *return_value, zval **return_value_ptr, zval *this_ptr, int return_value_used
  41. ht 参数个数,但不能直接使用,该用 ZEND_NUM_ARGS()获取
  42. return_value 函数返回zval
  43. return_value_ptr 返回值的指针,但想控制返回值的内容,不是直接返回返回值时候用到,如参数引用实现.
  44. this_ptr 如果当前方法是一个对象的方法,此值指向该方法指向的对象,不能直接使用,使用 getThis() 函数
  45. return_value_used 返回值有没有被使用
  46. 例:
  47. int argc = ZEND_NUM_ARGS();
  48. char *str=NULL;
  49. int strlen;
  50. //次方法用于获取函数参数
  51. //注意: O 参数须 &object zval 指针 和指明 zend_class_entry * 的指针
  52. // s 参数需要 &str char * 指针 和 &strlen int 长度指针
  53. if (zend_parse_parameters(argc TSRMLS_CC, "s|s",&str,&strlen) ==FAILURE) {
  54. return;
  55. }
  56. //此方法一般用于类的静态方法,当函数映射类方法的时候.
  57. //会校验getThis()的类和object是否一个类zend_class_entry
  58. if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &object, date_ce_date,&str,&strlen) == FAILURE) {
  59. RETURN_FALSE;
  60. }
  61. 关于返回
  62. 修改 return_value_ptr 指针指向要用ALLOC_ZVAL_*宏申请内存,
  63. 参考:http://www.walu.cc/phpbook/6.1.md
  64. 返回的宏 RETURN_*系列函数,资源用 ZEND_REGISTER_RESOURCE
  65. RETURN_ZVAL(); 返回zval结构
  66. 如果是申请的内存,RETURN_ZVAL(zv, copy, dtor) copy 0 dtor 0
  67. 如果是堆栈内存 RETURN_ZVAL(zv, copy, dtor) copy 1 dtor 0
  68. 4. 数组与HASH
  69. 1. zvalue_value 是个union 数组时为 hashtable
  70. 2. hashtable 表有很对对应的处理函数:zend_hash_*系列函数
  71. 3. 数组上的HASHTABLE一般不直接操作,通过add_*系列函数处理
  72. 4. hashtable 内存申请 ALLOC_HASHTABLE 等宏处理,用完释放FREE_HASHTABLE
  73. 5. 数组初始化也不要用直接处理hashtable,使用 array_init 处理
  74. 5. 资源变量
  75. 1. 需要使用资源变量须先得到一个资源列表
  76. 参数:1.请求资源,每次请求会清空此请求的资源列表
  77. 2.永久资源,服务启动后永久保存
  78. 3.显示资源名
  79. 4.内部管理参数,忽略
  80. le_myfile = zend_register_list_destructors_ex(myfile_dtor,NULL,"standard-c-file", module_number);
  81. static void myfile_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC){
  82. FILE *fp = (FILE *) rsrc->ptr;//转换指定类型,方便以后操作
  83. fclose(fp);
  84. }
  85. 2. 把资源注册进资源列表,并设置return_value
  86. int r=ZEND_REGISTER_RESOURCE(return_value, fp, le_myfile);
  87. 3. 查询资源
  88. filehandle 为资源zval
  89. ZEND_FETCH_RESOURCE(fp, FILE *, &filehandle, -1, "standard-c-file",le_myfile);
  90. if (fp == NULL){
  91. RETURN_FALSE;
  92. }
  93. 4.删除资源
  94. filehandle 为资源zval
  95. if (zend_list_delete(Z_RESVAL_P(filehandle)) == FAILURE) {
  96. RETURN_FALSE;
  97. }
  98. 6. 全局函数
  99. zend_function_entry test_functions[] =
  100. {
  101. //参数 : 函数名
  102. ZEND_FE(myecho, NULL)
  103. ZEND_FE_END
  104. };
  105. 注册到模块中
  106. zend_module_entry php_test_module_entry = {
  107. #if ZEND_MODULE_API_NO >= 20010901
  108. STANDARD_MODULE_HEADER,
  109. #endif
  110. "my test ext",//模块名
  111. test_functions,//函数列表
  112. NULL,
  113. NULL,
  114. NULL,
  115. NULL,
  116. PHP_MINFO(php_test),//模块介绍
  117. #if ZEND_MODULE_API_NO >= 20010901
  118. "1.6.0", //版本
  119. #endif
  120. STANDARD_MODULE_PROPERTIES
  121. };
  122. //函数实现,参考 3.函数部分
  123. PHP_FUNCTION(myecho){}
  124. 用户函数调用:
  125. 参数:
  126. function_table 函数表,全局从&CG(function_table)得到
  127. 对象,如果该函数是对象的方法,没有传NULL
  128. 函数名
  129. 返回值存储 zval指针,
  130. 参数数量
  131. 参数数组
  132. call_user_function(HashTable *function_table, zval **object_pp, zval *function_name, zval *retval_ptr, zend_uint param_count, zval *params[] TSRMLS_DC);
  133. 7. 类的实现,结构:zend_class_entry 分两种 ZEND_INTERNAL_CLASS ZEND_USER_CLASS
  134. //访问权限控制:ZEND_ACC_*系列宏
  135. //类方法定义
  136. //参数:类名 方法名
  137. ZEND_METHOD( myclass , public_method )
  138. {
  139. //获取参数方法,参考:3.函数 部分
  140. if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "s", &str,&strlen) == FAILURE) {
  141. RETURN_FALSE;
  142. }
  143. php_printf("hi function!");
  144. }
  145. //注册到函数列表
  146. static zend_function_entry myclass_method[]={
  147. //参数:类名 方法名 静态方法加 ZEND_ACC_STATIC
  148. ZEND_ME(myclass, public_method, NULL, ZEND_ACC_PUBLIC)
  149. {NULL,NULL,NULL}
  150. };
  151. zend_class_entry ce;
  152. zend_class_entry *myclass_ce;
  153. //参数:初始结构 类名 方法列表
  154. INIT_CLASS_ENTRY(ce,"myclass",myclass_method);
  155. //此方法会根据ce拷贝生成一个zend_class_entry并挂载到类列表中
  156. zend_register_internal_class(&ce TSRMLS_CC);
  157. //添加类的属性
  158. //参数:类指针 属性名 属性名长度 属性访问权限 : zend_declare_property_* 系列函数
  159. zend_declare_property_null(myclass_ce, "public_var", strlen("public_var"), ZEND_ACC_PUBLIC TSRMLS_CC);
  160. //定义类常量:
  161. //参数:类指针 属性名 属性名长度 属性访问权限 : zend_declare_class_constant* 系列函数
  162. zend_declare_class_constant_null(myclass_ce, "aaa", 3 TSRMLS_DC);
  163. 读取类静态属性
  164. ZEND_API zval *zend_read_static_property(
  165. zend_class_entry *scope,
  166. char *name,
  167. int name_length,
  168. //属性不存在是否抛出 notice
  169. zend_bool silent TSRMLS_DC
  170. );
  171. 更新类静态属性
  172. ZEND_API int zend_update_static_property(
  173. zend_class_entry *scope,
  174. char *name,
  175. int name_length,
  176. zval *value TSRMLS_DC
  177. );
  178. 其他封装的快捷函数 zend_update_static_property_*
  179. 8. 接口 结构也是: zend_class_entry
  180. static zend_function_entry i_myinterface_method[]={
  181. //注意这里的null指的是arg_info,具体可以参考:参数 arg_info 的定义
  182. ZEND_ABSTRACT_ME(i_myinterface, hello, NULL)
  183. ZEND_FE_END
  184. };
  185. //定义及初始化
  186. zend_class_entry ce;
  187. INIT_CLASS_ENTRY(ce, "i_myinterface", i_myinterface_method);
  188. i_myinterface_ce = zend_register_internal_interface(&ce TSRMLS_CC);
  189. 9. 继承及接口实现
  190. 1.实现接口:
  191. 写完类,接口后添加:
  192. 参数: 类指针 ,实现接口数量,接口指针...
  193. zend_class_implements(class_ce TSRMLS_CC,1,myinterface_ce);
  194. 2.实现继承:
  195. 注册类时候使用: zend_register_internal_class_ex
  196. 参数: 类指针 父类指针 父类名
  197. myclass_ce = zend_register_internal_class_ex(&ce,parent_class_ce,"parent_class" TSRMLS_CC);
  198. 10. 对象 zend_object_value
  199. 结构:
  200. typedef struct _zend_object_value {
  201. //unsigned int类型,EG(objects_store).object_buckets的索引
  202. zend_object_handle handle;
  203. zend_object_handlers *handlers;
  204. } zend_object_value;
  205. 创建对象:
  206. zval *obj;
  207. MAKE_STD_ZVAL(obj);
  208. object_init_ex(obj, zend_class_entry 类名 );
  209. //object_init(obj) 空对象
  210. 读取属性:
  211. ZEND_API zval *zend_read_property(
  212. zend_class_entry *scope,
  213. zval *object,
  214. char *name,
  215. int name_length,
  216. //属性不存在是否抛出 notice
  217. zend_bool silent TSRMLS_DC
  218. );
  219. 更新属性:
  220. ZEND_API int zend_update_static_property(
  221. zend_class_entry *scope,
  222. char *name,
  223. int name_length,
  224. zval *value TSRMLS_DC
  225. );
  226. 其他封装的快捷函数 zend_update_property_*
  227. 调用方法:
  228. ZEND_API zval* zend_call_method(zval **object_pp, zend_class_entry *obj_ce, zend_function **fn_proxy, const char *function_name, int function_name_len, zval **retval_ptr_ptr, int param_count, zval* arg1, zval* arg2 TSRMLS_DC);
  229. zend_call_method_with_0_params(obj, obj_ce, fn_proxy, function_name, retval)
  230. zend_call_method_with_1_params(&this_zval,myclass_ce,NULL,"hello",NULL);
  231. 11. 常用结构及宏解释:
  232. PHP_FN(name) 函数名生成
  233. PHP_MN(name) 方法名生成
  234. ZEND_NAMED_FUNCTION(name) 生成指定名的函数 一般用
  235. PHP_FUNCTION(name) 函数声明
  236. ZEND_METHOD(classname, name) 类方法声明
  237. zend_function_entry 数组用于声明模块或类的成员函数情况
  238. 生成zend_function_entry的元素配套宏:
  239. //注册全局的函数
  240. //参数:函数名 参数
  241. PHP_FE(name, arg_info)
  242. //注册类的函数
  243. //参数:类名 方法名 参数 访问权限控制
  244. PHP_ME(classname, name, arg_info, flags)
  245. //映射一个函数为类的方法
  246. //参数:方法名 函数名 参数 访问权限控制
  247. //用此宏须在函数体内进行类校验,zend_parse_method_parameters
  248. //调用时会把当前对象作为第一个参数传递给函数
  249. PHP_ME_MAPPING(name, func_name, arg_types, flags)
  250. //注册类的抽象函数,类和接口都用这个
  251. //参数:类名 方法名 参数
  252. PHP_ABSTRACT_ME(classname, name, arg_info)
  253. //结束标记
  254. PHP_FE_END
  255. 12. 参数 arg_info 的定义
  256. 一般情况下不需要定义参数,除非你希望PHP般你检查参数正确性,比如接口方法
  257. 生成arg_info的宏,以arg_say_hello为例:
  258. //参数:zend_arg_info 名,参数至少前N个
  259. ZEND_BEGIN_ARG_INFO(arg_say_hello, 0)
  260. //参数:是否设置为引用,参数名
  261. //ZEND_ARG_* 系列函数还可以声明对象等
  262. ZEND_ARG_INFO(0, name)
  263. ZEND_END_ARG_INFO()
  264. //其他介绍
  265. //name 参数名称
  266. //name_len 参数名称字符串长度
  267. //class_name 当参数类型为类时,指定类名称
  268. //class_name_len 类名称字符串长度
  269. //array_type_hint 标识参数类型是否为数组
  270. //allow_null 是否允许设置为空
  271. //pass_by_ref 是否设置为引用,即使用&操作符
  272. //return_reference 标识函数将重写return_value_ptr,后面介绍函数返回值时再做介绍
  273. //required_num_args 设置函数被调用时,传递参数至少为前N个,当设置为-1时,必须传递所有参数
  274. 13. 目录结构
  275. ext/ 扩展
  276. ext/standard PHP内置函数
  277. Zend/ PHP核心
  278. Zend/zend_builtin_functions.c 核心函数 还有常用的辅助函数
  279. sapi/ sapi接口实现
  280. main/ 对外编写接口
  281. 14. 流程及扩展备注
  282. zend_module_entry php_test_module_entry = {
  283. STANDARD_MODULE_HEADER,
  284. "my test ext", /* 模块名称 */
  285. test_functions, /* 模块函数 */
  286. PHP_MINIT(test), /* 模块启动 */
  287. PHP_MSHUTDOWN(test), /* 模块关闭 */
  288. PHP_RINIT(test), /* 请求开始 */
  289. PHP_RSHUTDOWN(test), /* 请求完成 */
  290. PHP_MINFO(php_test), /* 模块信息 */
  291. "1.6.0", /* 模块版本 */
  292. //还可以增加全局变量注册部分,参考:16.全局变量
  293. STANDARD_MODULE_PROPERTIES
  294. };
  295. ZEND_GET_MODULE(php_test);
  296. PHP_MINIT_FUNCTION(test)
  297. {
  298. //此阶段注册类等
  299. //注册INI
  300. //REGISTER_INI_ENTRIES();
  301. return SUCCESS;
  302. }
  303. PHP_RINIT_FUNCTION(test){
  304. return SUCCESS;
  305. }
  306. PHP_RSHUTDOWN_FUNCTION(test){
  307. return SUCCESS;
  308. }
  309. PHP_MSHUTDOWN_FUNCTION(test)
  310. {
  311. UNREGISTER_INI_ENTRIES();
  312. return SUCCESS;
  313. }
  314. 15. 配置设置与获取
  315. PHP_INI_BEGIN()
  316. PHP_INI_ENTRY("myini","bbb",PHP_INI_ALL, NULL)
  317. PHP_INI_END()
  318. //一般在 PHP_MINIT_FUNCTION 注册
  319. PHP_MINIT_FUNCTION(test)
  320. {
  321. //***
  322. REGISTER_INI_ENTRIES();
  323. //***
  324. }
  325. 获取配置:
  326. INI_* 系列宏
  327. 16. 线程安全的全局变量,并定义获取方法,类似于:EG(v) PG(v) SG(v) 等实现
  328. //test 一般为模块名,也可以用其他,用模块名号记忆
    //注意:全局变量不跟随请求,请求完成不会重置.
  329. ZEND_BEGIN_MODULE_GLOBALS(test)
  330. int flags;
  331. ZEND_END_MODULE_GLOBALS(test)
  332. #ifdef ZTS
  333. # define YOURGET(v) TSRMG(test_globals_id, zend_test_globals *, v)
  334. #else
  335. # define YOURGET(v) (test_globals.v)
  336. #endif
  337. //以上为声明部分
  338. //以下为:初始化及注册到PHP内核中
  339. ZEND_DECLARE_MODULE_GLOBALS(test);
  340. //全局可用
  341. //ZEND_EXTERN_MODULE_GLOBALS(test);
  342. zend_module_entry php_test_module_entry = {
  343. STANDARD_MODULE_HEADER,
  344. "my test ext",
  345. test_functions,
  346. NULL,
  347. NULL,
  348. NULL,
  349. NULL,
  350. NULL,
  351. NO_VERSION_YET,//以下为开启全局变量时增加
  352. PHP_MODULE_GLOBALS(test),//作用:注册到全局变量中
  353. PHP_GINIT(test),//全局变量初始化时调用函数,一般为启动PHP时,可为NULL
  354. PHP_GSHUTDOWN(test),//全局变量销毁时调用函数,一般为关闭PHP时,可为NULL
  355. NULL,
  356. STANDARD_MODULE_PROPERTIES_EX //注意:多个EX
  357. };
  358. //全局变量注册的回调函数 宏
  359. static PHP_GINIT_FUNCTION(test)
  360. {
  361. test_globals->flags = 0;
  362. }
  363. static PHP_GSHUTDOWN_FUNCTION(test)
  364. {
  365. //其他操作,如释放申请的内存等
  366. }
  367. 17. gdb调试扩展
  368. PHP编译的时候加上 -–enable-debug 参数
  369. 修改config.m4
  370. if test -z "$PHP_DEBUG" ; then
  371. AC_ARG_ENABLE(debug,
  372. [--enable-debug compile with debugging system],
  373. [PHP_DEBUG=$enableval],[PHP_DEBUG=no]
  374. )
  375. fi
  376. ./configure 的时候加入 enable-debug
  377. //设置 core 的大小
  378. ulimit -c unlimited
  379. //以下假设php路径在系统的/usr/bin或/usr/local/bin中
  380. gdb php -c core[core为生成的core文件]
  381. 常用调试命令:
  382. r 运行
  383. b 设置断点
  384. set args 设置参数
  385. n 运行下一步
  386. c 继续运行
  387. p 打印
  388. watch 当变量修改断点
  389. list 查看代码
  390. layout src 显示源码
  391. layout asm 显示汇编

    gdb 错误: Missing separate debuginfos, use: debuginfo-install 

  1、需要先修改“/etc/yum.repos.d/CentOS-Debuginfo.repo”文件的enable=1;
  2、使用 sudo yum install glibc 安装;
  3、使用 debuginfo-install glibc-2.12-1.132.el6.i686 安装。

  1.  

 

版权声明:本文为liushannet原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/liushannet/p/4074134.html