位置: 编程技术 - 正文

PHP扩展开发教程(总结)(php扩展编写)

编辑:rootadmin

推荐整理分享PHP扩展开发教程(总结)(php扩展编写),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:php扩展开发工具,php扩展安装方法,php7扩展开发,php扩展开发中文教程,php7扩展开发,php7扩展开发,php扩展开发中文教程,php扩展开发中文教程,内容如对您有帮助,希望把文章链接给更多的朋友!

PHP是一种解释型的语言,对于用户而言,我们精心的控制内存意味着easier prototyping和更少的崩溃!当我们深入到内核之后,所有的安全防线都已经被越过,最终还是要依赖于真正有责任心的软件工程师来保证系统的稳定运行。

1、线程安全宏定义

在TSRM/TSRM.h文件中有如下定义

#define TSRMLS_FETCH() void ***tsrm_ls = (void ***) ts_resource_ex(0, NULL)#define TSRMLS_FETCH_FROM_CTX(ctx) void ***tsrm_ls = (void ***) ctx#define TSRMLS_SET_CTX(ctx) ctx = (void ***) tsrm_ls#define TSRMG(id, type, element) (((type) (*((void ***) tsrm_ls))[TSRM_UNSHUFFLE_RSRC_ID(id)])->element)#define TSRMLS_D void ***tsrm_ls#define TSRMLS_DC , TSRMLS_D#define TSRMLS_C tsrm_ls#define TSRMLS_CC , TSRMLS_C

在ext/xsl/php_xsl.h有这么一段话

/* In every utility function you add that needs to use variables. in php_xsl_globals, call TSRM_FETCH(); after declaring other. variables used by that function, or better yet, pass in TSRMLS_CC after the last function argument and declare your utility function with TSRMLS_DC after the last declared argument. Always refer to the globals in your function as XSL_G(variable). You are. encouraged to rename these macros something shorter, see examples in any other php module directory.*/

1.在方法定义时加上TSRMLS_D(如果方法没有参数用这个)或者TSRMLS_DC(有1个以上的参数)

2.在方法调用时用TSRMLS_C(如果方法没有参数用这个)或者TSRMLS_CC(有1个以上的参数)

应该可以这样理解

第一个后缀字母D表示定义,即D=Define,第一个后缀字母C表示调用,即C=Call,而第二个后缀字母C是不是表示逗号呢? C=Comma (逗号)

TSRMLS_D就是定义了,所以是 void ***tsrm_ls

TSRMLS_DC是带逗号的定义,所以是 , void ***tsrm_ls

TSRMLS_C是调用,即tsrm_ls

TSRMLS_CC是调用并带逗号,即 ,tsrm_ls

所以一个是形参、一个是实参

可以这样使用

int php_myext_action(int action_id, char *message TSRMLS_DC);php_myext_action(, "The meaning of life" TSRMLS_CC);

一般推荐使用tsrm_ls指针定义的方式来保证线程安全

TSRMLS_FETCH调用需要一定的处理时间。这在单次迭代中并不明显,但是随着你的线程数增多,随着你调用TSRMLS_FETCH()的点的增多,你的扩展就会显现出这个瓶颈。因此,请谨慎的使用它。 注意:为了和c++编译器兼容,请确保将TSRMLS_FETCH()和所有变量定义放在给定块作用域的顶部(任何其他语句之前)。因为TSRMLS_FETCH()宏自身有多种不同的解析方式,因此最好将它作为变量定义的最后一行

2、PHP的生命周期

PHP的最多的两种运行模式是WEB模式、CLI模式,无论哪种模式,PHP工作原理都是一样的,作为一种SAPI运行。

1、当我们在终端敲入php这个命令的时候,它使用的是CLI。

它就像一个web服务器一样来支持php完成这个请求,请求完成后再重新把控制权交给终端。

2、当使用Apache作为宿主时,当一个请求到来时,PHP会来支持完成这个请求

PHP_MINIT_FUNCTION 初始化module时运行 PHP_MSHUTDOWN_FUNCTION 当module被卸载时运行 PHP_RINIT_FUNCTION 当一个REQUEST请求初始化时运行 PHP_RSHUTDOWN_FUNCTION 当一个REQUEST请求结束时运行 PHP_MINFO_FUNCTION 这个是设置phpinfo中这个模块的信息 PHP_GINIT_FUNCTION 初始化全局变量时 PHP_GSHUTDOWN_FUNCTION 释放全局变量时

比如PHP_GINIT_FUNCTION

这里有一段代码,可以测试一下

3、段错误调试

Linux下的C程序常常会因为内存访问错误等原因造成segment fault(段错误)此时如果系统core dump功能是打开的,那么将会有内存映像转储到硬盘上来,之后可以用gdb对core文件进行分析,还原系统发生段错误时刻的堆栈情况。这对于我们发现程序bug很有帮助。使用ulimit -a可以查看系统core文件的大小限制;使用ulimit -c [kbytes]可以设置系统允许生成的core文件大小。

ulimit -c 0 不产生core文件ulimit -c 设置core文件最大为kulimit -c unlimited 不限制core文件大小

步骤:

1、当发生段错误时,我们查看ulimit -a (core file size (blocks, -c) 0)并没有文件, 2、设置 :ulimit -c unlimited 不限制core文件大小3、运行程序 ,发生段错误时会自动记录在core中 (php -f WorkWithArray.php)4、ls -al core.* 在那个文件下(-rw------- 1 leconte leconte - :3 1 core.)5、使用gdb 运行程序和段错误记录的文件。(gdb ./test core.)6、会提哪行有错。

很多系统默认的core文件大小都是0,我们可以通过在shell的启动脚本/etc/bashrc或者~/.bashrc等地方来加入 ulimit -c 命令来指定core文件大小,从而确保core文件能够生成。除此之外,还可以在/proc/sys/kernel/core_pattern里设置core文件的文件名模板,详情请看core的官方man手册。

4、常见的变量操作宏

CG -> Complier Global 编译时信息,包括函数表等(zend_globals_macros.h:)EG -> Executor Global 执行时信息(zend_globals_macros.h:)PG -> PHP Core Global 主要存储php.ini中的信息SG -> SAPI Global SAPI信息

1、SG 针对SAPI信息 在main/SAPI.h文件中

看一下SG的定义

BEGIN_EXTERN_C()#ifdef ZTS# define SG(v) TSRMG(sapi_globals_id, sapi_globals_struct *, v)SAPI_API extern int sapi_globals_id;#else# define SG(v) (sapi_globals.v)extern SAPI_API sapi_globals_struct sapi_globals;#endifSAPI_API void sapi_startup(sapi_module_struct *sf);SAPI_API void sapi_shutdown(void);SAPI_API void sapi_activate(TSRMLS_D);SAPI_API void sapi_deactivate(TSRMLS_D);SAPI_API void sapi_initialize_empty_request(TSRMLS_D);END_EXTERN_C()

成员都在sapi_globals_struct这里了

那么我么可以这样调用

SG(default_mimetype)SG(request_info).request_uri

可以感受一下这么一段代码

2、EG Executor Globals

EG获取的是struct _zend_execution_globals结构体中的数据

通常,使用EG(symbol_table)获取的是全局作用域中的符号表,使用EG(active_symbol_table)获取的是当前作用域下的符号表

例如 来定义$foo = 'bar'

zval *fooval; MAKE_STD_ZVAL(fooval);ZVAL_STRING(fooval, "bar", 1);ZEND_SET_SYMBOL(EG(active_symbol_table), "foo", fooval);

PHP扩展开发教程(总结)(php扩展编写)

或者从符号表中查找$foo

zval **fooval;if(zend_hash_find(&EG(symbol_table), "foo", sizeof("foo"), (void **)&fooval) == SUCCESS) { RETURN_STRINGL(Z_STRVAL_PP(fooval), Z_STRLEN_PP(fooval));} else { RETURN_FALSE;}

上面的代码中,EG(active_symbol_table) == &EG(symbol_table)

3、CG() 用来访问核心全局变量。(zend/zend_globals_macros.h)

4、PG() PHP全局变量。我们知道php.ini会映射一个或者多个PHP全局结构。(main/php_globals.h)

5、FG() 文件全局变量。大多数文件I/O或相关的全局变量的数据流都塞进标准扩展出口结构。(ext/standard/file.h)

5、获取变量的类型和值

#define Z_TYPE(zval) (zval).type#define Z_TYPE_P(zval_p) Z_TYPE(*zval_p)#define Z_TYPE_PP(zval_pp) Z_TYPE(**zval_pp)

比如获取一个变量的类型

有这么几种类型

#define IS_NULL 0#define IS_LONG 1#define IS_DOUBLE 2#define IS_BOOL 3#define IS_ARRAY 4#define IS_OBJECT 5#define IS_STRING 6#define IS_RESOURCE 7#define IS_CONSTANT 8#define IS_CONSTANT_ARRAY 9#define IS_CALLABLE

php_printf()函数是内核对printf()函数的一层封装,我们可以像使用printf()函数那样使用它,以一个P结尾的宏的参数大多是*zval型变量。 此外获取变量类型的宏还有两个,分别是Z_TYPE和Z_TYPE_PP,前者的参数是zval型,而后者的参数则是**zval

比如gettype函数的实现

获取变量的值,有这么多宏来获取

Long

Boolean

Double

String value

String length

HashTable

Object

Object properties

Object class entry

Resource value

rot函数的实现

要获取变量的值,也应该使用Zend定义的宏进行访问。对于简单的标量数据类型、Boolean,long,double, 使用Z_BVAL, Z_LVAL, Z_DVAL

对于字符串类型,因为它含有两个字段char * (Z_STRVAL) 和 int (Z_STRLEN),因此需要用两个宏来进行取值,因为需要二进制安全的输出这个字符串

因为数组在zval中是以HashTable形式存在的,因此使用Z_ARRVAL()进行访问

一些类型转换函数

ZEND_API void convert_to_long(zval *op);ZEND_API void convert_to_double(zval *op);ZEND_API void convert_to_null(zval *op);ZEND_API void convert_to_boolean(zval *op);ZEND_API void convert_to_array(zval *op);ZEND_API void convert_to_object(zval *op);ZEND_API void _convert_to_string(zval *op ZEND_FILE_LINE_DC);

6、常量的实例化

我们可以这样实例化

常见的宏

/*注册LONG类型常量*/#define REGISTER_LONG_CONSTANT(name, lval, flags) zend_register_long_constant((name), sizeof(name), (lval), (flags), module_number TSRMLS_CC)

/*注册double类型常量*/#define REGISTER_DOUBLE_CONSTANT(name, dval, flags) zend_register_double_constant((name), sizeof(name), (dval), (flags), module_number TSRMLS_CC)

/*注册STRING类型常量*/#define REGISTER_STRING_CONSTANT(name, str, flags) zend_register_string_constant((name), sizeof(name), (str), (flags), module_number TSRMLS_CC)

/*注册STRING类型常量*/#define REGISTER_STRINGL_CONSTANT(name, str, len, flags) zend_register_stringl_constant((name), sizeof(name), (str), (len), (flags), module_number TSRMLS_CC)

7、全局变量

8、包装第三方库

配置(config.m4)

9、用于返回的宏

//这些宏都定义在Zend/zend_API.h文件里#define RETVAL_RESOURCE(l) ZVAL_RESOURCE(return_value, l)#define RETVAL_BOOL(b) ZVAL_BOOL(return_value, b)#define RETVAL_NULL() ZVAL_NULL(return_value)#define RETVAL_LONG(l) ZVAL_LONG(return_value, l)#define RETVAL_DOUBLE(d) ZVAL_DOUBLE(return_value, d)#define RETVAL_STRING(s, duplicate) ZVAL_STRING(return_value, s, duplicate)#define RETVAL_STRINGL(s, l, duplicate) ZVAL_STRINGL(return_value, s, l, duplicate)#define RETVAL_EMPTY_STRING() ZVAL_EMPTY_STRING(return_value)#define RETVAL_ZVAL(zv, copy, dtor) ZVAL_ZVAL(return_value, zv, copy, dtor)#define RETVAL_FALSE ZVAL_BOOL(return_value, 0)#define RETVAL_TRUE ZVAL_BOOL(return_value, 1)#define RETURN_RESOURCE(l) { RETVAL_RESOURCE(l); return; }#define RETURN_BOOL(b) { RETVAL_BOOL(b); return; }#define RETURN_NULL() { RETVAL_NULL(); return;}#define RETURN_LONG(l) { RETVAL_LONG(l); return; }#define RETURN_DOUBLE(d) { RETVAL_DOUBLE(d); return; }#define RETURN_STRING(s, duplicate) { RETVAL_STRING(s, duplicate); return; }#define RETURN_STRINGL(s, l, duplicate) { RETVAL_STRINGL(s, l, duplicate); return; }#define RETURN_EMPTY_STRING() { RETVAL_EMPTY_STRING(); return; }#define RETURN_ZVAL(zv, copy, dtor) { RETVAL_ZVAL(zv, copy, dtor); return; }#define RETURN_FALSE { RETVAL_FALSE; return; }#define RETURN_TRUE { RETVAL_TRUE; return; }

其实,除了这些标量类型,还有很多php语言中的复合类型我们需要在函数中返回,如数组和对象,我们可以通过RETVAL_ZVAL与RETURN_ZVAL来操作它们

、hashTable的遍历函数

//基于long key的操作函数zval *v3;MAKE_STD_ZVAL(v3);ZVAL_STRING(v3, "value3", 1);zend_hash_index_update(names, 0, &v3, sizeof(zval *), NULL);//按数字索引键更新HashTable元素的值zval **v4;zend_hash_index_find(names, 1, &v4); //按数字索引获取HashTable元素的值php_printf("v4 : ");PHPWRITE(Z_STRVAL_PP(v4), Z_STRLEN_PP(v4));php_printf("n");ulong idx;idx = zend_hash_index_exists(names, );//按数字索引查找HashTable,如果找到返回 1, 反之则返回 0zend_hash_index_del(names, 2); //按数字索引删除HashTable元素//hashTable的遍历函数zend_hash_internal_pointer_reset(names); //初始化hash指针zend_hash_internal_pointer_reset_ex(names, &pos);//初始化hash指针,并付值给poszend_hash_get_current_data(names, (void**) &val); //获取当前hash存储值,data should be cast to void**, ie: (void**) &datazend_hash_get_current_data_ex(names, (void**) &val, &pos) == SUCCESS; //获取当前hash存储值zend_hash_get_current_key(names, &key, &klen, &index, 0) == HASH_KEY_IS_LONGzend_hash_get_current_key_ex(names, &key, &klen, &index, 0, &pos) == HASH_KEY_IS_LONG; //读取hashtable当前的KEY,返回值会有两种 HASH_KEY_IS_LONG | HASH_KEY_IS_STRING ,分别对应array("value"),array("key"=>"value")两种hashtablezend_hash_move_forward(names);zend_hash_move_forward_ex(names, &pos); //hash指针移至下一位//HashTable长度php_printf("%*carray(%d) {n", depth * 2, ' ', zend_hash_num_elements(Z_ARRVAL_P(zv))

一个简单的函数

PHP内核实现

以上所述就是本文给大家介绍的PHP扩展开发教程,希望大家喜欢。

php实现网站留言板功能 我要实现的就是下图的这种样式,可参考下面这两个网站的留言板,他们的实现原理都是一样的畅言留言板样式:网易跟帖样式:原理需要在评论表添

双冒号 ::在PHP中的使用情况 前几天在百度知道里面看到有人问PHP中双冒号::的用法,当时给他的回答比较简洁因为手机打字不大方便!今天突然想起来,所以在这里总结一下我遇到

PHP explode()函数的几个应用和implode()函数有什么区别 explode()函数介绍explode()函数可以把字符串分割为数组。语法:explode(separator,string,limit)。参数描述separator必需。规定在哪里分割字符串。string必需。要分

标签: php扩展编写

本文链接地址:https://www.jiuchutong.com/biancheng/276022.html 转载请保留说明!

上一篇:smarty简单应用实例(smartypig)

下一篇:php实现网站留言板功能(php留言板的简单编写)

  • 税金返还需要交税吗
  • 运输开票的税点是多少
  • 坏账核销抵税
  • 视同销售但未收到钱怎么做账
  • 上季度弥补以前年度亏损与本季度亏损
  • 发生采购业务无合同需要缴印花税吗
  • 转回存货跌价准备对递延所得税资产的影响
  • 发票查询校验码看不清怎么办
  • 库存现金日记账格式
  • 物流商品采购价差如何做账
  • 专用基金计入什么科目
  • 关税现金流量表项目
  • 发票开出来对方不走账会怎么样?
  • 退回其他单位服务费怎么入账?
  • 研发支出费用化支出每个月都要结转吗
  • 收到违约金需要缴纳所得税吗
  • 补提以前年度个税会计分录
  • 公司开发票就会报税吗?
  • 预缴税多交了,税务局退吗
  • 增值税发票当期能抵扣吗
  • 卷式发票属于什么税
  • 哪些情形可以补胎
  • 餐饮发票可以抵扣成本吗
  • 税务代开劳务费税点如何确定
  • 收到委托代销清单的会计分录
  • 所得税费用计算典型例题
  • 做账的是什么会计
  • 1697508669
  • 所得税申报表本期金额上期金额指什么
  • 利润分配财务处理
  • 赡养老人个税扣除标准和条件是什么
  • 异地增值税预交可以网上缴纳吗
  • 腾讯手游助手如何隐藏键位
  • 苹果手机密码忘记了怎么重置密码
  • 苹果mac修改用户名和密码
  • cuda completed with errors
  • 交暖气费可以开单位发票吗
  • 已收到材料至月末仍未收到发票账单
  • 公司给员工发放福利会计分录
  • 知识图谱实现方案
  • python如何设置窗口背景色
  • 出口没有增值税发票需要交税吗
  • 冲销去年暂估成本对企业所得税的影响
  • 帝国cms采集教程
  • mongodb如何查询数据
  • 转回存货跌价准备的会计分录
  • 停车费报销会计分录
  • 市场开发费用会计分录
  • 冲抵和抵扣
  • 2021年税控盘收费
  • 刻章费用怎么说
  • 季节性停工固定资产折旧计入什么科目
  • 应付账款平账调到哪个科目
  • 展览展示服务费计入什么科目
  • 新手必看教程
  • 存货成本计算方法有几种?分别是什么?
  • deepin 2014系统下安装mysql数据库的方法步骤
  • win8系统无法连接到网络
  • 虚拟机linux使用
  • win10无线网络不见了只显示飞行模式
  • 无线网络连接不上显示无ip分配
  • qctray.exe - qctray进程 是什么文件 作用是什么
  • Win10 64位系统下火狐浏览器打开带flash网页卡死的解决方法
  • win10安装office2016无法注册字体可以忽略吗?
  • [置顶] 《精神怪谈》 后续起点
  • 简述opengl的编程步骤
  • jquery移除
  • jquery教程chm
  • jquery的css方法
  • 批处理文件的拷贝怎么写
  • unity游戏开发的技术路线有哪些
  • unity androidx
  • unity closestpoint
  • JavaScript+html5 canvas绘制的圆弧荡秋千效果完整实例
  • unity3d效果图
  • 胰腺在人体的哪个部位图解
  • Java之CyclicBarrier使用
  • 智能财税证书含金量如何
  • 纳税是什么税
  • 大连国家税务局官网
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设