PHP底层那点事

声明:本博文是我从另一个博客中概括出来的内容,记录到印象笔记中,现在再拿出来分享的,由于忘记了该博客的名字,所以无法贴出来,如果见到雷同,不用怀疑,是我抄的。

PHP四层体系

000340_NwMu_1156700.jpg

1、zend引擎。纯C语言实现,是PHP的内核部分,讲PHP解析解析成opcode并且实现相应的处理方法、基本的数据结构(hashtable、oo)、内存管理、提供相应api。

2、Extensions。围绕zend引擎,对外提供各种服务,如内置函数(array系列)、标准库都是通过Extension实现的。

3、SapiServer Application Programming Interface,服务端编程接口。通过钩子函数使php和外围交互数据。

4、上层应用。即PHP应用,通过不同sapi实现各种场景。例如apache2handler、cgi、cli。


PHP执行流程(opcode)

000451_mxhg_1156700.jpg

获取一段代码,经过词法分析、语法分析翻译成一个一个指令(opcode),zend虚拟机执行opcode(原理上最终是调用c语言函数)


HashTable-核心数据结构

PHP数组、zend内部的函数符号表、全局变量等都是基于hash table实现的。

zend hash table实现了基本的hash散列结构,同时通过附加一个双向链表,提供了正反向遍历数组的功能。如图

000608_ne10_1156700.jpg

1、散列结构。Zend散列结构是典型的hash表模型,通过链表方式解决冲突。zend的hash table是一个自增的数组结构,当hash表满了以后会动态以2倍扩容,初始大小为8。另外在通过key->value查询时候做了优化,用空间换时间(例如在每一个元素中都会用一个变量nKeyLength表示key的长度以快速判断)。

2、双向链表。Zend hash table通过一个链表结构实现了元素的线性遍历。做双向链表可以快速删除,避免遍历。

3、PHP关联数组。典型的hash_table应用。一次遍历如下

getKeyHashValue h;
index = n & nTableMask;
Bucket *p = arBucket[index];
while (p) {
    if ((p->nKeyLength == nKeyLength) && (p->h == h)) {

        RETURN p->data;  
    }
    p=p->next;
}
RETURN FALTURE;

4、PHP索引数组。即我们常见的数组。每一个元素同样分配了nKeyLength(为0),内部成员变量nNextFreeElement为当前分配到的最大id,每次push后同样自动加一。索引key在数组中式通过push的先后决定,而不是通过下标。对于double类型的key会将它当做索引key处理。

5、foreach是通过双向链表完成,对于索引数组比for快,因为省去了key->value的查找,对于$arr['123']和$arr[123]是等价的。


PHP变量

PHP变量分为简单类型(int、string、bool)、集合类型(array、resource、object)和常量(const)。以上变量都是底层同一种结构zval。

zval是zend另外一种重要的数据结构

000729_PcaN_1156700.jpg

主要分3部分

1、type:指定变量类型(整数、字符串、数组)

2、refcount&is_ref:实现引用计数

3、value:储存数据(一切整数都为long,一切小数都为double,当整数越界时候会转为double)

zvalue变量的实际数据,因为储存多种类型,所以是一个union。

引用计数在内存管理和字符串操作使用广泛。PHP变量就是一个典型应用。当refcount为0时候才会被回收,如果是引用赋值,则is_ref为1。

PHP通过引用计数共享数据,当试图改变其中一个变量的时候,如果zend发现该zval被共享,则赋值一个refcount为1的zval,另外原来的refcount递减,这个过程成为'zval分离',也叫'写时拷贝'。但是对于引用变量,修改其中一个,所有的都会被修改。


字符变量也是PHP中基本类型和简单变量,和c++的string一样,有一个变量记录长度,和c不同,PHP的字符串可以是2进制数据。

常见字符串拼接方式和速度比较

$strA='123';$strB='456';$intA=123;$intB=456;

1、$res=$strA.$strB和$res="$strA$strB";这种情况下zend会malloc一块内存进行处理,速度一般。

2、$strA=$strA.$strB;这种最快,在$strA中直接relloc,不会重复拷贝

3、$res=$intA.$intB;慢,因为进行了隐式转换

4、$strA=sprintf("%s%s",$strA.StrB);最慢,不过可读性好


在zend中,对resource和lval作为指针使用,直接指向资源地址,Resource是任意的符合结构,如mysqli、fosck、memcached等

资源的使用

注册:zend分配全局的唯一标示。

获取一个资源变量:罪域resource,zend值记录了它的id

资源销毁:资源需要用户手动销毁,例如unsert,zend是无法自动销毁资源的。

资源可以长期驻留,成为持久资源,因为它是贯穿整个SAPI生命周期的。这种方式可以在一定程度上提高性能。


全局变量和局部变量。任意时刻PHP会有两张符号表(symbol_table和active_symbol_table),其中前者是维护全局变量的,后者是一个指针,指向当前活动的变量符号表,当程序进入到某一个函数中时候,zend会为其分配一个符号表并且将active_symbol_table指向它。

转载于:https://my.oschina.net/zlLeaf/blog/307804

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值