学习笔记之php的运行机制与原理

前言

经常用php写cgi,但是发现自己并不理解它的运行原理,所以学习一下。

PHP是什么

PHP是一种适用于Web开发的动态语言,是一个用C语言实现,包含大量组件的软件框架。

  • 多进程模型:PHP是多进程模型。不同请求间互不干涉,即一个请求挂掉不会对全盘服务造成影响。(使用进程控制函数,创建子进程,执行程序,处理信号等)。PHP也能支持多线程模型。

    进程拥有一个完整的虚拟地址空间,不依赖于线程而独立存在;线程是进程的一部分,没有自己的地址空间,与进程内的其他线程一起共享分配给该进程的所有资源。
    区别:
    (1)进程具有独立的空间地址,一个进程崩溃后,在保护模式下不会对其它进程产生影响。
    (2)线程只是一个进程的不同执行路径,线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉。

  • 弱类型语言:和C、C++、C#、Java等不同,PHP是一种弱类型的语言。即一个变量的类型并不是一开始就确定不变的,运行中才会确定并可能发生隐式或显示的类型转换。

  • 引擎(Zend) + 组件(ext)的模式降低内部耦合
  • 中间层(sapi)隔绝web server和PHP
  • 语法简单灵活,没有太多规范

PHP的核心架构

PHP的核心架构
从下向上如下:

  1. Zend引擎:Zend整体用C语言实现,是PHP的内核部分。它将PHP代码翻译,实现了基本的数据结构,内存分配机制及管理,提供了相应的api供外部调用,是一切的核心。
  2. Extensions:围绕Zend引擎,extensions通过组件式的方式提供各种基础服务,我们常见的各种内置函数、标准库等都是通过extension来实现,用户也可以根据需要实现自己的extension。
  3. Sapi:Aerver Application Programming Interface,即服务端应用编程接口,是PHP和web server的中间层。Sapi通过钩子函数,使PHP能和外部交互数据,这也将PHP和上层应用解耦。
  4. 上层应用:就是我们平时编写的PHP程序,通过不同的sapi方式得到各种各样的应用模式

Sapi

我们常见的Sapi有:

  1. apache2handler:以apache作为webserver,采用mod_PHP模式运行时候的处理方式,也是现在应用最广泛的一种。
  2. fast-cgi:这是webserver和PHP直接的另一种交互方式,也就是大名鼎鼎的fastcgi协议,在最近fastcgi+PHP得到越来越多的应用,也是异步webserver所唯一支持的方式。nginx就是通过php-fpm(fast-cgi)来解析php的。
  3. cli:命令行调用的应用模式

php+apache和php+nginx的区别

apache是通过mod_php来解析php的;nginx是通过php-fpm(fast-cgi)来解析php的。

  1. PHP解释器是否嵌入Web服务器进程内部执行
    mod_php通过嵌入PHP解释器到Apache进程中,只能与Apache配合使用。这种方式的弊端是内存占用大,如处理CSS、JS等静态文件完全没有必要加载解释器;而cgi和fast-cgi以独立的进程的形式出现,只要对应的Web服务器实现cgi或者fast-cgi协议,就能够处理PHP请求。
  2. 单个进程处理的请求数量
    mod_php和fast_cgi的模式在每个进程的生命周期内能够处理多个请求,而cgi 的模式处理一个请求就马上销毁进程,在高并发的场景下cgi 的性能非常糟糕。而fast-cgi也有启动多个进程,占用内存的缺点。

    cgi和fast-cgi是通信协议V1.0和V2.0,而php-cgi和php-fpm是实现了这种协议的程序。所以处理具体请求的是php-cgi或php-fpm,它们遵循fast-cgi协议。

综上,如果对性能有极高的要求,可以将静态请求和动态请求分开,这时Nginx+php-fpm是比较好的选择。

PHP的执行流程

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

PHP变量

PHP是一门弱类型语言,本身不严格区分变量的类型。PHP变量可以分为简单类型(int、string、boolean)、集合类型(array、resource、object)和常量(const)。所有变量在底层都是同一种结构zval。
zval主要由三部分组成:

  • type:指定变量的类型
  • refcount&is_ref:用来实现引用计数
  • value:存储变量的实际数据(核心)。因为要存储多种类型,所以zvalue是一个union,也由此实现了弱类型。

和node.js比较

多进程和单进程

上面有提到,PHP是多进程模型。因此,如果PHP代码损坏,不会拖垮整个服务器。 PHP代码只运行在自己的进程范围中,当某个请求显示错误时,它只对特定的请求产生影响;而在Node.js环境中,所有的请求均在单一的进程服务中,当某个请求导致未知错误时,整个服务器都会受到影响。
以下是PHP和Node.js对处理Http请求时的模型。
php+apache模型
PHP_apache
node.js模型
node.js

多线程和单线程

Node.js 他用的是JavaScript引擎,那么注定它是单线程 ,使用异步方法开辟多个任务,无需像php等待上个任务线程使用结束之后给下个使用;PHP也是单线程但是它借用Apache服务器提供多线程服务。
运行机制对比

在高并发、大数据量时处理方式不同

php: 优化sql,用组件,用缓存,为了让线程尽快结束,进行下一次任务(上下衔接依次执行);
node:单线程、异步、事件驱动。因为运行速度很快并不会等待,所以如果后面用到前面返回的结果,就需要把后面的封装起来,作为一个回调函数执行。
高并发时处理对比