探究PHP底层

1、PHP是什么?

PHP 指的是我们从外面看到的一套完整的系统。这听起来有点糊涂,但其实并不复杂(PHP4 内部结构图)。从功能上来分:我们可以分为三部分:

1、 解释器部分(Zend 以引擎),负责对输入代码的分析、翻译和执行;
2、 功能性部分(PHP功能函数以及扩展),负责具体实现语言的各种功能(比如它的函数等等);
3、 接口部分(SAPI),负责同 WEB 服务器的会话等功能。

Zend包括了第一部分的全部和第二部分的局部,PHP内核 包括了第二部分的局部和第三部分的全部。他们合起来称之为 PHP 包。Zend 构成了语言的核心,同时也包含了一些最基本的 PHP 预定义函数的实现。PHP 包(内核)则包含了所有创造出语言本身各种显著特性的模块。

                  1.png

                                       

                                                                                                     (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应用、在命令行下以脚本方式运行等等。

          2.jpg

                                                                              (php结构 )

其架构思想:引擎(Zend)+扩展(ext)的模式:降低内部耦合

                         中间层(sapi):web server和php的通信接口, 隔绝web server和php。

如果php是一辆车,那么

车的框架就是php本身,即是我们外面看到一套完整系统。

Zend是车的引擎(发动机)

Ext下面的各种组件就是车的轮子

Sapi可以看做是公路,车可以跑在不同类型的公路上

而一次php程序的执行就是汽车跑在公路上。

因此,我们需要:性能优异的引擎+合适的车轮+正确的跑道

2、php生命周期

      查看:深入理解php底层:php生命周期 :http://blog.csdn.net/hguisu/article/details/7377520

3 、sapi

      如前所述,sapi通过通过一系列的接口,使得外部应用可以和php交换数据并可以根据不同应用特点实现特定的处理方法,我们常见的一些sapi有:

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

2)、cgi :这是webserverphp直接的另一种交互方式,也就是大名鼎鼎的fastcgi协议,在最近今年fastcgi+php得到越来越多的应用,也是异步webserver所唯一支持的方式。

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

如图:Sapi的简单示意图:

                                       3.jpg

 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路径  
   
    ...  
    ...  
};

这里介绍一下其中一些主要函数

· startupphp被调用时初始化操作,比如cgi模式,在startup的时候会加载所有的extension并执行模块初始化工作。

· shutdownphp关闭时收尾工作

· activate:请求初始化

· dectivate:请求结束时收尾工作

· ub_write:指定数据输出方式,比如apache2handler方式,由于php作为apache的一个so存在,因此其输出也就是调                          用apacheap_write函数,而在cgi模式下,会系统调用write

·  sapi_error:错误处理函数

·  read_post:读取post数据

·  register_server_variables:往$_SERVER中注册环境变量这个一般根据不同协议标准注册注册的变量。

在php源码中,sapi实现了很多接口:如下图:

4.jpg

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代码的执行过程如下图:

                           5.jpg


        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程序执行的最基本单位。

转自:http://blog.csdn.net/hguisu/article/details/7394430

原创文章,作者:s19930811,如若转载,请注明出处:http://www.178linux.com/3045

(1)
s19930811s19930811
上一篇 2015-04-10
下一篇 2015-04-12

相关推荐

  • N28-第四周博客作业

    1、复制/etc/skel目录为/home/tuser1,要求/home/tuser1及其内部文件的属组和其它用户均没有任何访问权限。

    2、编辑/etc/group文件,添加组hadoop。

    3、手动编辑/etc/passwd文件新增一行,添加用户hadoop,其基本组ID为hadoop组的id号;其家目录为/home/hadoop。

    4、复制/etc/skel目录为/home/hadoop,要求修改hadoop目录的属组和其它用户没有任何访问权限。

    5、修改/home/hadoop目录及其内部所有文件的属主为hadoop,属组为hadoop。

    6、显示/proc/meminfo文件中以大写或小写S开头的行;用两种方式;

    7、显示/etc/passwd文件中其默认shell为非/sbin/nologin的用户;

    8、显示/etc/passwd文件中其默认shell为/bin/bash的用户;

    9、找出/etc/passwd文件中的一位数或两位数;

    10、显示/boot/grub/grub.conf中以至少一个空白字符开头的行;

    11、显示/etc/rc.d/rc.sysinit文件中以#开头,后面跟至少一个空白字符,而后又有至少一个非空白字符的行;

    12、打出netstat -tan命令执行结果中以‘LISTEN’,后或跟空白字符结尾的行;

    13、添加用户bash, testbash, basher, nologin (此一个用户的shell为/sbin/nologin),而后找出当前系统上其用户名和默认shell相同的用户的信息;

    Linux干货 2017-12-26
  • 基于BIND实现的DNS正反解析及主从DNS的配置

    基于BIND实现的DNS正反解析及主从DNS的配置 标签: DNS正反解析 DNS主从复制 测试环境 准备2台虚拟机,一台为主DNS,IP地址为:192.168.103.161。另一台为从DNS,IP地址为:192.168.103.162两台都装好bind,所需包有:bind,bind-utils,bind-libs 主DNS的配置文件 配置主文件/etc/…

    Linux干货 2016-04-11
  • 三剑客-sed小结

     sed是一款流编辑器工具,通常我们用来对文本进行过滤与替换操作,特别是当你想要对几十个配置文件做统一更改时,你会感受到sed的魅力。它一次处理一行内容。处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直到…

    系统运维 2016-07-26
  • linux防火墙介绍

    一、前言firewall(防火墙):工作在网络进入或者流包,进出的网络数据包进行一定的规则进行检查过滤系统。包括iptables和netfilter组件。iptables 是与 Linux 内核集成的 IP 信息包过滤系统。如果 Linux 系统连接到因特网或 LAN、服务器或连接 LAN 和因特网的代理服务器, 则该系统系统中更好地控制 IP 信息包过滤和…

    2017-04-30
  • Linux文件查找工具之find “大宝剑”

    一、文件查找工具常用软件 locate:     locate命令其实是find -name的另一种写法,但是要比后者快得多,原因在于它不搜索具体目录,而是搜索一个数据库/var/lib/locatedb,这个数据库中含有本地所有文件信息。Linux系统自动创建这个数据库,并且每天自动更新一次,所以使用locate命令…

    Linux干货 2016-03-12
  • linux基础知识:计算机的组成及其功能

    摘要:
    1. 描述计算机的组成及其功能。
    2. 按系列罗列Linux的发行版,并描述不同发行版之间的联系与区别。
    3. 描述Linux的哲学思想,按照自己的理解对其解释性描述。
    4. 说明Linux系统上命令的使用格式;详细介绍ifconfig、echo、……等命令使用,配合相应实例阐述。
    5. 如何获取帮助信息,描述man文档章节划分。
    6. 罗列发行版基础目录名称命名法则及功用规定。

    2017-12-03