PHP(底层)的运行机制和原理

当涉及到PHP的运行机制也将PHP模块第一,PHP的共有三个模块:内核,Zend引擎,和扩展层;PHP内核用来处理请求、文件流、错误处理等相关操作;Zend引擎(泽)是用于源文件转换成机器语言,然后在虚拟机上运行它;扩展函数库和PHP流,用它们来执行某些操作。例如,我们需要MySQL扩展连接MySQL数据库。当执行程序时,可能有几个扩展连接。泽控制扩展它的权限,然后在处理特定任务后返回它。

最后,则返回程序的PHP内核的结果,然后将结果发送到业务层,然后输出到浏览器。

PHP说它很简单,但精通并不是一件简单的事情,除了使用它,我们还必须知道它在底部是如何工作的。

PHP是一种动态的Web开发语言,具体来说,它是一种在C语言中实现大量组件的软件框架,在更窄的角度来看,它可以被认为是一个强大的UI框架。

理解PHP的底层实现的目的是什么我们首先需要理解动态语言,我们需要首先理解它。内存管理和框架模型值得借鉴。我们可以扩大我们的发展,以实现更强大的功能和优化我们的节目的性能。

1的设计理念和特点。PHP

多进程模型:由于PHP是一个多进程模型,不同请求之间没有干扰,因此可以挂起一个请求,这不会影响整个服务。当然,随着时代的发展,PHP已经支持多线程模型。

弱类型语言:与C / C++,java,C #,和其他语言,PHP是弱类型语言,变量的类型是不在最初确定的,这将决定和隐式或显式类型转换操作。这种机制的灵活性在Web开发中非常方便和高效,它将在以后的PHP变量中详细介绍。

发动机的模式(Zend)+组件(EXT)降低了内部耦合。

中间层(SAPI)隔离Web服务器和PHP。

语法简单而灵活,没有太多的规范,缺点导致风格的混合,但糟糕的程序员不编写太多的程序来伤害整个世界。

四层2系统。PHP

PHP的核心体系结构如下:


从地图上可以看到,PHP是一个从底层到顶层的4层系统:

Zend引擎:Zend整体用纯C实现,是PHP核心的一部分,它将PHP代码翻译(词法和句法分析和一系列的汇编程序)处理相应的治疗方法可执行的操作码和实现,实现了基本的数据结构(如哈希表,OO),内存分配和管理API提供了一个外部调用相应的方法,是一切的核心,都是围绕Zend外围功能。

扩展:在Zend引擎,扩展提供的各种服务,通过基本的组成部分,我们有各种各样的内置函数(如数组),标准库实现的扩展,用户也可以根据需要实现外延扩张,以达到优化目标函数(如PHP贴吧,中间层是丰富的文本分析的使用是推广的一个典型应用)。

SAPI的全名:SAPI是服务器应用程序编程接口,也就是服务器应用程序编程接口SAPI通过一系列的钩子函数,使PHP可以和周围的数据,这是一个非常优雅和成功的PHP SAPI的设计,通过对PHP本身的成功和解耦隔离中的应用PHP可以不再考虑不同的应用程序本身也可以兼容,并根据自己的特点来实现不同的方法。

上层应用:这就是我们平时写的PHP程序,并通过不同的方式获得各种SAPI应用模式,如Web应用程序通过Web服务器,在命令行中运行脚本,等等。

如果PHP是一辆车,然后车车架是PHP,Zend是车的引擎(发动机),Ext以下的各种部件是汽车的轮子,SAPI可以看作是路,汽车可以运行在不同的道路类型,和PHP程序运行时在车上路。所以我们需要发动机性能优良+右轮+正确的跑道。

三.SAPI

正如前面所提到的,PHP SAPI可以交换数据,通过一系列的接口,可以根据不同的应用特点实现特定的处理方法。我们的一些常见的业务包括:

apache2handler:这是Apache作为Web服务器,使用mod_php模式运行时处理,是目前应用最为广泛的一种。

CGI:这是另一种方式的Web服务器和PHP之间的相互作用,即著名的FastCGI协议。近年来,FastCGI + PHP已经越来越多地应用于今年,也支持异步服务器的唯一途径。

命令行调用的应用程序模式

4。PHP执行流程的操作码

让我们来看看PHP代码执行的流程。


从图中我们可以看出,PHP实现了一个典型的动态语言的实现过程:得到一段代码,通过词法分析、语法分析阶段,源程序会被翻译成指令(操作码),然后Zend虚拟机执行的指令完成operation.php本身是用C实现的,所以最终电话是一种事实上的功能,我们可以看到PHP作为开发软件。

PHP的执行核心是翻译的一个指令,即操作码。

Opcode是在PHP程序执行的最基本的单元,一个操作码由两参数(OP1、OP2),返回值,和处理功能的PHP程序最终转化为一系列的操作码处理功能的顺序。

几种常见的处理函数:

zend_assign_spec_cv_cv_handler:变量分配($ = $ B)

zend_do_fcall_by_name_spec_handler:函数调用

zend_concat_spec_cv_cv_handler:字符串拼接$ A $

zend_add_spec_cv_const_handler:加法运算+ 2美元

zend_is_equal_spec_cv_const:法官平等= = 1美元

zend_is_identical_spec_cv_const:法官平等= = = 1美元

5。哈希表-核心数据结构

哈希表是Zend核心数据结构。在PHP中,它几乎被用来实现所有的公共函数。我们知道的PHP数组是它的典型应用程序。此外,在Zend,如函数符号表,全局变量,等等,也正是基于哈希表的实现。

PHP的哈希表具有以下特性:

支持典型的键>值查询

可以用作数组

添加和删除节点是O(1)复杂度

密钥支持混合类型:同时有一组关联索引数组。

值支持混合类型:数组(字符串,2332)

支持线性遍历,如foreach

Zend hash表实现了一个典型的散列结构,提供了一个正向和反向通过附加一个双向链表的遍历数组,其结构如下:


可以看出,在哈希表中,有键-值形式和双向链表模式的哈希结构,支持快速搜索和线性遍历非常方便。

哈希结构:的Zend hash结构是一种典型的哈希表的模型通过链表解决冲突。应该指出的是,Zend hash表是一个不断增长的数据结构的自。当哈希表的数量,它会动态地扩展和2次重新定位元素的初始大小为8。此外,当键->值快速查找,Zend本身也做了一些优化的空间换时间的速度。例如,在每一个元素,一个变量nkeylength用于识别用于快速测定长度的关键。

双向链表:通过链结构Zend哈希表实现线性遍历元素。在理论上,单向链表的使用是足够的,为什么双向链表的使用,主要目的是快速删除,避免遍历。Zend哈希表是一个复合结构。当用作数组时,它支持公共关联数组,也可以用作连续索引数,甚至允许2个数组的混合。

PHP数组:数组是一个典型的hash_table应用。查询过程经历以下步骤(你可以从代码中看到的,这是一种常见的散列的查询过程,增加了一些快速决定加快查找。):


getkeyhashvalue H;
指数= N ntablemask;
斗* P = arbucket {指数};
当(p){
If ((p->h = = h) (p->nKeyLength = = nKeyLength) {)
返回p >数据;
}
下一页;
}


PHP数组的索引数组索引:是我们共同的数组的下标访问。例如,$ ARR { 0 },Zend HashTable是归在哈希表的哈希值,并与nkeylength(0)也分配为指数型的关键。内部成员变量,nnextfreeelement,是最大的ID是目前分配,和自动添加一个接着一个的推动。正是这种规范化的过程,PHP可以实现协会和无关的组合。由于对推送操作的特殊性,在PHP数组索引键的顺序不是由下标的大小决定,而是由推确定。例如,美元ARR { 1 } = 2;$ ARR { 2 } = 3;双型的钥匙,Zend HashTable会把他当作一个索引键

6。PHP variable

PHP是一种弱类型的语言,其本身并不严格区分variable.php类型不需要指定类型的变量时declared.php可以运行的程序在执行一个隐藏的变量类型。像其他强类型语言中,类型转换的类型也可以在一个程序的显示。PHP变量可分为简单类型(int,string,bool),集合类型(数组资源对象),和常量(const)。上述所有变量都是相同的结构zval底部。

机制是另一个非常重要的数据结构,在Zend PHP变量的确定和实施。数据结构如下:


机制主要由三部分组成:

类型:指定变量的类型(整数、字符串、数组等)。

refcountis_ref:用来实现引用计数(稍后描述)

值:核心,存储变量的实际数据。

zvalue是实际的数据是用来保存一个变量。因为你想存储多种类型,zvalue是一个联盟,它实现了弱型。

PHP变量类型与其实际存储之间的关系如下:

is_long ->左值

is_double ->值

is_array -> HT

is_string -> STR

is_resource ->左值

引用计数被广泛应用于如记忆恢复,地方的字符串操作,等等。在PHP中的变量是引用计数的一个典型应用,变量的引用计数被成员变量is_ref和ref_count实施,通过引用计数,多变量数据共享,避免了大量频繁份消费。

在赋值操作,Zend点变量相同的变量和ref_count + +,和相应的ref_count-1当撤消操作。破坏行动实际上只进行ref_count时降低到了0。如果分配引用Zend修改is_ref 1。

PHP变量与引用计数共享数据,如果其中一个变量被更改了呢当试图写入一个变量,如Zend发现变量,变量点是由多个变量共享,它复制机制的ref_count 1和降低原有变量的引用计数,这叫做zval分离。可以看出,只有复制操作是由Zend当一个写操作发生时,所以它也被称为写时复制(写时复制)。

对于引用变量,需求不同于非引用类型。分配给作业的变量必须被捆绑。修改一个变量修改所有捆绑变量。

整数和浮点数是一个PHP的基本类型,以及一个简单的变量,整数和浮点数,相应的值直接存储在zvalue。类型是long和double,分别。

从zvalue结构,我们可以看到,整数型,和C等强类型语言,PHP不区分int,unsigned int,长长的,长长的等。对于它,只有一种类型的整数,即长,因此可以看出,在PHP中,整数值的范围取决于编译器数字的数目而不是固定的。

对于浮点数,类似的整数,它不区分浮点和双,但只有一种类型的双。

在PHP中,如果整数范围超出边界该怎么办在这种情况下,它会自动转换为双类型,这必须小心,很多技巧是由此产生的。

与整数、字符变量也在PHP的基本和简单的变量,zvalue结构可以看出,在PHP中,字符串是由一个指针指向实际数据的结构和长度,并在C++类似于字符串。因为一个真正的变量的长度是不同的,C,它的字符串可以是2二进制数据(包括),而在PHP中,字符串长度strlen是O(1)操作。

当添加、修改和添加字符串操作,PHP将内存生成新的字符串。最后,出于安全的考虑,PHP将仍然是在一个字符串的生成最后补充道

常用字符串拼接与速度比较:

这是假设有4个变量:$ strA =123;strB = 456美元;123美元= = 456专业维护;

现在,对几种字符串拼接方法进行了比较和解释如下:

RES =美元美元美元美元战略。strB RES =战略STRB美元美元

在这种情况下,可以将重新malloc一块内存和处理,其速度是一般。

战略=美元美元美元strB的战略。

这是最快的,和Zend将直接relloc当前策略,避免重复

美元美元美元之间维持既=。

这是比较慢的,因为它需要隐式格式转换,并且应尽量避免实际的编写程序。

美元战略= sprintf(%s %s,美元美元strB的战略。);

这将是最慢的方式,因为sprintf不是PHP的语言结构,它需要更多的时间格式的识别和处理,和它自身的机制也是malloc。但方式sprintf是最可读的,在实践中,可根据具体情况灵活选择。

PHP数组是由Zend HashTable自然实现。

如何实现每个操作呢一个数组的foreach的哈希表的遍历双向链表做为索引数组,遍历foreach的效率比这高得多,从而节省了查找键->值的计数操作直接调用哈希表-> numofelements,O(1)操作的。一个这样的字符串'123,Zend将被转换为整数形式。'123}和{ $ ARR ARR { 123 }是等价的美元

资源类型变量是PHP中最复杂的变量之一,也是一个复杂的结构。

PHP变量可以代表一个广泛的数据类型,但它是很难描述的自定义数据类型。由于没有描述这些复合结构的有效途径,是没有办法使用传统运营商给他们。为了解决这个问题,你只需要引用一个指针的任意标识(标签),这被称为资源。

在机制、资源、语句作为一个指针直接指向的地址资源所在地。资源可以是任意的复合结构,与我们熟悉的mysqli,fsock,Memcached等资源。

如何使用资源:

注册一个自定义的数据类型,你想使用它作为一种资源。首先,你需要登记,和Zend分配全局唯一标志。

获得资源变量:资源,保持hash_tale Zend的实际身份->数据。对于一个资源,只有它的ID记录在zval。取是通过寻找特殊值的返回hash_table ID。

资源破坏:资源的数据类型是多种多样的。Zend本身无法摧毁它。因此,用户必须提供一个破坏作用当资源注册。当设置是一种资源,可以调用相应的函数完成分析。删除它从全球资源表同时。

资源可以停留很长时间,不只是在被引用的所有变量的范围,即使一个请求和新要求的出现完成。这些资源被称为持久性资源,因为他们坚持通过SAPI的整个生命周期,除非他们是专门破坏。在许多情况下,持久性资源可以在一定程度上提高性能。例如,我们常见的mysql_pconnect,持久性资源分配的内存通过pemalloc这样的请求不会在请求结束时公布。

zend,两者之间没有区别。

PHP中的本地变量和全局变量是如何实现的一个要求,在任何时候,PHP可以看到两个符号表(symbol_table和active_symbol_table),其中前者是用来维护全局变量。后者是一个指针,指向当前活动的变量符号表。当一个程序进入一个函数,Zend将分配一个符号表,X,和点active_symbol_table到同时,全局变量和局部变量的区别是这样实现的。

获取变量值:PHP的符号表是通过hash_table,对每个变量赋予唯一的标识,并找到相应的机制从表根据鉴定。

一个全局变量是在函数:函数中,我们可以明确地宣布全球使用全局变量,symbol_table到相同名称的变量引用了active_symbol_table,如果有symbol_table没有同名的变量,它将创造第一。