使用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。

广告
将在 10 秒后关闭
bannerAds