1. <output id="5rrzn"></output>

        <dl id="5rrzn"><ins id="5rrzn"><strong id="5rrzn"></strong></ins></dl><dl id="5rrzn"><font id="5rrzn"><nobr id="5rrzn"></nobr></font></dl>
        1. 学PHP可以从底层的运行机制与原理开始

          码农程序 / 2019-03-18 19:35:30

          本公众号只做学习分享,本公众号会不定期的给大家分享视频教学教程,项目源码,文章最新动态等,?#34892;?#22823;家的支持!


          抖音号startphp

          用短视频和大家分享PHP学习方法,学习技巧与经验分享,

          欢迎关注抖音号:startphp


          教程力荐

          文章内容

          PHP是一种?#35270;?#20110;web开发的动态语言。具体点说,就是一个用C语言实现包含大量组件模块的软件框架。是一个强大的UI框架。

          简言之;PHP动态语言执行过程:拿到一段代码后,经过词法解析、语法解析等阶段后,源程序会被翻译成一个个指令(opcodes),然后ZEND虚拟机顺次执行这些指令完成操作。PHP本身是用C实现的,因此最终调用的也是C的函数,实际上,我们可以把PHP看做一个C开发的软件。

          一.PHP的设计理念及特点

          1、多进程模型:由于PHP是多进程模型,不同请求间互不干涉,这样保证了一个请求挂掉不会对全盘服务造成影响,目前PHP也早支持多线程模型

          2、弱类型语言:和C/C++、JAVA、C#等语言不同,PHP是一种弱类型的语言。一个变量的类型并不是一开始就确定不变的,运行中才会确定并可能发生隐式或显示的类型转换,这种机制的灵活性在web开发中非常方便、高效,具体会在后面PHP变量中详述。

          3、引擎(Zend)+组件(ext)的模式降低内部耦合。

          4、中间层(sapi )Sapi全称是Server Application Programming Interface 隔绝web server和PHP。

          5、语法简单灵活,没有太多规范。缺点导致风格混杂。

          二、PHP的四层体系

          PHP的核心架构如下图:(我自己根据网上的图有PS了下;比较形象了;www.daokr.com 是我的个人网站;准备运营一个PHP开源项目;之前的www.ikphp.com我是网站长)

          PHP从下倒上是一个4层体系:

          1、Zend引擎:Zend整体用纯C实现,是PHP的内核部分,他将PHP代码翻译(词法、语法解析等一系列编译过程)为可执行opcode的处理并实现相应的处理方法、实现了基本的数据结构(如:hashtable、OO)、内存分配机制及管理、提供了相应的api方法供外部调用,是一切的核?#27169;?#25152;有的外围功能均围绕Zend实现。

          2、Extensions:围绕着Zend引擎,extensions通过组件式的方?#25945;?#20379;各?#21482;?#30784;服务,我们常见的各种内置函数(array系列)、标准库等都是通过extension来实现,用户?#37096;?#20197;根据需要实现自己的extension的典型应用)。

          3、Sapi:Sapi全称Server Application Programming Interface,也就是服务端应用编程接口,Sapi通过一系列钩子函数,使得PHP可以和外围交互数据,这是PHP非常优雅和成功的设计,通过sapi成功的将PHP本身和上层应用解耦隔离,PHP可以不再考虑如何针对不同应用进行兼容,而应用本身?#37096;?#20197;针对自己的特点实现不同的处理方式。

          4、上层应用:这就是我们平时编写的PHP程序,通过不同的spai方式得到各种各样的应用模式,如何通过webserver实现web应用、在命令行下已脚本方式运行等等。

          我们需要:性能优异的引擎(Zend)+合适的车轮(Ext)+正确的跑道(Sapi)。

           

          三、Sapi

          Sapi通过一系列的接口,使得外部应用可以和PHP?#25442;?#25968;据并可以根据不同应用特点实现特定的处理方法,我们常见一些sapi有:

          1、apache2handler:这是以apache作为webserver,采用mod_PHP模式运行时候的处理方式,也是现在应用最广泛的一种。

          2、cgi:这是webserver和PHP直接的另一种交互方式,也就是大名鼎鼎的fastcgi协议,在最近fastcgi+PHP得到越来越多的应用,也是异步webserver所唯一支持的方式;典型应用nginx服务器;fastcgi 说白点就是 php的一个扩展

          • Web Server启动时载入FastCGI进程管理器(IIS ISAPI或Apache Module)

          • FastCGI进程管理器自身初始化,启动多个CGI解释器进程(可见多个php-cgi)并等待来自Web Server的连接。

          • 当客户端请求到达Web Server?#20445;現astCGI进程管理器选择并连接到一个CGI解释器。Web server将CGI环境变量和标?#38469;?#20837;发送到FastCGI子进程php-cgi。

          • FastCGI子进程完成处理后将标?#38469;?#20986;和错误信息从同一连接返回Web Server。当FastCGI子进程关闭连接?#20445;?#35831;求便告处理完成。FastCGI子进程接着等待并处理来自FastCGI进程管理器(运行在Web Server中)的下一个连接。 在CGI模式中,php-cgi在此便?#39034;?#20102;。

          • 在上述情况中,你可以想象CGI通常有多慢。每一个Web请求PHP都必须重新解析php.ini、重新载入全部扩展并重初始化全部数据结构。使用FastCGI,所有这些都只在进程启动时发生一次。一个额外的好处是,持续数据库连接(Persistent database connection)可以工作。

           

          3、cli:命令行调用的应用模式

          命令行界面(英语:command-line interface,缩写:CLI)是在图形用户界面得到普及之前使用最为广泛的用户界面,它通常不支持鼠标,用户通过键盘输入指令,计算机接收到指令后,予以执行。也有人称之为字符用户界面(CUI)。
          通常认为,命令行界面(CLI)没?#22411;?#24418;用户界面(GUI)那么方便用户操作。因为,命令行界面的软件通常需要用户记忆操作的命令,但是,由于其本身的特点,命令行界面要较图形用户界面节?#25216;?#31639;机?#20302;?#30340;资源。在熟记命令的前提下,使用命令行界面往往要较使用图形用户界面的操作速度要快。所以,图形用户界面的操作?#20302;持校?#37117;保留着可选的命令行界面。

          四、PHP的执行流程&opcode

           

          PHP动态语言执行过程:拿到一段代码后,经过词法解析、语法解析等阶段后,源程序会被翻译成一个个指令(opcodes),然后ZEND虚拟机顺次执行这些指令完成操作。PHP本身是用C实现的,因此最终调用的也是C的函数,实际上,我们可以把PHP看做一个C开发的软件。

          PHP的执行的核心是翻译出来的一条一条指令,也是opcode。

          Opcode是PHP程序执行的最基本单位。

          在计算机科学领域中,操作码(Operation Code, OPCode)被用于描述机器语言指令中,指定要执行?#25345;?#25805;作的那部分机器码,构成OPCode的指令格式和规范由处理器的指令规范指定。

          一个opcode由两个参数(op1,op2)、返回值和处理函数组成。PHP程序最终被翻译为一组opcode处理函数的顺序执行。

          常见的几个处理函数:

          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?#21495;?#26029;相等 $a==1
          ZEND_IS_IDENTICAL_SPEC_CV_CONST?#21495;?#26029;相等 $a===1


          五、HashTable——核心数据结构

          HashTable是Zend的核心数据结构,在PHP里面几乎并用来实现所有常见功能,我们知道的PHP数组即是其典型应用,此外,在zend内部,如函数符号表、全局变量等也都是基于hash table具有如下特点:

          1、支持典型的key->value查询

          2、可以当做数组使用

          3、添加、?#22659;?#33410;点是O(1)复杂度

          4、key支?#21482;?#21512;类型?#21644;?#26102;存在关联数组合索引数组

          5、Value支?#21482;?#21512;类型:array("string",2332)

          6、支持线性遍历:如foreach

          Zend hash table实现?#35828;?#22411;的hash表散列结构,同时通过附加一个双向链表,提供了正向、反向遍历数组的功能。其结构如下图:

           

           

          可以看到:在hash table中既有key->value形式的散列结构,也有双向链表模式,使得它能够非常方便的支持快速查找和线性遍历。

          1、散列结构:Zend的散列结构是典型的hash表模型,通过链表的方式来解决冲突。需要注意的是zend的hash table是一个自增长的数据结构,当hash表数目满了之后,其本身会动态以2倍的方式扩容并重新元素位置。初始大小均为8。另外,在进行 key->value快速查找时候,zend本身还做了一些优化,通过空间换时间的方式加快速度。比如在每个元素中都会用一个变量 nKeyLength标识key的长度以作快速判定。

          2、双向链表:Zend hash table通过一个链表结构,实现了元素的线性遍历。理论上,做遍历使用单向链表就够了,之所以使用双向链表,主要目的是为了快速?#22659;?#36991;免遍历。 Zend hash table是一种复合型的结构,作为数组使用?#20445;?#21363;支持常见的关联数组也能够作为顺序索引数字?#35789;?#29992;,甚至允许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;


          4、PHP索引数组?#26680;?#24341;数组就是我们常见的数组,通过下标访问。例如 $arr[0],Zend HashTable内部进行了归一化处理,对于index类型key同样分配了hash值和nKeyLength(为0)。内部成员变量 nNextFreeElement就是当前分配到的最大id,每次push后自动加一。正是这种归一化处理,PHP才能够实现关联?#22836;?#20851;联的混合。由于 push操作的特殊性,索引key在PHP数组中先后顺序并不是通过下标大小来决定,而是由push的先后决定。例如 $arr[1] = 2; $arr[2] = 3;对于double类型的key,Zend HashTable会将他当做索引key处理

          六、PHP变量

          PHP是一门弱类型语言,本身不严格区分变量的类型。PHP在变量申明的时候不需要指定类型。

          PHP在程序运行期间可能进行变量类型的隐示转换。 和其他强类型语言一样,程序中?#37096;?#20197;进行显示的类型转换。

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

          Zval主要由三部分组成:

          • type:指定了变量所述的类型(整数、字符串、数组等)

          • refcount&is_ref:用来实现引用计数(后面具体介绍)

          • value:核心部分,存储了变量的实?#36866;?#25454;

          Zvalue是用来保存一个变量的实?#36866;?#25454;。因为要存储多种类型,所以zvalue是一个union,也由此实现了弱类型。

          PHP变量类型和其实际存储对应关?#31561;?#19979;:

          • 引用计数在内存回收、字符串操作等地方使用非常广泛PHP中的变量就是引用计数的典型应用。Zval的引用计数通过成员变量is_ref和ref_count实现,通过引用计数,多个变量可以共享同一份数据。避免频繁拷贝带来的大量消耗。在进行?#25345;?#25805;作?#20445;瑉end将变量指向相同的zval同时ref_count++,在unset操作?#20445;?#23545;应的ref_count-1。只有ref_count减为0时才会真正执行销毁操作。如果是引用?#25345;擔?#21017;zend会修改is_ref为1。

          • PHP变量通过引用计数实现变量共享数据,那如果改变其中一个变量?#30340;?/strong>当试图写入一个变量?#20445;琙end若发现该变量指向的zval?#27426;?#20010;变量共 享,则为其复制一份ref_count为1的zval,并递减原zval的refcount,这个过程称为“zval分离”。可见,只?#24615;謨行?#25805;作发生时 zend才进行拷贝操作,因此也叫copy-on-write(?#35789;?#25335;贝)对于引用型变量,其要求?#22836;?#24341;用型相反,引用?#25345;?#30340;变量间必须是捆绑的,修改一个变量就修改了所有捆绑变量。整数、浮点数是PHP中的基础类型之一,也是一个简单型变量。对于整数和浮点数,在zvalue中直接存储对应的值。其类型分别是long和double。

          • 从zvalue结构中可以看出,对于整数类型,和c等强类型语言不同,PHP是不区分int、unsigned int、long、long long等类型的,?#36816;?#26469;说,整数只有一种类型也就是long。由此,可以看出,在PHP里面,整数的取值?#27573;?#26159;由编译器位数来决定而不是固定不变的。

          • 对于浮点数,类似整数,它也不区分float和double而是统一只有double一种类型在PHP中,如果整数?#27573;?#36234;界了怎么办?这种情况下会自动转换为double类型,这个一定要小?#27169;?#24456;多trick都是由此产生。

          • 和整数一样,字符变量也是PHP中的基础类型和简单型变量通过zvalue结构可以看出,在PHP中,字符串是由由指向实?#36866;?#25454;的指针和长度结 构体组成,这点和c++中的string比较类似。由于通过一个实际变量表示长度,和c不同,它的字符串可以是2进制数据(包含 足球外围投注app

                1. <output id="5rrzn"></output>

                  <dl id="5rrzn"><ins id="5rrzn"><strong id="5rrzn"></strong></ins></dl><dl id="5rrzn"><font id="5rrzn"><nobr id="5rrzn"></nobr></font></dl>

                      1. <output id="5rrzn"></output>

                        <dl id="5rrzn"><ins id="5rrzn"><strong id="5rrzn"></strong></ins></dl><dl id="5rrzn"><font id="5rrzn"><nobr id="5rrzn"></nobr></font></dl>