简单来说,PHPER 学 PHP 扩展开发核心就四点:
提性能:突破 PHP 解释执行的瓶颈,高频计算 / 数据处理等核心逻辑能提速数倍甚至数十倍;补能力:实现纯 PHP 做不到的底层操作(如系统 / 硬件交互、自定义语法 / 加密等);优架构:封装核心逻辑复用,隔离高危操作,提升系统稳定性;涨竞争力:从单纯的业务 CURD 开发者,升级为能触及 PHP 内核的中高级开发者 / 架构师,技术壁垒更高。
如果只是常规 Web 开发(CURD),可能用不上;但想解决性能瓶颈、拓展 PHP 能力边界,或往高阶方向发展,这是必备技能。
进入php源码ext目录下,新建demo拓展
php ext_skel.php --ext demo --vendor demo
进入demo拓展目录,执行php开发工具phpize
C:\project\php\php-8.5.1-devel-vs17-x64\phpize.bat
再执行编译工具
C:\project\php\php-sdk-binary-tools\phpsdk-vs16-x64.bat
执行配置demo
configure --enable-demo
编译
nmake
比如:demo 模块
/* demo extension for PHP */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "php.h"
#include "ext/standard/info.h"
#include "help.h" /* 引入帮助文件 */
/* 1.第一步 导出模块入口 */
extern zend_module_entry demo_module_entry;
#define phpext_demo_ptr &demo_module_entry
#if defined(ZTS) && defined(COMPILE_DL_DEMO)
ZEND_TSRMLS_CACHE_EXTERN()
#endif
/* 2.第二部 定义模块函数 */
/* -----------定义函数 hello */
/* 定义参数配置 */
beginArgWithReturnTypeInfoEx(info_hello, 0, 0, isVoid, 0)
endArgInfo()
/* 定义函数 hello */
phpFn(hello)
{
/* 解析参数 */
parseParamsNone();
/* 打印hello world */
php_printf("hello world\n");
}
/* -----------定义函数 hello_two */
/* 定义参数配置 */
beginArgWithReturnTypeInfoEx(info_hello_two, 0, 1, isStr, 0)
argTypeInfoWithDefaultVal(0, str, isStr, 0, "\"world\"")
endArgInfo()
/* 定义函数 hello_two */
phpFn(hello_two)
{
char *str = "kingbes";
size_t str_len = strlen(str);
/* 解析参数 */
parseParamsStart(0, 1)
paramOptional
paramStr(str, str_len);
parseParamsEnd();
zend_string *retval = strpprintf(0, "hello %s", str);
/* 返回字符串 */
returnStr(retval);
}
/* 3.第三步 定义模块初始化 */
// -----------定义模块函数
static const zend_function_entry ext_functions[] = {
zendFe(hello, info_hello)
zendFe(hello_two, info_hello_two)
zendFeEnd
};
/* -----------定义模块初始化 */
rinitModule(demo)
{
#if defined(ZTS) && defined(COMPILE_DL_DEMO)
ZEND_TSRMLS_CACHE_UPDATE();
#endif
return SUCCESS;
}
/* -----------定义模块信息 */
mInfoModule(demo)
{
printTableStart();
printTableRow("demo support", "enabled");
printTableRow("demo desc", "demo extension for PHP");
printTableEnd();
}
/* 4.第四步 定义模块入口 */
zend_module_entry demo_module_entry = {
STANDARD_MODULE_HEADER,
"demo", /* 拓展名称 */
ext_functions, /* 函数方法接口 */
NULL, /* PHP_MINIT - 模块初始化 */
NULL, /* PHP_MSHUTDOWN - 模块关闭 */
PHP_RINIT(demo), /* PHP_RINIT - 请求初始化 */
NULL, /* PHP_RSHUTDOWN - 请求关闭 */
PHP_MINFO(demo), /* PHP_MINFO - 模块信息 */
"0.1.0", /* 版本号 */
STANDARD_MODULE_PROPERTIES
};
#ifdef COMPILE_DL_DEMO
#ifdef ZTS
ZEND_TSRMLS_CACHE_DEFINE()
#endif
ZEND_GET_MODULE(demo)
#endif
php 使用
hello();
var_dump(hello_two());
比如:demo2 模块 命名空间demo2,类型MyClass
use demo2\MyClass;
/* demo2 extension for PHP */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "php.h"
#include "ext/standard/info.h"
#include "help.h"
/* 1.第一步 导出模块入口 */
extern zend_module_entry demo2_module_entry;
#define phpext_demo2_ptr &demo2_module_entry
#if defined(ZTS) && defined(COMPILE_DL_DEMO2)
ZEND_TSRMLS_CACHE_EXTERN()
#endif
/* 静态 类入口 */
static zend_class_entry *demo2_class_ce;
/* -----------定义类方法 */
beginArgInfo(info__construct, 0, 0,0)
endArgInfo()
phpMethod(MyClass, __construct)
{
parseParamsNone();
php_printf("hello MyClass\n");
}
beginArgWithReturnTypeInfoEx(info_hello, 0, 0, isVoid, 0)
endArgInfo()
phpMethod(MyClass, hello)
{
parseParamsNone();
php_printf("hello MyClass function\n");
}
/* -----------定义模块函数 */
static const zend_function_entry demo2_myclass_methods[] = {
zendMe(MyClass, __construct, info__construct, publicFlag)
zendMe(MyClass, hello, info_hello, publicFlag)
zendFeEnd
};
static zend_class_entry *register_class_demo2_MyClass(void)
{
zend_class_entry ce, *class_entry;
INIT_NS_CLASS_ENTRY(ce, "demo2", "MyClass", demo2_myclass_methods);
class_entry = zend_register_internal_class_ex(&ce, NULL);
class_entry->ce_flags |= ZEND_ACC_FINAL;
return class_entry;
}
/* -----------初始化类模块 */
rinitModule(demo2)
{
#if defined(ZTS) && defined(COMPILE_DL_DEMO2)
ZEND_TSRMLS_CACHE_UPDATE();
#endif
return SUCCESS;
}
minitFunction(demo2)
{
demo2_class_ce = register_class_demo2_MyClass();
return SUCCESS;
}
PHP_MSHUTDOWN_FUNCTION(demo2)
{
return SUCCESS;
}
/* -----------定义模块信息 */
mInfoModule(demo2)
{
printTableStart();
printTableRow("demo2 support", "enabled");
printTableRow("demo2 desc", "demo2 extension for PHP");
printTableEnd();
}
zend_module_entry demo2_module_entry = {
STANDARD_MODULE_HEADER,
"demo2", /* Extension name */
NULL, /* zend_function_entry */
PHP_MINIT(demo2), /* PHP_MINIT - Module initialization */
PHP_MSHUTDOWN(demo2), /* PHP_MSHUTDOWN - Module shutdown */
PHP_RINIT(demo2), /* PHP_RINIT - Request initialization */
NULL, /* PHP_RSHUTDOWN - Request shutdown */
PHP_MINFO(demo2), /* PHP_MINFO - Module info */
"1.0.0", /* Version */
STANDARD_MODULE_PROPERTIES};
#ifdef COMPILE_DL_DEMO2
#ifdef ZTS
ZEND_TSRMLS_CACHE_DEFINE()
#endif
ZEND_GET_MODULE(demo2)
#endif
php使用
use demo2\MyClass;
$myClass = new MyClass();
$myClass->hello();
help.h#ifndef HELP_H
#define HELP_H
/* For compatibility with older PHP versions */
#ifndef ZEND_PARSE_PARAMETERS_NONE
#define ZEND_PARSE_PARAMETERS_NONE() \
ZEND_PARSE_PARAMETERS_START(0, 0) \
ZEND_PARSE_PARAMETERS_END()
#endif
// ----------------------定义PHP拓展----------------------
/**
* @brief 模块信息函数
* @param var mod 拓展名
*/
#define mInfoModule(mod) PHP_MINFO_FUNCTION(mod)
#define printTableStart() php_info_print_table_start()
#define printTableRow(key, value) php_info_print_table_row(2, key, value)
#define printTableEnd() php_info_print_table_end()
/**
* @brief 初始化PHP拓展
* @param var mod 拓展名
*/
#define rinitModule(mod) PHP_RINIT_FUNCTION(mod)
/**
* @brief 初始化PHP拓展
* @param var mod 拓展名
*/
#define minitFunction(mod) PHP_MINIT_FUNCTION(mod)
// ----------------------定义PHP拓展----------------------
// ----------------------定义PHP方法----------------------
/**
* @brief 定义PHP方法结束
*
*/
#define zendFeEnd ZEND_FE_END
/**
* @brief 定义PHP方法
* @param var name 方法名
* @param var arginfo 参数配置名
*/
#define zendFe(name, arginfo) ZEND_FE(name, arginfo)
/**
* 创建 PHP 函数
* @param var name 函数名
*/
#define phpFn(name) \
ZEND_FUNCTION(name); \
PHP_FUNCTION(name)
/**
* @brief 定义PHP类方法
* @param var classname 类名
* @param var name 方法名
* @param var arg_info 参数配置名
* @param var flags 方法标志
*/
#define zendMe(classname, name, arg_info, flags) ZEND_ME(classname, name, arg_info, flags)
/**
* @brief 定义PHP类方法
* @param var classname 类名
* @param var name 方法名
*/
#define phpMethod(classname, name) \
ZEND_METHOD(classname, name); \
PHP_METHOD(classname, name)
// 公共方法标志
#define publicFlag ZEND_ACC_PUBLIC
// 受保护方法标志
#define protectedFlag ZEND_ACC_PROTECTED
// 私有方法标志
#define privateFlag ZEND_ACC_PRIVATE
// 属性或方法会覆盖掉私有属性或方法
#define changedFlag ZEND_ACC_CHANGED
// 静态方法标志
#define staticFlag ZEND_ACC_STATIC
// ----------------------定义PHP方法----------------------
// ----------------------定义参数解析----------------------
/**
* @brief 解析参数开始 (通常用不用返回的函数,比如构造函数等)
* @param var info_name 参数配置名
* @param int _unused 未使用参数
* @param int ret_ref 是否返回引用 0为不返回引用 1为返回引用
* @param int required_num_args 必须参数数量
*/
#define beginArgInfo(info_name, _unused, ret_ref, required_num_args) ZEND_BEGIN_ARG_INFO_EX(info_name, _unused, ret_ref, required_num_args)
/**
* @brief 解析返回参数开始
* @param var info_name 参数配置名
* @param int ret_ref 是否返回引用 0为不返回引用 1为返回引用
* @param int required_num_args 必须参数数量
* @param var type 返回参数类型
* @param int allow_null 是否允许NULL 0为不允许NULL 1为允许NULL
*/
#define beginArgWithReturnTypeInfoEx(info_name, ret_ref, required_num_args, type, allow_null) \
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(info_name, ret_ref, required_num_args, type, allow_null)
/**
* @brief 解析参数结束
*
*/
#define endArgInfo() ZEND_END_ARG_INFO()
/**
* @brief 解析默认参数类型信息
* @param int pass_by_ref 是否按引用传递 0为不按引用传递 1为按引用传递
* @param var arg_name 参数名
* @param var type_hint 参数类型
* @param int allow_null 是否允许NULL 0为不允许NULL 1为允许NULL
* @param mixed default_val 默认值
*/
#define argTypeInfoWithDefaultVal(pass_by_ref, arg_name, type_hint, allow_null, default_val) \
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(pass_by_ref, arg_name, type_hint, allow_null, default_val)
/**
* @brief 解析无参数
*
*/
#define parseParamsNone() ZEND_PARSE_PARAMETERS_NONE()
/**
* @brief 解析参数开始
* @param int start 开始参数索引 从0开始
* @param int end 结束参数索引 从0开始
*/
#define parseParamsStart(start, end) ZEND_PARSE_PARAMETERS_START(start, end)
/**
* @brief 解析参数结束
*
*/
#define parseParamsEnd() ZEND_PARSE_PARAMETERS_END()
/**
* @brief 参数为可选的
*
*/
#define paramOptional Z_PARAM_OPTIONAL
/**
* @brief 参数字符串
* @param var 字符串变量
*/
#define paramStr(var, var_len) Z_PARAM_STRING(var, var_len)
/**
* @brief 参数为整数
* @param var 整数变量
*/
#define paramInt(var) Z_PARAM_LONG(var)
/**
* @brief 参数为浮点数
* @param var 浮点数变量
*/
#define paramFloat(var) Z_PARAM_DOUBLE(var)
/**
* @brief 参数为数组
* @param var 数组变量
*/
#define paramArray(var) Z_PARAM_ARRAY(var)
/**
* @brief 参数为对象
* @param var 对象变量
*/
#define paramObj(var) Z_PARAM_OBJECT(var)
/**
* @brief 参数为布尔值
* @param var 布尔值变量
*/
#define paramBool(var) Z_PARAM_BOOL(var)
// 未定义参数类型
#define isUndef IS_UNDEF
// 参数为null类型
#define isNull IS_NULL
// 参数为false类型
#define isFalse IS_FALSE
// 参数为true类型
#define isTrue IS_TRUE
// 参数为整数类型
#define isInt IS_LONG
// 参数为浮点数类型
#define isFloat IS_DOUBLE
// 参数为字符串类型
#define isStr IS_STRING
// 参数为数组类型
#define isArr IS_ARRAY
// 参数为对象类型
#define isObj IS_OBJECT
// 参数为资源类型
#define isRes IS_RESOURCE
// 参数为文献类型
#define isRef IS_REFERENCE
// 参数为常量表达式类型
#define isConstantAst IS_CONSTANT_AST
// 参数为可调用类型
#define isCallable IS_CALLABLE
// 参数为可迭代类型
#define isIterable IS_ITERABLE
// 参数为void类型
#define isVoid IS_VOID
// 参数为静态类型
#define isStatic IS_STATIC
// 参数为间接类型
#define isIndirect IS_INDIRECT
// 参数为指针类型
#define isPtr IS_PTR
// 参数为别名指针类型
#define isAliasPtr IS_ALIAS_PTR
// 参数为布尔值类型
#define isBool _IS_BOOL
// 参数为数字类型
#define isNumber IS_NUMBER
// ----------------------定义参数解析----------------------
// ----------------------定义返回值----------------------
/**
* @brief 返回字符串
* @param str php字符串
*/
#define returnStr(str) RETURN_STR(str)
/**
* @brief 返回布尔值
* @param bool 布尔值
*/
#define returnBool(bool) RETURN_BOOL(bool)
/**
* @brief 返回 NULL
*
*/
#define returnNull() RETURN_NULL()
/**
* @brief 返回整数
* @param int 整数
*/
#define returnInt(int) RETURN_LONG(int)
/**
* @brief 返回浮点数
* @param double 浮点数
*/
#define returnFloat(double) RETURN_DOUBLE(double)
// ----------------------定义返回值----------------------
#endif /* HELP_H_H */
后续会慢慢完善笔记