今天看了一些PHP扩展的入门文章,很好的文章,但看的还是很吃力。主要是因为不了解文章里说的生命周期,内存分配,SAPI这些概念。然后代码里全是宏,如果不查源码,和看天书没什么区别。所以想记录一下从源码的角度分析 hello.c 这个文件的过程,其它文章里有的我就不重复了,我先放代码,这里有一个部分和原文章不一样。

随便新建一个文件夹,里面包含下面3个文件:

config.m4

PHP_ARG_ENABLE(hello, whether to enable Hello

World support,

[ --enable-hello Enable Hello World support])

if test "$PHP_HELLO" = "yes"; then

AC_DEFINE(HAVE_HELLO, 1, [Whether you have Hello World])

PHP_NEW_EXTENSION(hello, hello.c, $ext_shared)

fi

php_hello.h

#ifndef PHP_HELLO_H

#define PHP_HELLO_H 1

#define PHP_HELLO_WORLD_VERSION "1.0"

#define PHP_HELLO_WORLD_EXTNAME "hello"

PHP_FUNCTION(hello_world);

extern zend_module_entry hello_module_entry;

#define phpext_hello_ptr &hello_module_entry

#endif

hello.c

#ifdef HAVE_CONFIG_H

#include "config.h"

#endif

#include "php.h"

#include "php_hello.h"

// 模块所包含的函数列表信息

static zend_function_entry hello_functions[] = {

PHP_FE(hello_world, NULL)

{NULL, NULL, NULL}

};

// 模块自身的相关信息

// 如模块名,模块包含的函数,生命周期,版本号等

zend_module_entry hello_module_entry = {

#if ZEND_MODULE_API_NO >= 20010901

STANDARD_MODULE_HEADER,

#endif

PHP_HELLO_WORLD_EXTNAME,

hello_functions,

NULL,

NULL,

NULL,

NULL,

NULL,

#if ZEND_MODULE_API_NO >= 20010901

PHP_HELLO_WORLD_VERSION,

#endif

STANDARD_MODULE_PROPERTIES

};

// 与动态加载有关 Dynamic Loading,后面解释

#ifdef COMPILE_DL_HELLO

ZEND_GET_MODULE(hello)

#endif

// 你的扩展函数

PHP_FUNCTION(hello_world)

{

RETURN_STRING("Hello World", 1);

}

运行下面的命令可以验证扩展。

phpize

./configure

make

php -dextension=modules/hello.so -r "echo hello_world();"

和原文不同的是这里使用 zend_function_entry 而不是 function_entry。这个和 PHP 的版本有关,不然编译会出错。

我们先看这一段代码

static zend_function_entry hello_functions[] = {

PHP_FE(hello_world, NULL)

{NULL, NULL, NULL}

};

如果你查看 PHP 官方文档,也有可能会这样写。

static zend_function_entry hello_functions[] = {

PHP_FE(hello_world, NULL)

ZEND_FE_END

};

其实说到底,把这些你看不懂的宏的定义找出来,就好了,我们就先找 zend_function_entry,因为我的源码在下面这个路径下,所以我先 cd 过去。

/usr/local/Cellar/php56/5.6.32_8/include/php

然后用下面的命令找 zend_function_entry 的定义。

grep -rnw . -e 'zend_function_entry'

发现在 zend_API.h 这个文件。

./Zend/zend_API.h:41:} zend_function_entry;

源码是一个结构体,用到存储函数的信息。

typedef struct _zend_function_entry {

const char *fname;

void (*handler)(INTERNAL_FUNCTION_PARAMETERS);

const struct _zend_arg_info *arg_info;

zend_uint num_args;

zend_uint flags;

} zend_function_entry;

接着再看 PHP_FE,同理使用下面命令。

grep -rnw . -e 'PHP_FE'

得到下面的结果。

./main/php.h:352:#define PHP_FE ZEND_FE

再找 ZEND_FE,下面就不写了,最后查到是这个定义。

#define ZEND_FENTRY(zend_name, name, arg_info, flags) { #zend_name, name, arg_info, (zend_uint) (sizeof(arg_info)/sizeo

f(struct _zend_arg_info)-1), flags },

#define ZEND_FE(name, arg_info) ZEND_FENTRY(name, ZEND_FN(name), arg_info, 0)

其实就是一个关于函数结构体的信息,和之前的 zend_function_entry 对应。

再看 zend_module_entry 这一段代码,其实做法也是参照上面的,#if ZEND_MODULE_API_NO >= 20010901 是用来判断 api 版本是否大于等于 20010901 (这个是年月日),如果大于则在编译期包含 STANDARD_MODULE_HEADER 这个宏,这些信息都可以在下面这个源文件找到,ZEND_MODULE_API_NO 这个宏也是定义这个文件中的。

zend_modules.h

最后说说这个

// 与动态加载有关 Dynamic Loading,后面解释

#ifdef COMPILE_DL_HELLO

ZEND_GET_MODULE(hello)

#endif

其实我也不是很懂,查了 ZEND_GET_MODULE 这个宏,他是一个函数,用于在运行时供 Zend 引擎获取模块的名字。今天大概就到这里,下次再写函数带数的情况。

php extname shared,PHP: 编写第一个PHP扩展相关推荐

  1. php5.6扩展编写,php 5.6版本中编写一个PHP扩展的简单示例

    php 5.6版本中编写一个PHP扩展的简单示例 这篇文章主要介绍了php 5.6版本中编写一个PHP扩展的简单示例,本文给出扩展实现代码.编译方法.配置方法和使用例子等内容,需要的朋友可以参考下 有 ...

  2. go语言编写php扩展,[原创]快速开发一个PHP扩展-Go语言中文社区

    快速开发一个PHP扩展 本文通过非常快速的方式讲解了如何制作一个PHP 5.2 环境的扩展(PHP Extension),希望能够在图文的方式下让想快速学习的朋友了解一下制作过程. 需求:比如开发一个 ...

  3. 编写第一个HelloWorld驱动程序

    开发应用程序需要用到SDK,内核编程需要使用WDK(Windows Driver Kit),WDK已经自带所需要的头文件,库,C/C++语言及汇编语言的编译器与链接器,所有完全可以不用安装Visual ...

  4. Makefile编写及一个简单的Makefile架构实现

    Makefile编写及一个简单的Makefile架构实现 Makefile常用命令 GCC/G++常用编译参数 简单Makefile框架实现 使用CMake构建项目 Makefile常用命令 make ...

  5. 请编写出一个html页面 令其输出,javaweb程序设计案例教程_课后习题1.pdf

    第一章 [测一测] 学习完前面的内容,下面来动手测一测吧,请思考以下问题: 1.请描述HTML .CSS. .JavaScript 分别表示的含义. 2 .请列举出HTML 常用的标记.(至少10 个 ...

  6. iOS 11开发教程(七)编写第一个iOS11代码Hello,World

    iOS 11开发教程(七)编写第一个iOS11代码Hello,World 代码就是用来实现某一特定的功能,而用计算机语言编写的命令序列的集合.现在就来通过代码在文本框中实现显示"Hello, ...

  7. iOS 11开发教程(二)编写第一个iOS 11应用

    iOS 11开发教程(二)编写第一个iOS 11应用 编写第一个iOS 11应用 本节将以一个iOS 11应用程序为例,为开发者讲解如何使用Xcode 9.0去创建项目,以及iOS模拟器的一些功能.编 ...

  8. iOS游戏框架Sprite Kit基础教程第1章编写第一个Sprite Kit程序

    iOS游戏框架Sprite Kit基础教程第1章编写第一个Sprite Kit程序 程序是为了实现特定目标或解决特定问题而用计算机语言编写的命令序列的集合.本章将以编写第一个Sprite Kit程序为 ...

  9. Xamarin iOS开发实战第1章使用C#编写第一个iOS应用程序

    Xamarin iOS开发实战第1章使用C#编写第一个iOS应用程序 C#原本是用来编写Windows以及Windows Phone的应用程序.自从Xamarin问世后,C#的作用就发生了很大的变化. ...

最新文章

  1. git---远程仓库版本回滚
  2. 【邮箱使用】Yahoo邮箱POP3、SMTP开通以及设置方法
  3. PHP--认识Smarty模板引擎
  4. G - Bad Hair Day (单调栈)
  5. asp.net web 开发登录相关操作的控件LoginName、LoginStatus和LoginView控件使用详解
  6. P4245 【模板】任意模数多项式乘法(NTT)
  7. imx226_相机选型器
  8. 第一百零四天 how can I 坚持
  9. 谈谈JS里的{ }大括号和[ ]中括号的用法
  10. mngoDB 常用语法
  11. Win10企业版激活方法
  12. 用Kodi访问Win10共享文件夹
  13. Matlab学习手记——非线性拟合方法:压缩因子粒子群算法
  14. Espressif 玩转 固件下载
  15. 计算机桌面黑屏有鼠标,电脑屏幕黑屏但有鼠标指针是怎么回事?
  16. cmake清空缓存 cmake clean
  17. Matlab论文插图绘制模板第39期—阶梯图(Stairs)
  18. 用js进行日期的加减
  19. 解决Chaquopy在AS中pip安装过慢的问题
  20. Linux GDB分析死锁

热门文章

  1. 揭秘猪八戒调戏嫦娥背后的阴谋
  2. 【时光之穿越一千年】python全文字频解析【jieba】【matplotlib构图】案例
  3. 查询DBA_HIST_ACTIVE_SESS_HISTORY缓慢
  4. Docker 安装 For CentOS 7.4
  5. ssh终端远程登陆主机命令--笔记
  6. stm32 之引脚和各功能模块间关系
  7. 设置Hadoop的 dataNode的单个Map的内存配置
  8. 编码注释coding: utf-8
  9. Atitit.rust语言特性 attilax 总结
  10. 《人件集 人性化的软件开发》阅读笔记01