67677新澳门手机版 > 67677新澳门手机版 > PHP扩展编写方法
PHP扩展编写方法
2020-03-20 16:38

独自的 PHP 扩张能够独自于 PHP 源码之外实行分发。要开创一个这么的恢宏,必要预备好两样东西:

前天看了一部分PHP扩张的入门文章,很好的小说,但看的依旧很困苦。首假设因为不打听作品里说的生命周期,内部存款和储蓄器分配,SAPI这么些概念。然后代码里全部是宏,假设不查源码,和看天书没什么不一致。所以想记录一下从源码的角度分析hello.c 那个文件的进度,其余散文里一些作者就不另行了,作者先放代码,这里有叁个有的和原小说不等同。

本方案中应用的PHP扩张形式为:

用C/C++扩张PHP的利弊:
优点:
频率,如故效用
减削PHP脚本的复杂度, 极端情状下, 你只必要在PHP脚本中,轻松的调用一个扩张完成的函数,然后你持有的效益都就被扩张达成了
而劣点也是综上说述的: 付出复杂
可维护性减弱
开垦周期变长, 最简易的四个事例,当您用PHP脚本的时候, 纵然你开掘有些决断标准出错,你一旦校正了这一行,保存,那么就立刻能见到成效。 而假设是在C/C++编写的PHP扩展中, 那您可索要,改善源码,重新编译,然后重新load进PHP, 然后重启Apache,才能见到效果。
假定你熟谙C,那么编写贰个PHP增添,并非何等非常难的业务。 PHP本人就提供了二个框架,来简化你的费用。
最简便的法门来最早三个PHP扩大的付出,是应用PHP提供的强盛框架wizard ext_skel, 它会变动三个PHP扩张所必得的最基本的代码, 要使用它,首先你要下载PHP的源码,或许开辟包, 步入PHP源码的ext目录, 就能开掘这一个工具。
变迁叁个恢宏: ./ext_skel --extname=myext
步向/myext,接纳扩张类型:
vi config.m4
上面两体系型选一个就行了:
复制代码 代码如下:
//(信赖外界库State of Qatar
dnl PHP_ARG_WITH(myext, for myext support,
dnl Make sure that the comment is aligned:
dnl [ --with-myext Include myext support])
//去掉dnl
 PHP_ARG_WITH(myext, for myext support,
 Make sure that the comment is aligned:
 [  --with-myext             Include myext support])

  • 布署文件 (config.m4卡塔尔国
  • 你的模块源码

无论是新建叁个文本夹,里面包罗上边3个文件:

Ø下载PHP对应版本的源码,在里头到场、生成增加(如smsupport.so);

//可能将 //(不信赖外界库卡塔尔国 dnl PHP_ARG_ENABLE(myext, whether to enable myext support,dnl Make sure that the comment is aligned:dnl [ --enable-myext Enable myext support])//去掉dnl
改善头文件php_myext.h:
//PHP_FUNCTION(confirm_myext_compiled); /* For testing, remove later. */
//修改为
PHP_FUNCTION(myext); /* For testing, remove later. */
修改myext.c:
//将
//zend_function_entry myext_functions[] = {
// PHP_FE(confirm_myext_compiled, NULL) /* For testing, remove later. */
// {NULL, NULL, NULL} /* Must be the last line in myext_functions[] */
//};
//修改为
zend_function_entry myext_functions[] = {
PHP_FE(myext, NULL) /* For testing, remove later. */
{NULL, NULL, NULL} /* Must be the last line in myext_functions[] */
};
//在文书底部加多本人的函数
PHP_FUNCTION(myext)
{
zend_printf("Hello World!n");
}
安装本身的php扩大myext:
/usr/local/php/bin/phpize
./configure --with-php-config=/usr/local/php/bin/php-config
make
make install

接下去大家来描述一下只要创设这一个文件并整合起来。

config.m4

Ø然后针对安装同一本子的PHP(注意,不需如若源码安装的,能够透过yum install,apt-get install安装的),将smsupport.so放置到extension_dir中;在php.ini最后一行参加extension = smsupport.so;

修改php.ini,添加:
extension = "myext.so"
重启web服务器,查看phpinfo,就可以看出自个儿的扩展:

计划好系统工具

想要扩大能够在系统上编写翻译并打响运营,必要预备转以下工具:

  • GNU autoconf
  • GNU automake
  • GNU libtool
  • GNU m4

如上那几个都得以从 获取。

注:以上这几个都以类 Unix 意况下才具应用的工具。

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

Ø重启apached服务

图片 1

改装贰个早就存在的扩充

为了显得出创造多个单独的强盛是超级轻巧的作业,大家先将一个早就内嵌到 PHP 的扩大改成单身扩张。安装 PHP 况兼施行以下命令:

$ mkdir /tmp/newext
$ cd /tmp/newext

当今你早就有了叁个空目录。大家将 mysql 扩张目录下的公文复制过来:

$ cp -rp php-4.0.X/ext/mysql/* .
# 注:看来这篇 README 真的需要更新一下了
# PHP7 中已经移除了 mysql 扩展部分

到此地扩张就完事了,实行:

$ phpize

以往您能够独自贮存在此个目录下的文本到另各州方,这一个扩张能够完全部独用立存在了。

顾客在编写翻译时必要接收以下命令:

$ ./configure 
       [--with-php-config=/path/to/php-config] 
       [--with-mysql=MYSQL-DIR]
$ make install

那般 MySQL 模块就能够动用内嵌的 MySQL 客商端库也许已设置的放在 MySQL 目录中的 MySQL。

注:意思是说想要编写 PHP 扩张,你既要求已经设置了 PHP,也须求下载一份 PHP 源码。

php_hello.h

Ø从此以后,在php文件中平昔调用smsupport.so提供的秘诀就能够。

新建测验php文件:

概念贰个新增添

小编们给示例扩张命名称叫 “foobar”。

新扩充蕴涵七个财富文件:foo.c 和 bar.c(还会有一对头文件,但那么些不仅仅主要)。

身体力行扩大不援用任何外部的库(那一点很关键,因为如此客户就无需特意钦命一些编写翻译选项了)。

LTLIBRARY_SOURCES 选项用于钦命财富文件的名字,你能够有专断数量的能源文件。

注:上边说的是 Makefile.in 文件中的配置选项,能够参谋 xdebug。

#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

注意点

myext();

校正 m4 后缀的安排文件

m4 配置文件能够钦定一些外加的检讨。对于一个独自扩大来讲,你只要求做一些宏调用就能够。

PHP_ARG_ENABLE(foobar,whether to enable foobar,
[  --enable-foobar            Enable foobar])

if test "$PHP_FOOBAR" != "no"; then
  PHP_NEW_EXTENSION(foobar, foo.c bar.c, $ext_shared)
fi

PHP_ARG_ENABLE 会自动安装好精确的变量以承保增加能够被 PHP_NEW_EXTENSION 以共享格局运营。

PHP_NEW_EXTENSION 的率先个参数是增添的称呼,第一个参数是财富文件。第八个参数 $ext_shared 是由 PHP_ARG_ENABLE/WITHPHP_NEW_EXTENSION 设定的。

请始终使用 PHP_ARG_ENABLEPHP_ARG_WITH 实行安装。即便你不计划公布你的 PHP 模块,那几个设置也能够有限辅助让你的模块和 PHP 主模块的接口保持紧凑。

注:PHP_ARG_ENABLEPHP_ARG_WITH 应该是用以定义模块是动态扩大依旧静态编写翻译进 PHP 中,就跟编写翻译 PHP 时选拔的 --enable-xxx--with-xxx 一样。

hello.c

Ø在开展增加及测验的经过中大家必要安装PHP的SAFE_MODE为OFF,不然大概不可能成功扩展或测量试验。SAFE_MODE默认为OFF。

施行此文件,就可以看出再熟稔然而的“Hello World!”。

成立财富文件

ext_skel 可感觉您的 PHP 模块创设一些通用的代码,你也能够编写一些大旨函数定义和 C 代码来管理函数的参数。具体音信方可查阅 READNE.EXT_SKEL。

不要顾虑未有轨范,PHP 中有多数模块供你参谋,接收四个轻巧易行的点起来,增多你本人的代码。

注:ext_skel 能够生成好焦点模块要求的能源文件和计划文件,无需团结创立。

#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);
}

Ø编写翻译php扩张的条件和平运动作蒙受急需一致!

图片 2

纠正自定义模块

将 config.m4 文件和财富文件放到同三个目录中,然后奉行 phpize (PHP 4.0 以上的本子编写翻译 PHP 的时候都设置了 phpize)。

如若你的 phpize 不在系统意况变量中,你须求钦点相对路线,举个例子:

$ /php/bin/phpize

以此命令会自动复制必得的创设文件到当前目录并依照 config.m4 创制构造文件。

因而上述的手续,你早本来就有了一个独自的恢弘了。

运维上边包车型大巴下令能够表明扩充。

Ø提议先使用PHP推行脚本,那个时候提供错误新闻较为丰硕。

安装扩大

强大能够透过以下命令编写翻译安装:

$ ./configure 
            [--with-php-config=/path/to/php-config]
$ make install
phpize
./configure
make
php -dextension=modules/hello.so -r "echo hello_world();"

PHP扩张开采

给模块增加共享扶植

不时独立增加需即使共享的已供其余模块加载。接下来我会解释怎么样给已经成立好的 foo 模块增多分享扶植。

  1. 在 config.m4 文件中,使用 PHP_ARG_WITH/PHP_ARG_ENABLE 来设定扩充,那样就足以活动使用 --with-foo=shared[,..]--enable-foo=shared[,..] 那样的指令作为编译参数了。
  2. 在 config.m4 文件中,使用 PHP_NEW_EXTENSION(foo,.., $ext_shared) 使扩张能够被创设。
  3. 增多以下代码到你的 C 语言能源文件中:
   #ifdef COMPILE_DL_FOO
   ZEND_GET_MODULE(foo)
   #endif

这一段讲的方面都涉嫌过了,这里只是又强调了一下。

和最早的小说不一致的是此处运用 zend_function_entry 而不是 function_entry。那几个和 PHP 的版本有关,不然编写翻译会出错。

1.从 php中下载对应目标的PHP版本;

PECL 网址约定

即便您策画发表你的增到 PECL 的网址,要求构思以下几点:

  1. 添加 LICENSE 或 COPYING 到 package.xml
  2. 亟需在强大头文件中定义好版本音讯,那个宏会被 foo_module_entry 调用来声称扩大版本:
   #define PHP_FOO_VERSION "1.2.3"

我们先看这一段代码

2.是因为php信赖libxml2-dev,为此,首先通过apt-get install libxml2-dev可能yum install libxml2-dev(注libxml2-dev在不一致Linux下名称不相同,baidu下)

static zend_function_entry hello_functions[] = {
    PHP_FE(hello_world, NULL)
    {NULL, NULL, NULL}
};

3.解压缩1中下载的php包,步入目录,运转./configure实现都部队署,那个时候会转移编写extension所需的片段文书

如若您查看 PHP 官方文档,也可能有很大恐怕会如此写。

4.进去到php源码中的ext目录,试行./ext_skel --extname=smsupport,其会自动生成一层层目录及目录内的文本

static zend_function_entry hello_functions[] = {
    PHP_FE(hello_world, NULL)
    ZEND_FE_END
};

5.在ext/smsupport目录中

实则提起底,把那么些你看不懂的宏的定义找寻来,就好了,我们就先找 zend_function_entry,因为本人的源码在底下那么些渠道下,所以自个儿先 cd 过去。

a卡塔尔(قطر‎在.c文件中找到const zend_function_entry cqwei_functions[] = {,在其后增加自个儿定义的函数

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

只顾:自动生成的为c文件,由于本扩大中要用到cpp,强行将其改为cpp,在编写翻译时在后端加上-lstdc++,使得编写翻译成功

下一场用下边包车型大巴下令找 zend_function_entry 的定义。

PHP_FE(testadd,NULL)/*For testing, remove later. */

grep -rnw . -e 'zend_function_entry'

PHP_FE(dcsSM2Verify,arg_dcsSM2Verify)

发现在 zend_API.h 那几个文件。

PHP_FE(dcsSM4Decrypt,arg_dcsSM4Decrypt)

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

注意点:

源码是三个布局体,用到存款和储蓄函数的新闻。

ü将PHP_FE的名目改成温馨的函数,能够况兼包涵四个;

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中包含的函数必要参数,则应参预参数新闻,如arg_Verify,其中arg_Verify包含4个参数,arg_Decrypt包含2个参数。

进而再看 PHP_FE,同理使用上边施命发号。

nZEND_BEGIN_ARG_INFO_EX(arg_Verify,

grep -rnw . -e 'PHP_FE'

0, 0, 1)

得到下边包车型地铁结果。

ZEND_ARG_INFO(0,user)

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

ZEND_ARG_INFO(0,pubKey)

再找 ZEND_FE,上面就不写了,最终查到是这么些概念。

ZEND_ARG_INFO(0,ticket)

#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_ARG_INFO(0,sig)

实际上正是一个关于函数结构体的新闻,和此前的 zend_function_entry 对应。

ZEND_END_ARG_INFO()

再看 zend_module_entry 这一段代码,其实做法也是参照上边的,#if ZEND_MODULE_API_NO >= 二零零零0901 是用来推断 api 版本是或不是超过等于 二零零零0901 (这一个是年月日卡塔尔国,假若抢先则在编写翻译期包涵 STANDATucsonD_MODULE_HEADE昂Cora那几个宏,这一个音讯都得以在底下这些源文件找到,ZEND_MODULE_API_NO 这么些宏也是概念那一个文件中的。

nZEND_BEGIN_ARG_INFO_EX(arg_Decrypt,0, 0, 1)

zend_modules.h

ZEND_ARG_INFO(0,key)

最终说说这一个

ZEND_ARG_INFO(0,cipher)

// 与动态加载有关 Dynamic Loading,后面解释
#ifdef COMPILE_DL_HELLO
ZEND_GET_MODULE(hello)
#endif

ZEND_END_ARG_INFO()

实则笔者亦不是很懂,查了 ZEND_GET_MODULE 那个宏,他是三个函数,用于在运作时供 Zend 引擎获取模块的名字。后日津高校约就到此处,后一次再写函数带数的动静。

b)PHP_FUNCTION(testaddState of Qatar在概念自定义函数testadd的函数体,如下所示为最简易的开始和结果

PHP_FUNCTION(testadd)

{

zend_printf("testadd00");

}

c)PHP_FUNCTION(Verify卡塔尔(قطر‎,稍稍复杂,因为有参数和再次回到值,示比如下