深入理解PHP之源码目录结构与功能说明
说明
本文将详细讲解PHP源码目录结构以及其中各个子目录的作用,帮助读者深入理解PHP的内部结构,从而更好地学习和使用PHP。
源码目录结构
PHP源码目录结构主要分为以下几个部分:
- build:构建PHP的脚本和辅助工具;
- ext:PHP的扩展库;
- main:PHP的主要源代码,包括Zend引擎、内部函数和类库等;
- sapi:PHP的SAPI接口,用于与Web服务器等程序进行交互;
- TSRM:线程安全相关代码;
- Zend:Zend引擎的源代码。
以下是具体的目录结构及其功能:
├── build // 构建PHP的脚本和辅助工具
├── ext // PHP的扩展库
│ ├── bcmath
│ ├── ...
│ └── zip
├── main // PHP的主要源代码
│ ├── output.c // PHP输出相关代码,处理echo、print等输出语句
│ ├── php.h // PHP的主要头文件,定义了一些常量和类型等
│ ├── php.ini-development // PHP开发版本的配置文件
│ ├── php.ini-production // PHP生产版本的配置文件
│ ├── php.ini-production.cli // PHP使用命令行运行时生产版本的配置文件
│ ├── php.ini-recommended // 推荐的PHP配置文件
│ ├── php_stdlib.h // PHP标准库头文件
│ ├── SAPI.h // PHP的SAPI接口头文件
│ ├── sapi_server.h // PHP的Web服务器SAPI接口头文件
│ ├── sapi_cli.h // PHP的命令行SAPI接口头文件
│ ├── zend_API.h // Zend引擎的API接口头文件
│ ├── zend_compile.h // Zend编译相关头文件
│ ├── zend_execute.h // Zend执行相关头文件
│ ├── zend_hash.h // Zend哈希表头文件
│ ├── zend_ini.h // Zend配置文件读取头文件
│ ├── zend_language_parser.h // Zend语言解析器头文件
│ ├── zend_mmap.h // Zend内存映射相关头文件
│ └── zend_operators.h // Zend操作符相关头文件
├── sapi // PHP的SAPI接口,用于与Web服务器等程序进行交互
│ ├── apache2handler // Apache2 SAPI接口相关代码
│ ├── cli // 命令行SAPI接口相关代码
│ ├── fpm // PHP FastCGI进程管理器相关代码
│ ├── litespeed // LiteSpeed SAPI接口相关代码
│ ├── phpdbg // PHP调试器SAPI接口相关代码
│ └── embed // PHP嵌入其他程序的SAPI接口相关代码
├── TSRM // 线程安全相关代码
└── Zend // Zend引擎的源代码
├── zend_API.c // Zend引擎的API接口代码
├── zend_compile.c // Zend编译相关代码
├── zend_execute.c // Zend执行相关代码
├── zend_hash.c // Zend哈希表相关代码
├── zend_ini.c // Zend配置文件读取相关代码
├── zend_language_parser.c // Zend语言解析器相关代码
├── zend_list.c // Zend列表相关代码
├── zend_mmap.c // Zend内存映射相关代码
├── zend_operators.c // Zend操作符相关代码
└── zend_variables.c // Zend变量相关代码
示例-1: 自定义PHP扩展
通过PHP的扩展库,我们可以为PHP添加自定义的功能。下面是一个简单的示例:自定义一个PHP函数,用于计算斐波那契数列:
- 首先在ext目录下创建一个新的目录,命名为
fibonacci
,并创建config.m4
文件:
PHP_ARG_ENABLE(fibonacci, whether to enable Fibonacci function,
[ --enable-fibonacci
Enable Fibonacci support])
if test $PHP_FIBONACCI != "no"; then
PHP_SUBST(FIBONACCI_SHARED_LIBADD)
PHP_NEW_EXTENSION(fibonacci, fibonacci.c, $ext_shared)
fi
- 创建
fibonacci.c
文件,写入以下代码:
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
PHP_FUNCTION(fibonacci)
{
long n, i, t1 = 0, t2 = 1, next_term;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &n) == FAILURE) {
return;
}
for (i = 0; i < n; i++) {
if (i <= 1) {
next_term = i;
} else {
next_term = t1 + t2;
t1 = t2;
t2 = next_term;
}
}
RETURN_LONG(next_term);
}
static zend_function_entry fibonacci_functions[] = {
PHP_FE(fibonacci, NULL)
{NULL, NULL, NULL}
};
zend_module_entry fibonacci_module_entry = {
STANDARD_MODULE_HEADER,
"fibonacci",
fibonacci_functions,
NULL,
NULL,
NULL,
NULL,
NULL,
"1.0",
STANDARD_MODULE_PROPERTIES
};
ZEND_GET_MODULE(fibonacci)
- 在PHP源码根目录执行以下命令进行编译:
./buildconf
./configure --enable-fibonacci
make
sudo make install
- 在PHP中调用该函数:
echo fibonacci(10); // 输出55
示例-2: 自定义PHP SAPI接口
通过PHP的SAPI接口,我们可以自定义PHP与Web服务器等程序的交互方式。下面是一个简单的示例:自定义一个PHP SAPI接口,以HTTP GET方式获取参数并输出Hello, xxx!:
- 在sapi目录下创建一个新的目录,命名为
custom
,并创建Makefile.frag
文件:
SAPI = $(top_builddir)/sapi/custom/php
CC = gcc
CFLAGS = -I. -I$(top_srcdir)/Zend -I$(top_srcdir)/main \
-I$(top_srcdir)/sapi -I$(top_srcdir) \
$(EXTRA_INCLUDES)
LDFLAGS = -export-dynamic $(EXTRA_LDFLAGS)
EXTRA_INCLUDES =
EXTRA_LDFLAGS =
OBJS = custom.o \
$(top_builddir)/Zend/zend_alloc.o \
$(top_builddir)/Zend/zend_buildenv.o \
$(top_builddir)/Zend/zend_builtin_functions.o \
$(top_builddir)/Zend/zend_execute.o \
$(top_builddir)/Zend/zend_globals.o \
$(top_builddir)/Zend/zend_hash.o \
$(top_builddir)/Zend/zend_indent.o \
$(top_builddir)/Zend/zend_language_parser.o \
$(top_builddir)/Zend/zend_list.o \
$(top_builddir)/Zend/zend_opcode.o \
$(top_builddir)/Zend/zend_operators.o \
$(top_builddir)/Zend/zend_ptr_stack.o \
$(top_builddir)/Zend/zend_stack.o \
$(top_builddir)/Zend/zend_variables.o \
$(top_builddir)/main/php_open_temporary_file.o \
$(top_builddir)/main/php_logos.o
all: $(SAPI)
$(SAPI): $(OBJS)
$(CC) $(LDFLAGS) -o $@ $(OBJS)
clean:
rm -f $(SAPI) $(OBJS)
- 创建
custom.c
文件,写入以下代码:
#include "php.h"
#include "SAPI.h"
#include "zend_API.h"
static sapi_module_struct custom_module = {
"custom", // name
"Custom PHP Module", // pretty name
php_uname('s'), // php.sapi_name
NULL, // startup
NULL, // shutdown
NULL, // activate
NULL, // deactivate
NULL, // message_handler
NULL, // phpinfo
"1.0", // version
NULL, // globals_ctor
NULL, // globals_dtor
NULL, // post_startup
NULL, // child_terminate
STANDARD_SAPI_MODULE_PROPERTIES
};
static PHP_FUNCTION(hello)
{
char *name;
size_t name_len;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name, &name_len) == FAILURE) {
return;
}
php_printf("Hello, %s!", name);
}
static zend_function_entry custom_functions[] = {
PHP_FE(hello, NULL)
{NULL, NULL, NULL}
};
zend_module_entry custom_module_entry = {
STANDARD_MODULE_HEADER,
"custom",
custom_functions,
NULL,
NULL,
NULL,
NULL,
NULL,
"1.0",
STANDARD_MODULE_PROPERTIES
};
void _custom_module_startup(sapi_module_struct *sapi_module)
{
sapi_module->php_ini_path_override = NULL;
}
static int custom_module_startup(sapi_module_struct *sapi_module)
{
_custom_module_startup(sapi_module);
return zend_startup_module(&custom_module_entry);
}
#ifdef COMPILE_DL_CUSTOM
ZEND_GET_MODULE(custom)
#endif
int main(int argc, char *argv[])
{
sapi_startup(&custom_module);
if (php_module_startup(&custom_module, NULL, 0) == FAILURE) {
return 1;
}
php_output_activate(NULL, NULL);
PHP_EMBED_MAIN_BEGIN();
php_printf("Content-type: text/html\r\n\r\n");
zend_execute_scripts(ZEND_REQUIRE, NULL, 1, "hello.php");
PHP_EMBED_MAIN_END();
return 0;
}
- 在PHP源码根目录执行以下命令进行编译:
cd sapi/custom
make
- 在sapi目录创建
custom_server.php
文件,写入以下代码:
<?php
$request_uri = $_SERVER['REQUEST_URI'];
parse_str(parse_url($request_uri, PHP_URL_QUERY), $params);
$name = $params['name'] ?? 'World';
echo hello($name);
- 进入PHP源码目录,执行以下命令启动自定义SAPI服务:
sapi/custom/php -S localhost:8000 -t sapi/custom sapi/custom_server.php
- 在浏览器访问
http://localhost:8000/?name=PHP
,可以看到输出Hello, PHP!。
总结
通过以上两个示例,我们可以了解PHP源码的目录结构和各个子目录的作用,并了解如何利用PHP扩展库和SAPI接口进行自定义开发。同时也可以为读者带来更好的学习和使用PHP的体验。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:深入理解PHP之源码目录结构与功能说明 - Python技术站