Php extension开发

2,482 views

Published on

Published in: Technology
0 Comments
3 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
2,482
On SlideShare
0
From Embeds
0
Number of Embeds
139
Actions
Shares
0
Downloads
44
Comments
0
Likes
3
Embeds 0
No embeds

No notes for slide

Php extension开发

  1. 1. ianzhang
  2. 2. What is Extension <ul><li>standard extension </li></ul><ul><li>自定义 extension </li></ul>
  3. 3. What is Extension <ul><li>apc, mysqli 等都是 extension </li></ul><ul><li>默认放在 /usr/local/php/lib/php/extensions/no-debug-non-zts-20060613 中 </li></ul><ul><li>在 php.ini 中开启需要的 extension </li></ul>
  4. 4. Extension 能做什么 <ul><li>和不同业务交互,接口是 C/C++ 接口,我们需要 extension 从 php 和这些接口交 互,协议接口 </li></ul><ul><li>使用 extension 和共享内存交互,和高性能 c 程序完成高性能工作 - 数据库异步写操作 </li></ul><ul><li>利用 c 的运算速度,完成高性能算法在 php 中的实现 </li></ul><ul><li>将之前必须在 c 的环境下的工作,转移到 php 中 – 高性能 server 在 php 中的开发 </li></ul>
  5. 5. 今天的目标 <ul><li>Hello World </li></ul><ul><li>一个简单的加法运算函数 </li></ul>
  6. 6. 开发环境 <ul><li>Linux 系统 </li></ul><ul><li>autoconfig </li></ul><ul><li>php 源码 </li></ul><ul><li>安装好的 php 环境 </li></ul>That‘s All ! Easy
  7. 7. PHP 程序生命周期
  8. 8. Apache PHP 子进程
  9. 9. Begin <ul><li>所有 extension 的编译环境都放在源代码的 Ext 子目录下 </li></ul><ul><li>使用自动构建系统 </li></ul><ul><li>./ext_skel --extname = my_module </li></ul><ul><li>创建了名为 my_module 的文件夹 </li></ul>
  10. 10. config.m4 <ul><li>用于 Autoconfig, 用 m4 文件来处理宏生成需要的 configure 文件 </li></ul><ul><li>config.m4 文件负责在配置时解析 configure 的命令行选项 </li></ul><ul><li>在 config.m4 中 dnl 表示注释 </li></ul>
  11. 11. config.m4 <ul><li>PHP_ARG_WITH 和 PHP_ARG_ENABLE 指定了 PHP 扩展模块的工作方式,前者意味着不需要第三方库,后者正好相反 </li></ul><ul><li>if test &quot;$PHP_MY_MODULE&quot; != &quot;no“ </li></ul><ul><li>PHP_ADD_INCLUDE 指定 PHP 扩展模块用到的头文件目录 </li></ul><ul><li>PHP_SUBST(MY_MODULE_SHARED_LIBADD) 用于说明这个扩展编译成动态链接库的形式 </li></ul>
  12. 12. C -> C++ <ul><li>PHP core 是用 c 编写的,使用 c++ 的时候,需要在 config.m4 中增加参数 </li></ul><ul><li>PHP_REQUIRE_CXX() </li></ul><ul><li>PHP_ADD_LIBRARY(stdc++,&quot;&quot;,MY_MODULE_SHARED_LIBADD) </li></ul><ul><li>PHP_NEW_EXTENSION(my_module, “my_module.cpp&quot;, $ext_shared) </li></ul><ul><li>修改 .c 变成 .cpp </li></ul>
  13. 13. C -> C++ <ul><li>对于 ext_skel 生成的代码使用 extern “c” 来兼容纯 c 的代码 </li></ul><ul><li>注:因为不同的编译器可能生成不同的中间符号名,所以用 extern 来修饰,具体参见 http://www.cppblog.com/Macaulish/archive/2008/06/17/53689.html </li></ul>
  14. 14. Add function <ul><li>打开 php_my_module.h </li></ul><ul><li>找到 PHP_FUNCTION ,增加一行 PHP_FUNCTION(my_module_test); </li></ul><ul><li>打开 my_module.cpp </li></ul><ul><li>搜索 PHP_FE ,增加一行 PHP_FE(my_module_test, NULL) </li></ul><ul><li>增加 PHP_FUNCTION(my_module_test) </li></ul>
  15. 15. Coding function <ul><li>ZEND 的编程使用大量的宏,手册和对宏的了解是必不可少的 </li></ul><ul><li>Output </li></ul><ul><li>Input </li></ul><ul><li>Handle </li></ul><ul><li>Return </li></ul>
  16. 16. Output <ul><li>使用 zend_printf 函数完成 output </li></ul><ul><li>zend_error(E_ERROR, “xxx” ) 错误输出 E_ERROR </li></ul><ul><li>E_WARNING </li></ul><ul><li>E_NOTICE </li></ul><ul><li>E_CORE_ERROR </li></ul><ul><li>E_COMPILE_ERROR </li></ul><ul><li>E_COMPILE_WARNING </li></ul>
  17. 17. Input <ul><li>ZEND_NUM_ARGS () 取得传入参数数量 </li></ul><ul><li>WRONG_PARAM_COUNT 抛出参数错误,终止程序 </li></ul>
  18. 18. Input <ul><li>使用 zend_parse_parameters 来取得参数 </li></ul><ul><ul><li>第一个参数表示需要解析的个数,可以使用 ZEND_NUM_ARGS() 来表示对传入的参数“有多少要多少”。 </li></ul></ul><ul><ul><li>type_spec 是一个字符串,用来指定各个参数的类型,类似于 printf 中的参数格式化 ,当然后面的就是类似的变参,但是注意这里全部要使用参数的指针来获取 </li></ul></ul>
  19. 19. Input 参数类型 <ul><li>l - 长整数 </li></ul><ul><li>d - 双精度浮点数 </li></ul><ul><li>s - 字符串 ( 也可能是空字节 ) 和其长度 </li></ul><ul><li>b - 布尔值 </li></ul><ul><li>r - 资源 , 保存在 zval* </li></ul><ul><li>a - 数组 , 保存在 zval* </li></ul><ul><li>o - (任何类的)对象 , 保存在 zval* </li></ul><ul><li>O - (由 class entry 指定的类的)对象 , 保存在 zval* </li></ul><ul><li>z - 实际的 zval* </li></ul><ul><li>| - 表明剩下的参数都是可选参数。如果用户没有传进来这些参数值,那么这些值就会被初始化成默认值。 </li></ul><ul><li>/ - the parsing function will call SEPARATE_ZVAL_IF_NOT_REF() on the parameter it follows, to provide a copy of the parameter, unless it's a reference </li></ul><ul><li>! - the parameter it follows can be of specified type or NULL (仅用在 a 、 o 、 O 、 r 和 z 身上)。如果用户传进来了一个 NULL 值,则存储该参数的变量将会设置为 NULL 。 </li></ul>
  20. 20. Input Sample1
  21. 21. Input Sample2
  22. 22. Handle <ul><li>Exension 中处理部分最特殊的部分就是 php extension 中 c 的变量如何被 php 代码使用 </li></ul><ul><li>两种交互方法 </li></ul><ul><ul><li>创建一个变量,加到 php 的变量容器中 </li></ul></ul><ul><ul><li>创建一个变量,返回这个变量 </li></ul></ul>
  23. 23. PHP 访问 Zend 变量 <ul><li>创建 zval 容器 </li></ul><ul><li>对 zval 结构进行填充 </li></ul><ul><li>把 zval 引入 zend 的内部符号表中 </li></ul><ul><li>从 php 端访问 </li></ul>
  24. 24. 变量作用域 <ul><li>全局变量 </li></ul><ul><li>&EG(symbol_table) </li></ul><ul><li>局部变量 </li></ul><ul><li>EG(active_symbol_table) </li></ul><ul><li>使用局部变量的时候要注意陷阱和段错误 </li></ul>
  25. 25. 加入符号表效率 <ul><li>宏 ZNED_SET_SYMBOL </li></ul><ul><li>首先检查变量是否已经存在于符号表中,如果已经存在则将其转换为一个引用变量(同时会自动销毁原有的 zval 容器)。速度较慢,节省内存 </li></ul><ul><li>zend_hash_update 函数 </li></ul><ul><li>强制更新符号表,速度较快,内存消耗稍多 </li></ul>
  26. 26. 变量赋值 <ul><li>zval 结构 </li></ul><ul><li>value 存放 zval 的值, type 存放类型 </li></ul><ul><li>zval 赋值 </li></ul>
  27. 27. 不同变量类型 <ul><li>IS_LONG </li></ul><ul><li>IS_DOUBLE </li></ul><ul><li>IS_STRING </li></ul><ul><li>IS_BOOL </li></ul>
  28. 28. 数组变量赋值 <ul><li>数组在 Zend 内部是用哈希表( HashTable )来存储的 </li></ul><ul><li>array_init(zval*) 来进行数组的初始化 </li></ul><ul><li>使用 add_assoc_*() 和 add_index_*() </li></ul><ul><li>add_assoc_long(zval *array, char *key, long n); </li></ul><ul><li>add_assoc_string(zval *array, char *key, char *str, int duplicate); </li></ul><ul><li>add_index_long(zval *array, uint idx, long n); </li></ul><ul><li>add_index_string(zval *array, uint idx, char *str, int duplicate); </li></ul>
  29. 29. 数组变量赋值 <ul><li>因为数组变量是用 hash 表来管理的,使用 </li></ul><ul><li>zend_hash_update(new_array->value.ht, key, strlen(key) + 1, (void *)&new_element, sizeof(zval *), NULL) </li></ul><ul><li>zend_hash_index_update(new_array->value.ht, key, (void *)&new_element, sizeof(zval *), NULL) </li></ul>
  30. 30. 对象变量 <ul><li>Object like Array </li></ul><ul><li>object_init() 初始化对象 </li></ul><ul><li>使用 add_property_*() 函数 </li></ul><ul><li>add_property_long(zval *object, char *key, long l); </li></ul><ul><li>add_property_string(zval *object, char *key, char *str, int duplicate); </li></ul><ul><li>add_property_bool(zval *object, char *key, int b); </li></ul>
  31. 31. Return <ul><li>返回值都是通过为 return_value 的变量传递的。这个参数是一个已经申请好空间的 zval 容器,无需先对 return_value 执行 MAKE_STD_ZVAL 宏指令。 </li></ul>
  32. 32. Return <ul><li>使用 RETURN_* 和 RETVAL_* 宏来完成 </li></ul><ul><li>RETURN_BOOL(bool) 返回一个布尔值。 RETURN_NULL() 返回一个空值。 </li></ul><ul><li>RETURN_LONG(long) 返回一个长整数。 </li></ul><ul><li>RETVAL_LONG(long) 设定返回值为指定的一个长整数。 </li></ul><ul><li>RETVAL_DOUBLE(double) 设定返回值为指定的一个双精度浮点数。 </li></ul><ul><li>RETVAL_STRING(string, duplicate) </li></ul>
  33. 33. More to learn <ul><li>Extension 运行模式 </li></ul><ul><li>内存管理 </li></ul><ul><li>资源控制 </li></ul><ul><li>Class </li></ul><ul><li>… .. </li></ul>
  34. 34. Reference <ul><li>Zend API </li></ul><ul><li>http://yanbin.org/archive/php-manual-hacking-the-code-of-php.html </li></ul><ul><li>Extension Writing </li></ul><ul><li>http://devzone.zend.com/article/1021 </li></ul><ul><li>http://my.huhoo.net/archives/2008/06/linuxcphp.html </li></ul><ul><li>GOOGLE </li></ul><ul><li>PHP.NET </li></ul>
  35. 35. Thank You

×