php扩展开发-使用 C 语言编写高性能 PHP 扩展的底层编译与调用(入门)
前提
掌握C,php,Linux,php扩展开发,编译,php-devel安装
which -a php php-config phpize我这个是lnmp安装包安装的,其实是有php-config的
ln -s /usr/local/php/bin/php-config /usr/bin/php-config或者
echo 'export PATH=/usr/local/php/bin:$PATH' >> ~/.bashrc
source ~/.bashrc重新执行
which -a php php-config phpize以php8.3为例,开发一个php扩展
创建一个php_ext目录
mkdir -p /root/php_ext下载php源码
wget https://www.php.net/distributions/php-8.3.7.tar.gz解压
tar -zxvf php-8.3.7.tar.gzcd /root/php-8.3.7/ext可以看到有一个ext_skel.php
提示
ext_skel.php 是 php 扩展开发的脚手架工具,用于快速生成扩展开发的基本框架。要在这个目录下执行命令
php ext_skel.php --ext youhujun --dir /root/php_ext命令含义:
--ext youhujun 定义扩展模块名称为 youhujun
--dir /root/php_ext 将生成的完整扩展工程,输出到 /root/php_ext 目录

进入目录
cd /root/php_ext/youhujunyouhujun/
├── .gitignore
├── config.m4 # Linux编译的autoconf配置(最重要!)
├── config.w32 # Windows下编译扩展的配置文件
├── youhujun.c # 【核心C源码,扩展业务写这里】
├── php_youhujun.h # 头文件,模块声明
├── youhujun_arginfo.h # 函数参数元信息,用于PHP反射、IDE提示(PHP8新增!)
├── youhujun.stub.php # # 【函数签名声明源】用 PHP 语法声明对外函数;gen_stub.php 据此生成
└── tests/ # phpt自动化测试用例目录
youhujun.stub.php # 【函数签名声明源】扩展对外暴露的 PHP 函数在这里声明(只有签名,没有实现)
# ├─ 主线:build/gen_stub.php 解析它 → 生成 youhujun_arginfo.h(内核据此解析参数/类型检查/反射)
# ├─ 副线:IDE、静态分析靠它获得代码提示(.so 是二进制,IDE 读不了)
# └─ 铁证:arginfo.h 首行写着 "This is a generated file, edit the .stub.php file instead."

💡重点:*.stub.php 和 *_arginfo.h 这两个是 PHP8 之后才新增!老 PHP7/5 脚手架没有!
作用:给 IDE 提供函数的类型提示,内核里面读取参数信息,这是新版扩展开发很关键的点。
phpize./configure --with-php-config=/usr/bin/php-config在工作区下创建.vscode然后创建一个c_cpp_properties.json内容如下:
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**",
"${workspaceFolder}/youhujun",
"/usr/local/php/include/php",
"/usr/local/php/include/php/main",
"/usr/local/php/include/php/Zend",
"/usr/local/php/include/php/TSRM",
"/usr/local/php/include/php/ext",
"/usr/local/php/include/php/ext/date/lib"
],
"defines": [
"HAVE_CONFIG_H"
],
"cStandard": "c11",
"intelliSenseMode": "linux-gcc-x64"
}
],
"version": 4
}接下来修改youhujun.stub.php
<?php
/**
* @generate-class-entries
* @undocumentable
*/
function yh_p(mixed $param): void {}之后
php build/gen_stub.php youhujun.stub.php自动下载
如果下载失败,就自己手动下载,这里我下载的是5.4.0
tar -zxvf PHP-Parser-v5.4.0.tar.gz提示
注意必须是PHP-Parser-5.0.0,这个是因为gen_stub.php的代码决定的
mv PHP-Parser-v5.4.0 /root/php_ext/youhujun/build/PHP-Parser-5.0.0ls /root/php_ext/youhujun/build/PHP-Parser-5.0.0/lib/PhpParser/
重新
php build/gen_stub.php youhujun.stub.php- LNMP 的 php.ini 默认 display_errors=Off,Fatal error 被写进 /var/log/php/error.log
- gen_stub.php 需要 passthru() 自动下载 PHP-Parser,但 LNMP 默认禁用了它
- 解决:php -d disable_functions= build/gen_stub.php youhujun.stub.php
显示:# Saved youhujun_arginfo.h
接着修改youhujun.c
/* youhujun extension for PHP */
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "php.h"
#include "ext/standard/info.h"
#include "php_youhujun.h"
#include "youhujun_arginfo.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_FUNCTION(yh_p)
{
zval *param;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_ZVAL(param)
ZEND_PARSE_PARAMETERS_END();
php_printf("<pre>");
zend_print_zval_r(param, 0);
php_printf("</pre>");
}
/* {{{ PHP_RINIT_FUNCTION */
PHP_RINIT_FUNCTION(youhujun)
{
#if defined(ZTS) && defined(COMPILE_DL_YOUHUJUN)
ZEND_TSRMLS_CACHE_UPDATE();
#endif
return SUCCESS;
}
/* }}} */
/* {{{ PHP_MINFO_FUNCTION */
PHP_MINFO_FUNCTION(youhujun)
{
php_info_print_table_start();
php_info_print_table_row(2, "youhujun support", "enabled");
php_info_print_table_end();
}
/* }}} */
/* {{{ youhujun_module_entry */
zend_module_entry youhujun_module_entry = {
STANDARD_MODULE_HEADER,
"youhujun", /* Extension name */
ext_functions, /* zend_function_entry */
NULL, /* PHP_MINIT - Module initialization */
NULL, /* PHP_MSHUTDOWN - Module shutdown */
PHP_RINIT(youhujun), /* PHP_RINIT - Request initialization */
NULL, /* PHP_RSHUTDOWN - Request shutdown */
PHP_MINFO(youhujun), /* PHP_MINFO - Module info */
PHP_YOUHUJUN_VERSION, /* Version */
STANDARD_MODULE_PROPERTIES
};
/* }}} */
#ifdef COMPILE_DL_YOUHUJUN
# ifdef ZTS
ZEND_TSRMLS_CACHE_DEFINE()
# endif
ZEND_GET_MODULE(youhujun)
#endif之后
make确认扩展本身能不能加载
php -d extension=modules/youhujun.so -m | grep youhujun可以看到已经有了youhujun
php -d extension=modules/youhujun.so -r "yh_p('游鹄君');"可以看到已经输出了<pre>游鹄君</pre>
之后就可以在php.ini中添加youhujun.so扩展了
