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