使用PHP源代码库进行分支并从源代码构建PHP
简述
为了回顾学习 PHP 的构建方法、git 命令以及 PHP 源码的努力,我写下了这篇文章。当我提供补丁或提出改进意见给 github 上的 php-src 时,为了保持代码库的维护,随着时间的推移,我需要合并 fork 的 php-src 的更新。
注册错误报告和功能请求
您可以从此页面注册。在注册页面之后,您可以在Github上添加公开的拉取请求。
引入PHP的构建工具
在后续的 ./configure 阶段中,会显示所缺少的工具,您只需逐个安装即可。对于 Ubuntu,有一系列的命令可用于安装构建工具。
sudo apt-get build-dep php7
编译 PHP
因为我的GitHub账号名字是masakielastic,所以克隆仓库的命令为:如果使用./configure选项,指定–enable-debug –enable-maintainer-zt并进行构建,脚本执行时将会检测到内存泄漏。由于不想在系统中安装,所以将安装路径设置为源代码目录内。
git clone git@github.com:masakielastic/php-src.git
cd php-src
./buildconf
./configure --enable-debug --enable-maintainer-zts --prefix=`pwd`/local
让我们建筑起来。
make
即使不安装,也可通过以下路径使用命令工具。
sapi/cli/php -v
进行安装操作时,请执行以下命令:
执行 make install
让我们确认安装的命令工具位置。
local/bin/php -v
处理一次性筷子。
创建一个只包含最新记录的代码仓库。
使用 `–depth` 选项来创建浅克隆。
git clone https://github.com/php/php-src.git --branch master --depth=1
更新浅克隆
在浅层存储库中,当执行git fetch时,它会拒绝要求更新.git/shallow目录中的引用,所以需要指定以下选项。
git pull --update-shallow
将浅克隆转换为完全克隆。
浅层克隆无法在执行git pull时自动合并。为了更新,需要将浅层克隆转换为完整克隆。
git pull --unshallow
克隆独立的分支
通过克隆独立的分支来节省下载时间,而不是进行浅层克隆。如果指定了 –depth 选项,则默认会添加 –single-branch 选项。
git clone https://github.com/php/php-src.git --branch master --single-branch
仓库管理
注册上游分支
显示已注册的分支列表。
git remote -v
让我们注册作为顶级分支的 php/php-src。
git remote add upstream git@github.com:php/php-src.git
让我们确认一下是否已注册。
检查和切换分支
让我们确认一下工作中的分支。 de .)
git branch
让我们切换到想要操作的分支进行作业。
git checkout master
创建和删除本地分支
我们来创建一个新的本地分支。
git branch hello_world
你也可以同时创建并切换到工作分支。
git checkout -b hello_world
执行以下命令来删除分支。但是,无法删除正在进行中的分支,您需要切换到另一个分支。
git branch -d hello_world
要删除远程分支,请指定 –delete 选项。
git push origin --delete hello_world
追随上游的变更
获取上游的更改。
git fetch upstream
将上游的更改合并。
git merge upstream/master
让我们将更改同步到 Github 的远程分支(origin)。
git push origin master
要想更新自己创建的分支,需要使用 rebase。
git checkout my_branch
git rebase upstream/master
git push --force-with-lease origin my_branch
请查看以下的文章,了解为什么–force-with-lease比–force更可取的原因。
如果遇到无法构建的版本,在可构建的版本上执行rebase操作。
git rebase --onto <new-parent> <old-parent>
模块开发
构建扩展模块
让我们构建mbstring吧。
cd ext/mbstring
../../local/bin/phpize
./configure
请用文本编辑器打开 Makefile,并修改 prefix 和 EXTENSION_DIR 等内容。在我的环境中,它们的值分别是 /Users/masakielastic/test/php-src/local 和 /Users/masakielastic/test/php-src/local/lib/php/extensions/no-debug-non-zts-20141001。
在完成修正作业后,请进行编译并执行测试。
make
make test
从命令行加载扩展模块。
已经构建的模块位于 modules 文件夹中。要通过命令行加载模块,可以使用 -dextension 选项来指定路径。
php -dextension=modules/mbstring.so test.php
限定考试范围
如果想要限定考试范围,可以按照以下方式指定目录。
make test TESTS=ext/standard/tests/strings
生成扩展模块的模板
执行 ext/ext_skel 命令。
cd /path/to/ext
./ext_skel --extname=helloworld
cd helloworld
解除 config.m4 中接下来的三行注释。
PHP_ARG_WITH(helloworld, for helloworld support,
Make sure that the comment is aligned:
[ --with-helloworld Include helloworld support])
通过常规命令,您可以构建剩余的部分。如前所述,您需要修改 Makefile 中的前缀和 EXTENSION_DIR。
../../local/bin/phpize
./configure
make
让我们尝试执行已注册的 confirm_helloworld_compiled 函数作为示例。
var_dump(
confirm_helloworld_compiled(str_repeat('1234567890', 100))
);
确认confirm_helloworld_compiled是这样定义的:使用zend_parse_parameters函数进行参数解析,并使用类似RETURN_STRINGL的宏来指定返回值。只要理解了这些,就足够了。
PHP_FUNCTION(confirm_helloworld_compiled)
{
char *arg = NULL;
int arg_len, len;
char *strg;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arg_len) == FAILURE) {
return;
}
len = spprintf(&strg, 0, "Congratulations! You have successfully modified ext/%.78s/config.m4. Module %.78s is now compiled into PHP.", "helloworld", arg);
RETURN_STRINGL(strg, len, 0);
}
我们现在来注册一个名为helloworld的函数。
PHP_FUNCTION(helloworld);
const zend_function_entry helloworld_functions[] = {
PHP_FE(confirm_helloworld_compiled, NULL) /* For testing, remove later. */
PHP_FE(helloworld, NULL)
PHP_FE_END /* Must be the last line in helloworld_functions[] */
};
PHP_FUNCTION(helloworld)
{
printf("Hello, World!\n");
return;
}
学习PHP源代码应该怎么做呢?
阅读使用ext/ext_skel命令生成的扩展模块、标准字符串和数组函数的定义会很有帮助。同时,也需要回想起自己作为PHP初学者时是如何学习概念的,并进行反思。
即使一开始完全不理解,也要养成定期阅读相关函数和类的定义的习惯。对于不清楚如何使用的内部函数,可以在GitHub上搜索并查找用例。
在nikic先生的文章中,有关于标准函数的命名方式,例如strlen。由于strlen的宏定义中使用了ZEND_FUNCTION,所以如果不了解,很难找到。
如果是在扩展模块上,cURL 是容易学习的。虽然有 PHP 内部书籍作为全面的文档,但最开始阅读可能难以理解。
你可以在网上阅读旧版的奥莱利《Programming PHP》。这本书对于查找内存管理函数、函数参数(zend_parse_parameters)和返回值选项非常有用。如果你还想要纸质书籍,可以考虑购买《扩展和嵌入 PHP》(2006年)这本书。
需要学习适应PHP 7.0。引入了快速参数解析API,并且正在逐步替换zend_parse_parameters。此外,还有一篇关于从PHP 5升级到PHP 7的内部升级总结文章。
有关字符串操作方面,引入了zend_string API。此外,还引入了smart_string API以取代smart_str API。