内置函数在底层 C 的注册流程,按最实用顺序就是这 8 步:

  1. 写函数实现                                                                                                           2. 写参数签名 arginfo
  3. 写函数注册表 zend_function_entry[]                                                                                   4. 写模块入口 zend_module_entry
  5. 在 config.m4 声明扩展
  6. PHP_NEW_EXTENSION(..., $ext_shared) 支持静态/动态
  7. ./configure --enable-hp(静态内置)或 --enable-hp=shared(so)
  8. 编译后用 php -m、function_exists() 验证

  下面给你最小完整模板。

  ---
  1) 函数实现(C)

  PHP_FUNCTION(hp_hello)
  {
      RETURN_STRING("hello hp");
  }

  ---
  2) 参数信息(arginfo)

  ZEND_BEGIN_ARG_INFO_EX(arginfo_hp_hello, 0, 0, 0)
  ZEND_END_ARG_INFO()

  如果有参数,比如 hp_add(int $a, int $b):

  ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_hp_add, 0, 2, IS_LONG, 0)
      ZEND_ARG_TYPE_INFO(0, a, IS_LONG, 0)
      ZEND_ARG_TYPE_INFO(0, b, IS_LONG, 0)
  ZEND_END_ARG_INFO()

  ---
  3) 函数注册表(关键)

  static const zend_function_entry hp_functions[] = {
      PHP_FE(hp_hello, arginfo_hp_hello)
      // PHP_FE(hp_add, arginfo_hp_add)
      PHP_FE_END
  };

  PHP_FE 就是把 “PHP 函数名 -> C 函数指针 + 参数签名” 绑定进 Zend 函数表。

  ---
  4) 模块入口(关键)

  zend_module_entry hp_module_entry = {
      STANDARD_MODULE_HEADER,
      "hp",              // 扩展名
      hp_functions,      // 注册函数表
      PHP_MINIT(hp),     // 模块初始化
      NULL,              // MSHUTDOWN
      NULL,              // RINIT
      NULL,              // RSHUTDOWN
      PHP_MINFO(hp),     // phpinfo
      "1.0.0",
      STANDARD_MODULE_PROPERTIES
  };

  #ifdef COMPILE_DL_HP
  ZEND_GET_MODULE(hp)
  #endif

  MINIT 负责模块级初始化(类注册、常量注册、INI 注册等)。

  ---
  5) config.m4(构建入口)

  PHP_ARG_ENABLE(hp, whether to enable hp extension,
  [  --enable-hp           Enable hp extension], no)

  if test "$PHP_HP" != "no"; then
    PHP_NEW_EXTENSION(hp, hp.c, $ext_shared)
  fi

  ---
  6) 完整最小 hp.c 示例

  #ifdef HAVE_CONFIG_H
  #include "config.h"
  #endif

  #include "php.h"
  #include "ext/standard/info.h"

  PHP_FUNCTION(hp_hello)
  {
      RETURN_STRING("hello hp");
  }

  ZEND_BEGIN_ARG_INFO_EX(arginfo_hp_hello, 0, 0, 0)
  ZEND_END_ARG_INFO()

  static const zend_function_entry hp_functions[] = {
      PHP_FE(hp_hello, arginfo_hp_hello)
      PHP_FE_END
  };

  PHP_MINIT_FUNCTION(hp)
  {
      return SUCCESS;
  }

  PHP_MINFO_FUNCTION(hp)
  {
      php_info_print_table_start();
      php_info_print_table_row(2, "hp support", "enabled");
      php_info_print_table_end();
  }

  zend_module_entry hp_module_entry = {
      STANDARD_MODULE_HEADER,
      "hp",
      hp_functions,
      PHP_MINIT(hp),
      NULL,
      NULL,
      NULL,
      PHP_MINFO(hp),
      "1.0.0",
      STANDARD_MODULE_PROPERTIES
  };

  #ifdef COMPILE_DL_HP
  ZEND_GET_MODULE(hp)
  #endif

  ---
  7) 编译方式

  静态内置(进 PHP 二进制):
  ./buildconf --force
  ./configure --enable-hp ...
  make -j"$(nproc)"
  make install

  动态 so:
  phpize
  ./configure --enable-hp=shared
  make -j"$(nproc)"
  make install

  ---
  8) 验证

  php -m | grep -i hp
  php -r 'var_dump(function_exists("hp_hello")); echo hp_hello(), PHP_EOL;'

  ---
  一句话记忆版:
  真正“注册”发生在 hp_functions 挂到 zend_module_entry 这一步,Zend 在模块加载时把这张表塞进全局函数表,PHP
  层就能直接调用了。

更多推荐