php内核探索
http://www.nowamagic.net/librarys/veda/special/PHP%E5%86%85%E6%A0%B8%E6%8E%A2%E7%B4%A2 关注PHP 源代码 Zend\zend.h ------------------------------------------------------ 变量的值由一个结构体构成 struct _zval_struct{ zvalue_value value; /*变量的值 */ zend_uint refcount_gc;/*指向的次数*/ zend_uchar type; /*变量类型*/ zend_uchar is_ref_gc;/*是否引用*/ } type字段值为以下常量(8种数据类型) IS_NULL,IS_BOOL,IS_LONG,IS_DOUBLE IS_STRING,IS_ARRAY,IS_OBJECT,IS_RESOURCE ---------------------------------- zvalue_value:类型的结构union typedef union _zvalue_value{ long lval double dval struct{ char * int len; }str; HashTable * ht; //数组类型 zend_object_value obj; } zvalue_value; PHP中有8种数据类型,为什么zvalue_value->value联合体中,只有5种? 答: 1:NULL直接zval->type=IS_NULL,就可以表示不必设置vaLue的值 2:BOOL型 ,zval->type=IS_BOOL,再设置 zval.value.lval=1/0 3:Resoure型,资源型,往往是服务器上打开的一个接口,如 文件读取接口 zval->type=IS_RESOURCE,zval.value.lval=服务器上打的接口的编号 PHP字符串类型,长度是已经缓存的,调用STRLEN 时系统可直接返加其长度,不必计算 ---------------------------------------- zvalue_zvalue: 值内容 lval dval struct str *ht obj type: 值类型 refgc_count is_ref_gc ---------------------------------------------- php底层变量的实现 eg: <?php $a=3; /* { union_zvalue{long 3} type IS_LONG refcount_gc:1 is_ref_gc:0 } */ $b='hello' /* { {char:'hello' len:5 } type:IS_STRING refcount_gc:1 ls_ref_gc:0 } */ > --------------------------------------------------------------------- 符号表:symbol_table 符号表是一张哈希表,里面存储了变量名->变量的ZVAL结构体的地址 zeng/zend_globals.h中的HashTable symbol_table定义 eg: <?php $a=3 $b=4.321 $c='hello'; /***** 生成了3个结构体, 同时,全局符号表中,多了3条记录 a----->0x123---->结构体{3} b----->ox21d---->结构体{4.321} c----->0x3A0---->结构体{HELLO} ***/ > 变量的赋值与引用 <?php $a=3; $b=$a; /***** 产生一个结构体 **** / ------------------------------------------------------ 当变量a赋值 $a=3 当前结构体: zvalue:3 type:IS_LONG refcont_gc:1 is_ref_gc:0 当变量$a给$b赋值时 $b=$a 结构体变为: zvalue:3 type:IS_LONG recount_gc:2 is_ref_gc:0 这样没有发声结构体复制,省空间, 两个变量指向同一个结构体,refcount_gc值从1变为2 ----------------------------------------------------- 写时复制copy on write <?php $a=3; $b=$a; /***** 产生一个结构体 ****/ $b=5 /**** 符号表中$a指向下面结构体 zvalue:3 type:IS_LONG recount_gc:1 is_ref_gc:0 --------------------------------------------------------------------- 符号表$b,指向另外一个结构体(一开始共用,到某一方要修改值时才分裂:copy on write) zvalue:5 type:IS_LONG recount_gc:1 is_ref_gc:0 ****/ echo $a,$b;3,5 没有干扰到对方 ------------------------------------------- 引用复制特点 引用时,is_ref_gc=1,说是这个结构体与变量是引用关系,改的时候,不分裂 直接修改什,所有指向此结构体的变量,值都变化 EG: $a=3 zvalue:3 type:IS_LONG refcount_gc:1 is_ref_gc:0 当$b=&a //引用 $b与$a同时指向一个结构体 zvalue:3 type:IS_LONG refcount_gc:2 is_ref_gc:1 $b=5 :结构体不分裂 结构体还是如下 zvalue:3 type:IS_LONG refcount_gc:2 is_ref_gc:1 ----------------------------------------------------------------------- <?php //强制分裂 $a=3; /*** { value:3 refcount_gc:1 is_ref_gc:0 } **/ $b=$a; /*** { value:3 refcount_gc:2 is_ref_gc:0 } **/ $c=&a; //不会是如下这样变,否则,$b将会受干扰 /*** { value:3 refcount_gc:3 is_ref_gc:1 } **/ //如果ls_ref_gc 0->的过程中,recount_gc>1,将会强制分裂 $b分烈一份结构体 { value:3 refcount_gc:1 is_ref_gc:0 } $a,$c结构体如下 { value:3 refcount_gc:2 is_ref_gc:1 } $c=5 echo $a,$b,$c 5,3,5 ------------------------------------------------------------------- <?php $arr=array(0,1,2,3); $tmp=$arr; $arr[1]=11; echo $tmp[1]; //1 分析: $arr=array(0,1,2,3) 结构体: zvalue:*ht ---------->0 addr1------->zval:0 type:IS_ARRAY 1 addr2-------->zval:1 refcount_gc:1 2 addr3--------->zval:2 is_ref-gc:0 3 addr4---------zval:3 | | $tmp=$arr----------------- $tmp 结构体 zvalue:*ht type:IS_ARRAY refcount_gc:2 is_ref-gc:0 -------------------------------------------------------------------- $arr[1]=11 此时结构 zvalue:*ht ---------->0 addr1------->zval:0 type:IS_ARRAY 1 addr2-------->zval:11 refcount_gc:1 2 addr3--------->zval:2 is_ref-gc:0 3 addr4---------zval:3 些时的$tmp结构: zvalue:*ht ---------->0 addr1 //指向arr type:IS_ARRAY 1 addr2-------->zval:1(自已创建的) refcount_gc:1 2 addr3 //指定arr is_ref-gc:0 3 addr4 //指定arr -------------------------------------------------------------------------------------------- $arr=array(0,1,2,3) $x=&arr[1]; $tmp=$arr; $arr[1]=999 echo $tmp[1] //999 ------------------------------------------------------ 查看PHP函数的C语言实现: cd php-src 查找 grep -rn "PHP_FUNCTION(socket_accept)" ./ext 返回 ./ext/sockets/sockets.c:938:PHP_FUNCTION(socket_accept) 查找 grep -rn "PHP_FUNCTION(array_merge)" ./ext 返回 ./ext/standard/array.c:2266:PHP_FUNCTION(array_merge) 可以看出,PHP库函数的基本都在php-src/ext目录下,里面有具体函数库比如socket,一般的函数基本都在标准库standard. PHP源码的几个重要目录: ext(扩展) 108M Zend(引擎) 9.2M sapi(cli/cgi/mod_php/fpm) 3.1M