php 拓展开发 笔记

KingBes

简单来说,PHPER 学 PHP 扩展开发核心就四点:

  1. 提性能:突破 PHP 解释执行的瓶颈,高频计算 / 数据处理等核心逻辑能提速数倍甚至数十倍;
  2. 补能力:实现纯 PHP 做不到的底层操作(如系统 / 硬件交互、自定义语法 / 加密等);
  3. 优架构:封装核心逻辑复用,隔离高危操作,提升系统稳定性;
  4. 涨竞争力:从单纯的业务 CURD 开发者,升级为能触及 PHP 内核的中高级开发者 / 架构师,技术壁垒更高。
    如果只是常规 Web 开发(CURD),可能用不上;但想解决性能瓶颈、拓展 PHP 能力边界,或往高阶方向发展,这是必备技能。

windows 开发环境

准备工作

  1. php源码
  2. php开发工具
  3. php编译SDK工具
  4. vs 17 2022(版本根据php的要求)(自己找教程 搭建msvc环境)
  5. 对应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 */

后续会慢慢完善笔记

109 0 0
0个评论

KingBes

2030
积分
0
获赞数
0
粉丝数
2023-06-12 加入
🔝