[译] 给PHP开发者的PHP源码-第一部分-源码结构

文章来自:http://www.hoohack.me/2016/02/04/phps-source-code-for-php-developers-chphp

原文:http://blog.ircmaxell.com/2012/03/phps-source-code-for-php-developers.htmlhtml

做为一个开发者,我发如今个人平常工做中愈来愈多地查看PHP的源码。在为了弄清楚奇怪的边界问题和为何某些问题应该发生的却没有发生而去理解背后究竟发生了什么事情的时候很是有用。在文档缺失、不完整或者错误的状况下也颇有用。所以,我已经决定经过一系列的文章来分享我学到的知识,给予PHP开发者们足够的知识去真正阅读PHP的C语言源码。你并不须要有C语言的基础(咱们会总结一些基础),但若是有的话会更有帮助。mysql

这是这个系列的第一篇文章。在这篇文章,咱们会谈论PHP程序的基础:在哪里找到它,基本的代码结构和一些最基础的C语言概念。须要说明的是,这一系列文章的目标是得到源码的阅读理解能力。这意味着为了过一下某些点,某些概念会被简化而不是太复杂的描述。这不会给阅读形成明显的差别,但若是你想为源码作贡献,则还有更多的知识须要补充。在我作简化的时候,我会尽可能指出这些简化。sql

另外,这系列文章是基于5.4版本的源码,在不一样版本中,大部分概念都是同样的,但这里,咱们须要针对此次的文章有一个版本的定义(为了让新的版本出来后接下来的文章更容易地遵循)。数组

那么,咱们能够开始了吧?svn

在哪里找到PHP的源码

下载PHP源码最简单的方式是经过PHP的SVN仓库。对于这此文章,咱们检出(check out)了5.4的分支。这对于成为PHP的前沿或者真正的开发PHP(解决bugs,实现特性等等)来讲是很是棒的。值得注意的是,PHP社区正在(这篇文章正在写的时候)将源码迁移到GIT仓库中。一旦迁移完成,我会更新这篇文章以达到标准。(译者注:译者翻译的时候PHP已经迁移到GIT仓库了)。函数

事实上,下载源码对咱们的目的来讲并非真正的有用。咱们不想编辑它,咱们只是想使用它和跟踪它是如何运行的。咱们能够下载它,而后导入到一个好的IDE中,在这些IDE中咱们能够点击跳到函数的定义和声明,当我发现这比想象中略困难。我有一个更好的解决方案。工具

事实证实,PHP社区在维护一个对于咱们来讲一个很是好的工具。那就是lxr.php.net。这主要是一个自动生成可搜索的源码列表,并且有语法高亮和函数所有有连接的。这个是我几乎只用来浏览C源码的工具,实在太棒(即便在我写补丁的时候,我依然到lxr而不是我正在开发的代码库)。咱们还不会讲到如何作更有效的搜索,但咱们会在谈论PHP核心函数的时候讲到。优化

从这里开始,咱们将开始谈论PHP5.4。为了达到这目的,咱们会使用这个lxr连接做为其余文章的基础。当我提到“5.4的根目录”的时候,我就是说这个页面。操作系统

那么,既然咱们能够查看源码目录了,那么咱们来谈谈这里面都有什么吧。

PHP源码结构

那么,当你查看列在5.4的根目录的文件和目录时,还有不少能够研究。我但愿你只关注两个目录:extZend。其余的文件和目录对于PHP扩展和开发来讲很重要,但对于咱们的目的来讲,咱们彻底能够忽略它们。那么,为何这两个目录那么重要呢?

PHP程序被分为,你猜对了,两个主要的部分。第一部分是Zend引擎,控制PHP代码运行时候的运行环境。它处理PHP提供的全部“语言层”的特性,包括:变量,表达式,语法解析,代码执行和错误处理。没有这个引擎,就没有PHP。引擎的源码放在了Zend目录。

PHP第二个核心的部分,是包含在PHP里面的扩展。这些扩展包括咱们能够在PHP调用的每个核心函数(例如strpos,substr,array_diff,mysql_connect等等)。也包括核心的类(MySQLi,SplFixedArray,PDO等等)。

在核心代码中,决定在哪里找到你想查看的功能最简单的方法是,查看PHP的文档首页。PHP的文档也被分为两个主要的部分(为了达到咱们的目的),语言参考函数参考。做为一个庞大的归纳,若是你想查看的是在语言参考中的定义,颇有可能能够在Zend文件夹找到。若是是在函数参考中,能够在ext文件夹中找到。

一些基本的C语言概念

这部分不是为了成为C的入门,而是一个“读者的配套指南”。有以下概念:

变量

在C里面,变量是静态和强类型的。这意味着变量必需要使用一个类型定义以后才能使用。一旦定义以后,你不能改变它的类型(你能够在以后转换成其余类型,但你须要使用不一样的变量来实现)。由于,在C语言里面,变量并不真实地存在。它们只是为了咱们使用的方便的内存地址的标签。正由于如此,C语言没有PHP中的引用。取而代之,它有指针。为了咱们的目的,把指针想象成指向其余变量的变量。把它看成PHP中变量的变量。

那么,经过上面的描述,咱们来谈论一下变量的语法。C语言没有使用任何的前缀来标识变量。所以,要说出它们的不一样的惟一方式(为了达到咱们的目的)是查看它们的定义。若是你在函数的顶部(或者函数的声明)看到在类型和空格以后的字符,那就是变量。一个要说明的关键点是变量名前面能够有一个或这多个符号。星号(*)代表变量是指向某个类型的指针(一个引用)。两个星号代表变量是指向指针的指针。三个星号代表变量是指向一个指向其余指针的指针。

这个间接寻址很是重要,由于PHP内部使用不少的双层指针。这是由于引擎须要可以传递块数据(PHP变量),和全部有趣的类型如PHP引用,写时复制以及对象引用等等。所以,只要意识到**ptr意味着咱们正使用两层的引用(不是变量的引用,而是一个数据引用的引用)。这又一点迷惑,但若是引用对你来讲是彻底新的知识,我建议你阅读一下这方面的知识(尽管咱们的目的是不用必需阅读C)。会有帮助的。

如今,另外一个理解指针的事情是它们是如何在C的数组里应用的(不是PHP的数组,而是C语言中的数组)。由于指针是内存地址,咱们能够经过分配一块的内存来定义一个数组,而后经过递增指针来遍历它。正常状况下,咱们可使用表明一个字符(8位)的C的数据类型char来存储字符串中的一个字符。但咱们也能够像使用数组那样使用它来访问字符串后面的字节。所以,咱们能够只在第一个字节里存储一个指针而不是存储正一个字符串在变量中。而后,咱们能够递增指针(增长它的内存地址)来遍历整个字符串。

char *foo = "test";
// foo 是指向"t"在内存的片断保存"test"的指针
// 要访问"e",咱们能够经过下面的方式:
char e = foo[1];
char e = *(foo + 1);
char e = *(++foo);

要另外阅读C语言重点的变量和指针,查看这本很好的免费书籍

预处理说明

C在编译以前使用一步叫作“预处理”的步骤。这一步包含优化和根据你传递给编译器的选项动态使用部分代码。咱们将谈论两个主要的预处理器说明:条件语句和宏。

条件语句容许代码在编译输出或者不是基于定义时被引入。这看起来很像下面的例子。这容许不一样的代码根据不一样的操做系统被使用(所以尽管它们使用不一样的API,也能够在Windows和Linux中很好的使用)。另外,它容许一部分代码被引入或者不是基于定义的指示。事实上,这是配置步骤中如何编译PHP的执行过程。

#define FOO 1
#if FOO
Foo is defined and not 0
#else
Foo is not defined or is 0
#endif
#ifdef FOO
Foo is defined
#else
Foo is not defined
#endif

另外一个说明我叫它作宏。这是最简单简化代码的迷你函数。它们不是真正的函数,可是在编译预处理是会执行简单的文本替换。所以,宏不会真正地调用函数。你能够为函数定义写一个宏(事实上,PHP就是这么作的,但咱们会在后面的文章中深刻了解这个)。我想说的是,宏容许在预处理编译时使用更简单的代码。

#define FOO(a) ((a) + 1)
int b = FOO(1); // Converted to int b = 1 + 1

源文件

最后这一部分,咱们须要了解的是两种在C源码使用的类型的文件。主要有两种文件:.c.h.c文件是包含了源码准备编译的文件。一般来讲,.c文件包含了不能分享到其余文件的私有函数的实现。.h(或者说头文件)定义了在.c文件中能够被其余文件看到的函数,包括预处理宏。头文件定义公共API的方式,是经过不使用函数体从新声明函数的签名(跟PHP中的接口和抽象方法类似)。这样,源码就能够经过头文件连接在一块儿了。

下一部分

这个系列的下一部分文章,咱们即将讨论内部函数在C里面是怎么定义的。所以你能够跳到任意的内部函数(好比strlen)查看它的定义和它是如何工做的。保持这个节奏。

相关文章
相关标签/搜索