生成扩展模板
人性化的PHP项目组给出了一个模板,也就是ext目录下的skeleton
其实我们可以直接COPY过来用的,网上很多方法都是去执行sh脚本ext_skel
或者php脚本ext_skel_win32.php
ext_skel
的作用极速生成一个skeleton插件而已,而源码中一般的已经生成好了的。
所以我们只需要改写几句ext_skel_win32.php
的脚本就能直接生成而不用安装CygWin
ext_skel_win32_virink.php
<?php
$extname = "YourExtName";
$skel = "skeleton";
$fp = fopen("$skel/skeleton.dsp", "rb");
if ($fp) {
$dsp_file = fread($fp, filesize("$skel/skeleton.dsp"));
fclose($fp);
$dsp_file = str_replace("extname", $extname, $dsp_file);
$dsp_file = str_replace("EXTNAME", strtoupper($extname), $dsp_file);
$fp = fopen("$extname/$extname.dsp", "wb");
if ($fp) {
fwrite($fp, $dsp_file);
fclose($fp);
}
}
$fp = fopen("$extname/$extname.php", "rb");
if ($fp) {
$php_file = fread($fp, filesize("$extname/$extname.php"));
fclose($fp);
$php_file = str_replace("dl('", "dl('php_", $php_file);
$fp = fopen("$extname/$extname.php", "wb");
if ($fp) {
fwrite($fp, $php_file);
fclose($fp);
}
}
?>
模板说明
最核心的内容就是php_extname.h
和extname.c
这两个文件,其他的都是辅助编译的。
php_extname.h
#ifndef PHP_EXTNAME_H
#define PHP_EXTNAME_H
上面两句没什么用
extern zend_module_entry extname_module_entry;
#define phpext_extname_ptr &extname_module_entry
这两句就是声明扩展模块的入口,给PHP调用的
#define PHP_EXTNAME_VERSION "0.1.0"
定义版本号
#ifdef PHP_WIN32
# define PHP_EXTNAME_API __declspec(dllexport)
#elif defined(__GNUC__) && __GNUC__ >= 4
# define PHP_EXTNAME_API __attribute__ ((visibility("default")))
#else
# define PHP_EXTNAME_API
#endif
判断操作系统以及编译器类型
#ifdef ZTS
#include "TSRM.h"
#endif
#ifdef ZTS
#define EXTNAME_G(v) TSRMG(extname_globals_id, zend_extname_globals *, v)
#else
#define EXTNAME_G(v) (extname_globals.v)
#endif
#endif /* PHP_EXTNAME_H */
ZTS是是否启用线程安全模式,不定义就是Non Thread Safe
extname.c
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
没什么用,无视
#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
#include "php_extname.h"
头文件,你懂的~~
static int le_extname;
定义全局资源(全局变量),在线程安全模式(thread safety
)下就不需要了
PHP_FUNCTION(confirm_extname_compiled)
{
char *arg = NULL;
int arg_len, len;
char *strg;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arg_len) == FAILURE) {
return;
}
len = spprintf(&strg, 0, "Congratulations! You have successfully modified ext/%.78s/config.m4. Module %.78s is now compiled into PHP.", "extname", arg);
RETURN_STRINGL(strg, len, 0);
}
定义一个php函数,这个函数是在php脚本里调用的。
PHP_FUNCTION是定义php函数的宏
// php.h
#define PHP_FUNCTION ZEND_FUNCTION
// zend_API.h
#define ZEND_FUNCTION(name) ZEND_NAMED_FUNCTION(ZEND_FN(name))
#define ZEND_NAMED_FUNCTION(name) void name(INTERNAL_FUNCTION_PARAMETERS)
#define ZEND_FN(name) zif_##name
函数名:confirm_extname_compiled
,调用:<?php confirm_extname_compiled(); ?>
zend_parse_parameters,获取函数参数
ZEND_API int zend_parse_parameters(int num_args TSRMLS_DC, const char *type_spec, ...);
RETURN_STRINGL,返回处理的结果
// zend_API.h
#define RETURN_STRINGL(s, l, duplicate) { RETVAL_STRINGL(s, l, duplicate); return; }
#define RETVAL_STRINGL(s, l, duplicate) ZVAL_STRINGL(return_value, s, l, duplicate)
#define ZVAL_STRINGL(z, s, l, duplicate) do { \
const char *__s=(s); int __l=l; \
zval *__z = (z); \
Z_STRLEN_P(__z) = __l; \
Z_STRVAL_P(__z) = (duplicate?estrndup(__s, __l):(char*)__s);\
Z_TYPE_P(__z) = IS_STRING; \
} while (0)
各种宏很多的~~想要知道的更多,自己去读源码咯
PHP_MINIT_FUNCTION(extname)
{
/* If you have INI entries, uncomment these lines
REGISTER_INI_ENTRIES();
*/
return SUCCESS;
}
Zend Engine加载了该模块时执行的函数,如果模块有ini配置,则需要使用REGISTER_INI_ENTRIES();
注册
PHP_MSHUTDOWN_FUNCTION(extname)
{
/* uncomment this line if you have INI entries
UNREGISTER_INI_ENTRIES();
*/
return SUCCESS;
}
ZE结束的时候执行此函数,最后关闭自己的核心子系统
PHP_RINIT_FUNCTION(extname)
{
return SUCCESS;
}
PHP收到请求的时候都执行该函数
PHP_RSHUTDOWN_FUNCTION(extname)
{
return SUCCESS;
}
PHP脚本执行完毕后执行该函数
PHP_MINFO_FUNCTION(extname)
{
php_info_print_table_start();
php_info_print_table_header(2, "extname support", "enabled");
php_info_print_table_end();
/* Remove comments if you have entries in php.ini
DISPLAY_INI_ENTRIES();
*/
}
在phpinfo()
中显示相关信息
const zend_function_entry extname_functions[] = {
PHP_FE(confirm_extname_compiled, NULL)
PHP_FE_END
};
声明自定义的php函数,供Zend Engine获取以便调用。
zend_module_entry extname_module_entry = {
STANDARD_MODULE_HEADER,
"extname",
extname_functions,
PHP_MINIT(extname),
PHP_MSHUTDOWN(extname),
PHP_RINIT(extname),
PHP_RSHUTDOWN(extname),
PHP_MINFO(extname),
PHP_EXTNAME_VERSION,
STANDARD_MODULE_PROPERTIES
};
实现扩展模块的入口
#ifdef COMPILE_DL_EXTNAME
ZEND_GET_MODULE(extname)
#endif
编译为zend扩展
加载工程
0x01
打开VS2012,选择”文件”–“新建”–“从现有代码创建目录”
选择C++类型的项目,下一步
然后,选择你的php扩展文件夹路径,并且给项目命名,下一步
选择动态链接库项目。
0x02
直接用vs2012打开extname.dsp文件,升级工程
配置解决方案
右键项目属性,配置列表选择所有配置,然后选择C/C++,常规,附加包含目录,编辑
加入以下几个php源码目录(实际目录以开发者自己的目录为准):
E:\php-x.x.x-src
E:\php-x.x.x-src\main
E:\php-x.x.x-src\TSRM
E:\php-x.x.x-src\Zend
然后选择预处理器,预处理器定义,编辑,加入以下变量:
- ZEND_DEBUG=0
- PHP_EXTENSION
- PHP_WIN32
- ZEND_WIN32
- HAVE_EXTNAME=1
- COMPILE_DL_EXTNAME
- ZTS(这一个变量加上是开启线程安全,不加是关闭线程安全)
(这里EXTNAME,要改成你的扩展名称,不改成你的扩展名,php会不识别)
config.w32.h
在E:\php-x.x.x-src\win32\build\
文件夹里找到”config.w32.h.in”,
将这个文件复制到E:\php-x.x.x-src\main\
文件夹里,去掉后面的”.in”
然后修改该文件里面的PHP_COMPILER_ID
#define PHP_COMPILER_ID "VC11" //编译器版本号
项目属性,链接器,输入,附加依赖项,编辑,将php5.lib的路径放进去
php5.lib
这个文件在编译好了的php程序目录dev里面有
结束语
导致了基本上好了,编译吧~~最简单的Demo扩展
然后,你可以根据PHP的各种API去编写你心仪的扩展啦
FROM : virzz.com | Author:Virink
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论