探究PHP底层
探究PHP底层
1、PHP是什么?
PHP 指的是我们从外面看到的一套完整的系统。这听起来有点糊涂,但其实并不复杂(PHP4 内部结构图)。从功能上来分:我们可以分为三部分:
1、 解释器部分(Zend 以引擎),负责对输入代码的分析、翻译和执行;
2、 功能性部分(PHP功能函数以及扩展),负责具体实现语言的各种功能(比如它的函数等等);
3、 接口部分(SAPI),负责同 WEB 服务器的会话等功能。Zend包括了第一部分的全部和第二部分的局部,PHP内核 包括了第二部分的局部和第三部分的全部。他们合起来称之为 PHP 包。Zend
构成了语言的核心,同时也包含了一些最基本的 PHP 预定义函数的实现。PHP 包(内核)则包含了所有创造出语言本身各种显著特性的模块。

(PHP 内部结构图)
从内容模块上来分:我们可以分为四层体系结构:
1)Zend引擎:Zend整体用纯c实现,是php的内核部分,它将php代码翻译(词法、语法解析等一系列编译过程)为可执行opcode的处理并实现相应的处理方法、实现了基本的数据结构(如hashtable、oo)、内存分配及管理、提供了相应的api方法供外部调用,是一切的核心,所有的外围功能均围绕zend实现。
2)Extensions扩展:围绕着zend引擎,extensions通过组件式的方式提供各种基础服务,我们常见的各种内置函数(如array系列)、标准库等都是通过extension来实现,用户也可以根据需要实现自己的extension以达到功能扩展、性能优化等目的(如贴吧正在使用的php中间层、富文本解析就是extension的典型应用)。
3)Sapi :Sapi全称是Server
Application Programming
Interface,也就是服务端应用编程接口,sapi通过一系列钩子函数,使得php可以和外围交互数据,这是php非常优雅和成功的一个设计,通过sapi成功的将php本身和上层应用解耦隔离,php可以不再考虑如何针对不同应用进行兼容,而应用本身也可以针对自己的特点实现不同的处理方式。4)上层应用: 这就是我们平时编写的php程序,通过不同的sapi方式得到各种各样的应用模式,如通过webserver实现web应用、在命令行下以脚本方式运行等等。

(php结构 )
其架构思想:引擎(Zend)+扩展(ext)的模式:降低内部耦合
中间层(sapi):web server和php的通信接口, 隔绝web server和php。
如果php是一辆车,那么
车的框架就是php本身,即是我们外面看到一套完整系统。
Zend是车的引擎(发动机)
Ext下面的各种组件就是车的轮子
Sapi可以看做是公路,车可以跑在不同类型的公路上
而一次php程序的执行就是汽车跑在公路上。
因此,我们需要:性能优异的引擎+合适的车轮+正确的跑道
如前所述,sapi通过通过一系列的接口,使得外部应用可以和php交换数据并可以根据不同应用特点实现特定的处理方法,我们常见的一些sapi有:
1) 、apache2handler 这是以作为,采用模式运行时候的处理方式,也是现在应用最广泛的一种。
2)、cgi :webserverphpfastcgifastcgi+phpwebserver3)、cli :
Sapi的定义及主要接口函数:
- struct _sapi_module_struct {
- char *name; // 名字标识
- char *pretty_name; // 更好理解的名字
- int (*startup)(struct _sapi_module_struct *sapi_module); // 启动函数
- int (*shutdown)(struct _sapi_module_struct *sapi_module); // 关闭方法
- int (*activate)(TSRMLS_D); //激活
- int (*deactivate)(TSRMLS_D); // 停用
- int (*ub_write)(const char *str, unsigned int str_length TSRMLS_DC);
- // 没有缓存的写操作(unbuffered write)
- void (*flush)(void *server_context); // flush
- struct stat *(*get_stat)(TSRMLS_D); // get uid
- char *(*getenv)(char *name, size_t name_len TSRMLS_DC); // getenv
- void (*sapi_error)(int type, const char *error_msg, ...); /* error
- handler */
- int (*header_handler)(sapi_header_struct *sapi_header, sapi_header_op_enum
- op,
- sapi_headers_struct *sapi_headers TSRMLS_DC); /* header handler */
- /* send headers handler */
- int (*send_headers)(sapi_headers_struct *sapi_headers TSRMLS_DC);
- void (*send_header)(sapi_header_struct *sapi_header,
- void *server_context TSRMLS_DC); /* send header handler */
- int (*read_post)(char *buffer, uint count_bytes TSRMLS_DC); /* read POST
- data */
- char *(*read_cookies)(TSRMLS_D); /* read Cookies */
- /* register server variables */
- void (*register_server_variables)(zval *track_vars_array TSRMLS_DC);
- void (*log_message)(char *message); /* Log message */
- time_t (*get_request_time)(TSRMLS_D); /* Request Time */
- void (*terminate_process)(TSRMLS_D); /* Child Terminate */
- char *php_ini_path_override; //覆盖ini路径
- ...
- ...
- };
这里介绍一下其中一些主要函数
· startup:php被调用时初始化操作,比如cgi模式,在startup的时候会加载所有的extension并执行模块初始化工作。
· shutdown:php关闭时收尾工作
· activate:请求初始化
· dectivate:请求结束时收尾工作
· ub_write:指定数据输出方式,比如apache2handler方式,由于php作为apache的一个so存在,因此其输出也就是调
用apache的ap_write函数,而在cgi模式下,会系统调用write。
· sapi_error:错误处理函数
· read_post:读取post数据
· register_server_variables:往$_SERVER中注册环境变量这个一般根据不同协议标准注册注册的变量。
在php源码中,sapi实现了很多接口:如下图:

4、php脚本的执行
SAPI处于PHP架构的上层,而真正的脚本执行是有Zend引擎来完成。
目前语言分为两类:
第一类:编译型语言.如c/c++ Java之类,他们的共性是运行之前必须对源代码进行编译,然后运行编译后的目标文件。
第二类语言:解释型语言:如PHP,Ruby,Python。他们需要解释器来执行这些源代码。实际上这些语言还是要经过编译环节的。只不过他们在运行的时候进行编译,为了效率,并不是每次执行的时候都会重新编译,比如PHP的各种opcode缓存扩展(如APC Xcache等)。
说明:PHP从2000年发布的PHP4开始就不是解释性语言。当一个PHP脚本被执行的时候,首先PHP源代码由Zend引擎编译成名为Zend opcodes的机器代码。这些代码保存在RAM中。然后执行opcodes运行真正的脚本。因此,PHP实际上和Java,C#等语言一样是编译语言。否则,它的执行会很慢。
我们来看PHP脚本是怎么被执行的。如hello.php:
- <?php
- $str = "Hello world!\n";
- echo $str;
命令行执行:php hello.php
输出结果显然是:Hello world!
但是执行脚本的时候,PHP/Zend做了什么呢?
4.1、程序的执行:
1)传递给php程序需要的执行文件hello.php,php程序完成基本的准备工作后启动PHP及Zend引擎,加载注册的扩展模块。
2) 初始化完后读取脚本文件,Zend引擎对脚本进行此词法分析,语法分析,然后有Zend引擎编译成opcode码,最后执行 opcode码。
php代码的执行过程如下图:

php实现了一个典型的动态语言执行过程:拿到一段代码后,经过词法解析、语法解析等阶段后,源程序会被翻译成一个个指令(opcodes),然后ZEND虚拟机顺次执行这些指令完成操作。PHP本身是用c实现的,因此最终调用的也都是c的函数,实际上,我们可以把php看做是一个c开发的软件。
通过上面描述不难看出,php的执行的核心是翻译出来的一条一条指令,也即opcode.
4.2、词法分析和语法分析
解释器一般包括两部分:
1)、 读取源程序,并处理语言结构
2)、处于语言结构并生成目标程序
而Lex和Yacc可以解决第一个问题。很多编程都有Lex/Yacc作为语言的词法语法分析生成器,比如PHP,Python、Ruby已经MySQL的sql语言。
Lex生成词法分析器。
Yacc语法分析生成器
4. 3、opcode
PHP 构建在Zend虚拟机(Zend VM)之上的,PHP的opcode就是ZEND 虚拟机中的指令,即Opcode是php程序执行的最基本单位。
探究PHP底层的更多相关文章
- WinDbg探究CLR底层(1) - 应用程序域
一.什么是应用程序域 操作系统由于其稳定性与可靠性的要求,都会使用隔离层,来确保运行在某个隔离层内的代码不会对其他隔扇层的代码产生影响.如Windows通过进程来实现这种隔离机制,所能的可执行代码.数 ...
- 6.Docker容器底层实现了解与安全机制
原文地址: 点击直达 0x00 底层实现 我们以 Docker 基础架构来探究Docke底层的核心技术,简单的包括: Linux 上的命名空间(Namespaces) 控制组(Control grou ...
- ubuntu 下dbus的环境搭建和使用
从https://launchpad.net/ubuntu/+source/dbus/1.10.6-1ubuntu2下载需要的dbus包,然后解压,./configure make && ...
- 微软.NET各子技术领域的应用前景
从2002年微软发布.NET 1.0,其间历经了8年的发展,再到.NET 4.0,其已经成为一个庞大而复杂的软件开发与运行平台,架构日益复杂,应用领域也在不断地扩展,包容了“一堆”的子技术领域. 在. ...
- Java中ArrayList的删除元素总结
Java中循环遍历元素,一般有for循环遍历,foreach循环遍历,iterator遍历. 先定义一个List对象 List<String> list = new ArrayList&l ...
- FPGA基础学习(7) -- 内部结构之CLB
目录 1. 总览 2. 可配置逻辑单元 2.1 6输入查找表(LUT6) 2.2 选择器(MUX) 2.3 进位链(Carry Chain) 2.4 触发器(Flip-Flop) 参考文献: 一直以来 ...
- Google论文BigTable拜读
这周少打点dota2,争取把这篇论文读懂并呈现出来,和大家一起分享. 先把论文搞懂,然后再看下和论文搭界的知识,比如hbase,Chubby和Paxos算法. Bigtable: A Distribu ...
- 职业规划 - DREAM START
前言 最近面试了好多公司,得出一个结论:做一份详细的计划.一个程序员,不只是写写代码这么简单的事,一种更高的境界则是在代码中.系统的设计中,能找到人生的意义,简单说就是生活的道理.我一直认为:当你在一 ...
- 浅谈Spring中JDK动态代理与CGLIB动态代理
前言Spring是Java程序员基本不可能绕开的一个框架,它的核心思想是IOC(控制反转)和AOP(面向切面编程).在Spring中这两个核心思想都是基于设计模式实现的,IOC思想的实现基于工厂模式, ...
随机推荐
- 写了一个bug,最后却变成了feature,要不要修呢?
事情是这样子的,前不久接到一个需求,为一个游戏开发礼包码功能 通常一款游戏运营期间会搞各种各样的活动吸引玩家,其中最常见的就是发放礼包, 玩家可以通过礼包码兑换礼包. 用礼包码兑换礼包有个一限制,游 ...
- Path.Combine 合并两个路径字符串,会出现的问题
Path.Combine(path1,path2) 1.如果path2字符串,以 \ 或 / 开头,则直接返回 path2
- 读《你不知道的JavaScript(上卷)》后感-作用域闭包(二)
github原文 一. 序言 最近我在读一本书:<你不知道的JavaScript>,这书分为上中卷,内容非常丰富,认真细读,能学到非常多JavaScript的知识点,希望广大的前端同胞们, ...
- linq 在查询表达式中处理 null 值
此示例显示如何在源集合中处理可能的 null 值. IEnumerable<T> 等对象集合可包含值为 null 的元素. 如果源集合为 null 或包含值为 null 的元素,并且查询不 ...
- 机器翻译评测——BLEU改进后的NIST算法
◆版权声明:本文出自胖喵~的博客,转载必须注明出处. 转载请注明出处:http://www.cnblogs.com/by-dream/p/7765345.html 上一节介绍了BLEU算的缺陷.NIS ...
- n! 进制
n! 进制 Time limit per test: 1.0 seconds Time limit all tests: 1.0 seconds Memory limit: 256 megabytes ...
- Jumpserver部署与安装
jumpserver特点: 完全开源,GPL授权 Python编写,容易再次开发 实现了跳板机基本功能,认证.授权.审计 集成了Ansible,批量命令等 支持WebTerminal Bootstra ...
- 网页静态化技术Freemarker的详细介绍
网页静态化技术Freemarker 一.Freemarker的基本介绍 1.1为什么要使用网页静态化技术 网页静态化解决方案在实际开发中运用比较多,例如新闻网站,门户网站中的新闻频道或者是文章类的频道 ...
- Maven快速使用阿里云的代理maven仓库
自从开源中国的maven仓库挂了之后就一直在用国外的仓库,慢得想要砸电脑的心都有了.如果你和我一样受够了国外maven仓库的龟速下载?快试试阿里云提供的maven仓库,从此不在浪费生命…… 仓库地址: ...
- 如何实现border-width:0.5px;
工作中遇到了一个产品需求,要求把列表分割线改成0.5px,直接写成border:0.5px solid #cccccc;是不符合规范的写法,会存在Android和IOS手机上的兼容问题,故,我们可以利 ...