1、php特点
php虽然是脚本语言但是不是解释器解析的,而是zend虚拟机解析,php代码被编译成opcode,最后又由zend虚拟机来执行,执行完后opcode被清除(可以适用三方工具缓存opcode如apc、xcache,php不支持)
2、变量的实现
了解变量实现首先了解zend zvalue_value结构体
{
zvalue_value:[联合体] ,联合体的内容可能是C语言中的long,double,hashtable…
type:变量类型 , IS_NULL,IS_BOOL,IS_STRING…… IS_RESOURCE
refcount_gc:被指个数
is_ref_gc:是否引用
}
type字段的值为以下常量
IS_NULL, IS_BOOL,IS_LONG,IS_DOUBLE
IS_STRING,IS_ARRAY,IS_OBJECT
IS_RESOURCE
例如:
{
value:{char:’test’,len:5}
type:IS_STRING
refcount_gc:1
is_ref_gc:0
}
如果变量值是字符串,长度是已经缓存在联合体中的,所以strlen计算字符串长度很快
3、了解符号表和变量的花名册
变量符号表是存在hash表中,同时存的还有zvalue_value结构体的地址
在 hash symbol_table中
4、传值变化
传值变化只是改动了结构体中的refcount_gc:值
$a=3;这个时候只有$a指向这个结构体
{zvalue:3;type:IS_LONG;refcount_gc:1;is_ref_gc:0;}
$b=$a;这个时候$a和$b同时指向这个结构体
{zvalue:3;type:IS_LONG;refcount_gc:2;is_ref_gc:0;}
只有当$a或者$b修改时,结构体才分裂
5、引用赋值
引用变化是改动了结构体中的refcount_gc:值和is_ref_gc值
$a=3;这个时候只有$a指向这个结构体
{value:3;type:IS_LONG;refcount_gc:1;is_ref_gc:0;}
$b=&$a;这个时候$a和$b同时指向这个结构体
{value:3;type:IS_LONG;refcount_gc:2;is_ref_gc:1;}
当$a或者$b修改时结构体不分裂,值相应都变化
6、强制分裂
$a = 1;
$b = $a;
$c = &$a;
$c = 2;
如果is_ref_gc:0变为is_ref_gc:1的时候,recout_gc>1的时候,就会产生强制分裂,所有在$c=&$a;的时候,$a和$b就会分裂成俩个结构体
7、引用数组怪现象
$arr = array(1,2,3);
$v = &$arr[1];
$arrs = $arr;
$arr[1] = 100;
echo $arrs[1];//100
php对数组如果只修改数组内的元素,php没有产生强制分裂,反而是影响到,说明php没有检索php数组内的变量变化
8、循环怪现象
current(数组);
$arr = array(“a”,”b”,”c”,”d”);
foreach($arr as &$val){}
foreach($arr as $val){
print_R($arr);
}
//abca,abcb,abcc,abcc
这个时候产生的结果很是让人怀疑,其实这和引用数组怪象一样只不是变成了foreach形式
$val = &$arr[0];
$val = &$arr[1];
$val = &$arr[2];
$val = &$arr[3];
这样就是$val = &$arr[3]发生了应用
9、函数符号表与作用域
在php函数执行的时候,会生成环境执行体op_array(函数的执行步骤),不管函数执行多少次,op_array只存在一个,变量则存在*symbor_table(会生成对应环境栈 多个),所以函数内部变量不会影响外部变量,同时外部变量也不能影响内部变量
10、函数静态变量的实现
静态变量是放在op_array中所以不管调用多少次都是调用的一个静态变量。
11、常量
常量分系统定义和用户定义,所以用户定义和系统定义的重复,也不会产生错误
常量存储和变量差不多,不过常量的哈希表只有一个zend_constants所以对全局有效,而函数中的变量,则会生成一个独立的符号表,所以互不影响(不同文件变量是相互不影响的)
变量存储对象的时候,是走了 _toString()魔术方法函数转话
class test{
public $a = “test”;
public function _toString(){
return $this->name;
}
}
$b = new test();
define(‘c’,$b);
echo c;//test;
12、对象
对象只存储了对象名和对象池指针。对象在对象池中
handle指向hash表,然后hash表指向对象池
13、内存分析
php分为zend_mm_storge层、zend_mm_heap层、emalloc,efree层。
zend_mm_storge是php运行时会申请一块内存。
zend_mm_heap是在大块内存中在分层。
然后具体使用是emalloc,efree层,同时php有内存回收极致,当emalloc,efree层适用后,内存会在释放回到大层缓存中。
14、性能分析
使用XHProf查找PHP性能瓶颈
总结,php使用了大量的hash表,同时对应内存管理十分高效。
HHVM
2015 年 1 月 19 日
有点教程的味道
2015 年 2 月 16 日
好深奥