PHP底层运行机制与原理

php的设计理念及特点

  • 多进程模型:由于PHP是多进程模型,不同请求间互不干涉,这样保证了一个请求挂掉不会对全盘服务造成影响,当然,时代发展,PHP也早已支持多线程模型 。
  • 弱类型语言:和C/C++、JAVA、C#等语言不同,PHP是一门弱类型语言 。一个变量的类型并不是一开始就确定不变,运行中才会确定并可能发生隐式或显式的类型转换,这种机制的灵活性在web开发中非常方便、高效 。
  • 引擎(Zend)+组件(ext)的模式,降低内部耦合 。
  • 中间层(sapi),隔绝web server和PHP 。
  • 语法简单灵活,没有太多规范 。
 
PHP的核心架构
PHP核心架构如下图,从下到上可以简单分为四层体系:
PHP底层运行机制与原理

文章插图
 
  • Zend引擎:纯C实现,是PHP的内核部分,它将PHP代码翻译(词法、语法解析等一系列编译过程)为可执行opcode的处理并实现相应的处理方法、实现了基本的数据结构(如hashtable、oo)、内存分配及管理、提供了相应的api方法供外部调用,是一切的核心,所有的外围功能均围绕Zend实现 。
  • Extensions:围绕着Zend引擎,extensions通过组件式的方式提供各种基础服务,我们常见的各种内置函数(如array 系列)、标准库等都是通过extension来实现 。
  • Sapi :全称是Server Application Programming Interface服务端应用编程接口,Sapi通过一系列钩子函数,使得PHP可以和外围交互数据,这是PHP非常优雅和成功的一个设计,通过 sapi成功的将PHP本身和上层应用解耦隔离,PHP可以不再考虑如何针对不同应用进行兼容,而应用本身也可以针对自己的特点实现不同的处理方式 。
  • 常见的一些sapi有:
  • Apache2handler:这是以apache作为webserver,采用mod_PHP模式运行时候的处理方式,也是现在应用最广泛的一种 。
  • cgi:这是webserver和PHP直接的另一种交互方式,也就是大名鼎鼎的fastcgi协议,在最近今年fastcgi+PHP得到越来越多的应用,也是异步webserver所唯一支持的方式 。
  • cli:命令行调用的应用模式
  • 上层应用:这就是我们平时编写的PHP程序,通过不同的sapi方式得到各种各样的应用模式,如通过webserver实现web应用、在命令行下以脚本方式运行等 。
PHP的执行流程
PHP底层运行机制与原理

文章插图
 
常见的几个处理函数:
  • ZEND_ASSIGN_SPEC_CV_CV_HANDLER : 变量分配 ( a=b)
  • ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER:函数调用
  • ZEND_CONCAT_SPEC_CV_CV_HANDLER:字符串拼接 a.b
  • ZEND_ADD_SPEC_CV_CONST_HANDLER: 加法运算a+2
  • ZEND_IS_EQUAL_SPEC_CV_CONST:判断相等 a==1
  • ZEND_IS_IDENTICAL_SPEC_CV_CONST:判断相等 a===1
 
Zend引擎介绍
 
4.1 实现HashTable数据机构:
HashTable是Zend的核心数据结构 。在PHP里面几乎用来实现所有常见功能,我们知道的PHP数组即是其典型应用,此外,在zend内部,如函数符号表、全局变量等也都是基于hash table来实现 。
Zend hash table实现了典型的hash表散列结构,同时通过附加一个双向链表,提供了正向、反向遍历数组的功能 。其结构如下图
PHP底层运行机制与原理

文章插图
 
可以看到,在hash table中既有key->value形式的散列结构,也有双向链表模式,使得它能够非常方便的支持快速查找和线性遍历 。
散列结构:Zend的散列结构是典型的hash表模型,通过链表的方式来解决冲突 。需要注意的是zend的hash table是一个自增长的数据结构,当hash表数目满了之后,其本身会动态以2倍的方式扩容并重新元素位置 。初始大小均为8 。另外,在进行 key->value快速查找时候,zend本身还做了一些优化,通过空间换时间的方式加快速度 。比如在每个元素中都会用一个变量 nKeyLength标识key的长度以作快速判定 。
双向链表:Zend hash table通过一个链表结构,实现了元素的线性遍历 。理论上,做遍历使用单向链表就够了,之所以使用双向链表,主要目的是为了快速删除,避免遍历 。Zend hash table是一种复合型的结构,作为数组使用时,即支持常见的关联数组也能够作为顺序索引数字来使用,甚至允许2者的混合 。
PHP关联数组:关联数组是典型的hash_table应用 。一次查询过程经过如下几步(从代码可以看出,这是一个常见的hash查询过程并增加一些快速判定加速查找):
getKeyHashValue h;index = n & nTableMask;Bucket *p = arBucket[index];while (p) { if ((p->h == h) && (p->nKeyLength == nKeyLength)) { RETURN p->data;} p=p->next;}RETURN FALTURE;


推荐阅读