PHP的运行时与解释

PHP解释器与Web Server

PHP解释器可以独立运行,从而应用在与Web完全无关的场合,就像其它通用语言一样。但本段文字关注与Web Server共同使用的场合。

web 服务器可以用三种方法来利用 PHP 生成 web 页面:

第一种方法是将 PHP 用作一个单独运行的语言解释器(CGI Wapper)。以这种方法运行,PHP 会为向 web 服务器提出的每个 PHP 页面请求生成并结束一个 PHP解释器线程。由于该线程会随每个请求的结束而结束,因此任何在这个线程中利用的任何资源(例如指向SQL 数据库服务器的连接)都会随线程的结束而关闭。在这种情况下,使用持久连接和非持久连接没有任何区别——因为PHP脚本本身的执行不是持久的。

第二,也是最常用的方法,是把 PHP 用作多进程 web 服务器的一个模块,这种方法目前只适用于 Apache。对于一个多进程的服务器,其典型特征是有一个父进程和一组子进程协调运行,其中实际生成 web 页面的是子进程。每当客户端向父进程提出请求时,该请求会被传递给还没有被其它的客户端请求占用的子进程。这也就是说当相同的客户端第二次向服务端提出请求时,它将有可能被一个不同的子进程来处理。在开启了一个持久连接后,所有请求 SQL 服务的后继页面都能够重用这个已经建立的 SQL Server 连接。

最后一种方法是将 PHP 用作多线程 web 服务器的一个插件。目前 PHP 4 已经支持 ISAPI、WSAPI 和 NSAPI(在非Windows 环境下),这些使得 PHP 可以被用作诸如 Netscape FastTrack (iPlanet)、Microsoft's Internet Information Server (IIS) 和 O'Reilly's WebSite Pro 等多线程 web 服务器的插件。

来源: https://secure.php.net/manual/zh/features.persistent-connections.php

无论使用何种方式,均涉及到PHP与Web Server(以及CLI)的通信,这一通信过程遵循一定协议,如CGI/FastCGI/ISAPI等等,它们统称SAPI。任何想把输出结果交给Web Server的程序解释器都会使用类似的协议,例如Python解释器同样通过FastCGI协议与Web Server通信。

PHP-FPM

当前的主流做法是,Web Server(如Nginx)将收到的HTTP请求通过本机端口交给 PHP-FPM 这一独立的PHP进程管理软件(PHP-FPM使用的协议是FastCGI)。PHP-FPM会创建一个主进程,该进程控制何时以及如何把HTTP请求转发给它的一个或多个PHP子进程,以及什么时候创建和销毁子进程。PHP-FPM进程池中的每个进程存在的时间比单个HTTP请求长,可以处理上百个HTTP请求。可以通过配置文件来配置PHP-FPM的行为。

字节码缓存——OPcache

现代的PHP解释器通常不直接解释PHP源代码,因为PHP源代码文件可以被预编译为字节码,从而加快一次程序执行的速度。PHP 5.5起内置了一个Zend Opcache扩展,该扩展可以在内存中缓存字节码。通过模块OPcache可以在运行时控制它的行为。

PHP7中在字节码后加入一道JIT流程,效率更高。

通过php.ini以及其他方式配置解释器的行为

可以通过配置文件php.ini来配置PHP解释器的行为。该文件视情况,可散落在文件系统的各处,例如,如果通过PHP-FPM运行PHP解释器,则php.ini在/etc/php5/fpm中;如果通过bash来调用PHP解释器,则解释器行为由/etc/php5/cli中的php.ini控制。不同情况下,php.ini被使用的方式也不同,例如,如果PHP解释器作为Web Server的模块被使用,则该文件只在Web Server被启动时被读取一遍,而对于作为 CGI 和 CLI 版本,每次调用都会读取。

除了通过php.ini,也可以通过其它方式修改配置,例如在运行时通过函数iniset进行、通过Web Server的配置文件进行,等等。每个配置选项都有一个“配置模式”,决定了该 PHP 配置项是否能够以及通过何种方式被设定,例如,配置模式为“PHPINISYSTEM”的选项不能在运行时通过iniset函数配置。

与优化相关的配置项

  • 通过配置项memory_limit可以设定单个PHP进程可以使用的最大内存
  • 与Zend OPcache有关的配置项以“opcache”开头。可以配置缓存的字节码占用的内存、驻留字符串(interned string,程序中在不同地方使用的同一内容的字符串在内存中只创建一个)的大小、为几个PHP文件创建字节码缓存、字节码缓存是否更新以及更新时间(建议在生产环境中禁止更新缓存)
  • 通过配置与文件上传有关的配置项(一般名字里带“file”字样),可以防止PHP处理用户上传的过大或过多的文件
  • 最长执行时间maxexcutiontime:配置一次PHP执行过程所花费的最长时间,默认30秒,建议改成5秒。对于请求触发的耗时任务应当以异步的形式进行
  • 对session处理方式的配置:默认的PHP session处理程序总是在硬盘上进行,应当引入redis或memcached等内存数据库来进行。通过session.save_handler等选项来配置
  • 配置缓冲取大小:PHP在返回程序输出结果给Web Server时,会先在缓冲区里积累一定量的数据后再发给Web Server。通过配置outputbuffering和implictflush可以配置相关行为
  • 配置路径缓存区的大小:PHP在导入(include)文件时有个按一定路径搜寻指定文件的过程(见《语法、表达式、语句与操作符》中“文件寻找路径 ”一节),通过路径缓存机制可以缩短搜索过程。配置项realpathcachesize

垃圾回收

见官方文档http://php.net/manual/zh/features.gc.php

扩展和库

PHP中的“扩展”指的是使用 C 编写并编译进PHP解释器的外部代码。关于扩展,官方文档提供了一个列表,更多的扩展可以见pecl.php.net,按归属分:

  • 核心扩展库,并非真正的扩展库,它们属于 PHP 内核的一部分,即使从源码编译PHP解释器,也不能通过编译选项将其排除
  • 绑定的扩展库,绑定在编译好的 PHP 发行包中
  • 外部扩展库,已经包含在PHP中但是需要编译它们才能使用,并且可能需要额外的扩展库
  • PECL 扩展库,可以通过 pecl 命令安装,或者下载源码自行编译安装

以PHP代码形式提供的第三方代码一般被叫做“包”或“库”,发布在社区中的包的列表可以见Packagist。目前一般使用composer作为包管理器,以代替早期的包管理器pear。