第一节:环境搭建
编译安装的关键点:配置编译安装环境,build-essential环境。
1.1 准备编译环境
针对于ubuntu16.04 下面建设编译安装环境:
apt-get install build-essential
1.2 编译
cd ~/php-src
./buildconf
./configure –help #查看可用参数
./configure –disable-all #编译最精简的php文件
make && make install 即可进行安装,
然后通过php -v 查看相应信息。
第二节:源码结构、阅读代码方法
2.1 目录结构
build 编译相关文件
ext 扩展相关文件
main php核心文件
Zend 引擎实现目录
pear PHP扩展与应用仓库
sapi 服务器抽象层代码
TSRM 线程安全
tests 测试脚本集合
win32 window 平台的相关实现
2.1 查看源码
任何编辑器均可
第三节:常用代码
3.1 “##”和”#”
3.1.1 双井号(##)【就是连接两个一起】
在C语言的宏中,”##”被称为连接符(concatenator),它是一种预处理运算符,用来把两个语言符号(Token)组合成单个语言符号。这里的语言符号不一定是宏的变量。并且双井号不能作为第一个或最后一个元素存在。如下所示源码:
#define PHP_FUNCTION ZEND_FUNCTION
#define ZEND_FUNCTION(name) ZEND_NAMED_FUNCTION(ZEND_FN(name))
#define ZEND_FN(name) zif_##name
#define ZEND_NAMED_FUNCTION(name) void name(INTERNAL_FUNCTION_PARAMETERS)
#define INTERNAL_FUNCTION_PARAMETERS int ht, zval *return_value, zval **return_value_ptr, zval *this_ptr, int return_value_used TSRMLS_DC
PHP_FUNCTION(count);
// 预处理器处理以后,PHP_FUNCTION(count);就展开为如下代码
void zif_count(int ht, zval *return_value, zval **return_value_ptr, zval *this_ptr, int return_value_used TSRMLS_DC)
宏ZEND_FN(name)中有一个“##”,它的作用一如之前所说,是一个连接符,将zif和宏的变量name的值连接起来。以这种连接方式为基础,多次使用这种宏形式,可以将它作为一个代码生成器,这样可以在一定程度上减少代码密度,我们可以将它理解为一种代码重用的手段,间接地减小不小心所造成的错误。
3.1.2 单井号(#)【表示后面的是字符串】
“#”是一种预处理运算符,它的功能是将其后面的宏参数进行字符串化操作,简单说就是在对它所引用的宏变量通过替换后在其左右各加上一个双引号,用比较官方的话说就是将语言符号(Token)转化为字符串。例如:
\#define STR(x) #x
int main(int argc, char** argv)
{
printf("%s\n",STR(It is a long string));// 输出 it is a long string
return 0;
}
如前文所说, it is long string 是宏 STR 的参数,在展开后被包裹成一个字符串了。所以 printf 函数能直接输出这个字符串,当然这个使用场景不是很合适,因为这种用法并没有实际的意义,实际中在宏中可能包裹其它的逻辑,比如对字符串进行封装等等。
3.2 关于宏定义中的do-while循环【多行宏使用方式】
通用php内宏调用的用法,因为while(0),也就是仅仅执行一遍。这样方便编译,考虑到平台移植性和不同的系统配置。
\#define ALLOC_ZVAL(z)
do{
(z) = (zval*)emalloc(sizeof(zval_gc_info));
GC_ZVAL_INIT(z);
}while(0)
因为通常的预处理方式,会导致不同的语法结构出错。例如下面情况:
\#define TEST(a,b) a++;b++;
if(expr)
TEST(a,b);
else
do_else();
经过预处理后,会变成:
if(expr)
a++;b++;
else
do_else();
这样就会导致逻辑错误,b++就没有正常执行了。如果要正常的话,需要我们添加{}才能正常执行。
还有另外的一个问题就是:
为了更好的兼容平台,需要定义部分“空操作”
方式1:
\#ifdef SERIALIZE_HEADERS
#define VEC_FREE() smart_str_free(&vec_str)
\#else
#define VEC_FREE() do{}while(0)
\#endif
方式2:
\#ifdef DEBUG
\# define LOG_MSG printf
\#else
\# define LOG_MSG()
\#endif
3.3 #line预处理
3.4 php中的全局变量宏