专栏首页PHP在线给PHP开发者讲讲PHP源码-第一部分

给PHP开发者讲讲PHP源码-第一部分

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

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

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

那么,我们可以开始了吧?

在哪里找到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)查看它的定义和它是如何工作的。保持这个节奏。

本文分享自微信公众号 - php(phpdaily)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2016-05-12

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • PHPer:让我们拥抱敏锐吧

    PHP时代,远没有结束 关于PHP未来的忧虑由来已久,一边是掌控着把持系统的微软的.net平台,一边是红透半边天的Java技巧:PHP似乎已经走到了尽...

    wangxl
  • PHP:40+开发工具推荐

    PHP是为Web开发设计的服务器脚本语言,但也是一种通用的编程语言。超过2.4亿个索引域使用PHP,包括很多重要的网站,例如 Facebook、Digg和Wor...

    wangxl
  • 顶级PHP大师的开发原则

    1. 在合适的时候使用PHP – Rasmus Lerdorf 没有谁比PHP的创建者Rasmus Lerdorf明白PHP用在什么地方是更合理的,他于199...

    wangxl
  • 6本PHP必备书籍,你值得拥有

    PHP(Hypertext Preprocessor,中文名:“超文本预处理器”)是一种通用开源脚本语言。语法吸收了C语言、Java和Perl的特点,利于学习,...

    企鹅号小编
  • PHP技能树—大神的进阶之路

    沈唁
  • PHP中的预定义常量和魔术常量

    返回文件的完整路径和文件名。如果用在包含文件中,则返回包含文件名。自 PHP 4.0.2 起,__FILE__ 总是包含一个绝对路径,而在此之前的版本有时会包含...

    用户7657330
  • TIOBE 9 月排行榜:Java没有悬念,PHP 正努力保住前十位置

    自 2001 年 TIOBE 指数开始以来, PHP 始终保持在榜单的前 10 位。它甚至是 2004 年 TIOBE 的年度编程语言。直到 2009 年底,一...

    Java帮帮
  • Zend 创始人提议创建PHP变种,暂命名为 P++

    今日消息,不久前从 Zend 公司离职的 Zeev Suraski 以 PHP 开发组成员的身份提议要创建 PHP 方言,暂命名为 P++。

    猿哥
  • PHP是什么

    学习一样技能,你得先清楚这项技能是到底做什么的,说到这里,我想大家都会简单的说是做网站的,因为PHP在WEB领域应用最为广泛,大多数网站都是用PHP做的。准确的...

    公众号php_pachong
  • PHP中的预定义常量

    3、__CLASS__: 类的名称(PHP 4.3.0 新加)。自 PHP 5 起本常量返回该类被定义时的名字(区分大小写)。在 PHP 4 中该值总是...

    用户7657330

扫码关注云+社区

领取腾讯云代金券