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

  

posted @ 2016-05-11 15:43  zengkefu  阅读(245)  评论(0编辑  收藏  举报