当前位置:首页 > 商讯 >

深入理解PHP代码的执行的过程

作者:永年县聚联紧固件制造有限公司    发布时间:2017-09-09 10:31:31

深入理解PHP代码的执行的过程 一、前言

语言是人们进行沟通和交流的表达符号,每种语言都有专属于自己的符号,表达方式和规则。 就编程语言来说,它也是由特定的符号,特定的表达方式和规则组成。语言的作用是沟通,不管是自然语言,还是编程语言,它们的区别在于自然语言是人与人之间沟通的工具, 而编程语言是人与机器之间的沟通渠道。

就PHP语言来说,它也是一组符合一定规则的约定的指令。 在编程人员将自己的想法以PHP语言实现后,通过PHP的虚拟机(确切的来说应该是PHP的语言引擎Zend)将这些PHP指令转变成C语言 (可以理解为更底层的一种指令集)指令,而C语言又会转变成汇编语言, 最后汇编语言将根据处理器的规则转变成机器码执行。这是一个更高层次抽象的不断具体化,不断细化的过程。

从一种语言到另一种语言的转化称之为编译,这两种语言分别可以称之为源语言和目标语言。 这种编译过程通过发生在目标语言比源语言更低级(或者说更底层)。 语言转化的编译过程是由编译器来完成, 编码器通常被分为一系列的过程:词法分析、语法分析、语义分析、中间代码生成、代码优化、目标代码生成等。 前面几个阶段(词法分析、语法分析和语义分析)的作用是分析源程序,我们可以称之为编译器的前端。 后面的几个阶段(中间代码生成、代码优化和目标代码生成)的作用是构造目标程序,我们可以称之为编译器的后端。 一种语言被称为编译类语言,一般是由于在程序执行之前有一个翻译的过程, 其中关键点是有一个形式上完全不同的等价程序生成。 而PHP之所以被称为解释类语言,就是因为并没有这样的一个程序生成, 它生成的是中间代码Opcode,这只是PHP的一种内部数据结构。

二、 PHP代码的执行的过程

比如我们写一个简单的程序

这个简单的程序他执行过程是怎样的呢?其实,执行过程也正如我们前面所说分为4个步骤。(这里只是指PHP语言引擎Zend执行过程,不包含Web服务器的执行过程。) 1.Scanning(Lexing) ,将PHP代码转换为语言片段(Tokens) 2.Parsing, 将Tokens转换成简单而有意义的表达式 3.Compilation, 将表达式编译成Opocdes 4.Execution, 顺次执行Opcodes,每次一条,从而实现PHP脚本的功能。

注1:Opcode是一种PHP脚本编译后的中间语言,就像Java的ByteCode,或者.NET的MSL

注2:现在有的Cache比如APC,可以使得PHP缓存住Opcodes,这样,每次有请求来临的时候,就不需要重复执行前面3步,从而能大幅的提高PHP的执行速度。

1. Scanning(Lexing),将PHP代码转换为语言片段(Tokens)

那什么是Lexing? 学过编译原理的同学都应该对编译原理中的词法分析步骤有所了解,Lex就是一个词法分析的依据表。

对于PHP在开始使用的是Flex,之后改为re2c, MySQL的词法分析使用的Flex,除此之外还有作为UNIX系统标准词法分析器的Lex等。 这些工具都会读进一个代表词法分析器规则的输入字符串流,然后输出以C语言实做的词法分析器源代码。 这里我们只介绍PHP的现版词法分析器,re2c。 在源码目录下的Zend/zend_language_scanner.l 文件是re2c的规则文件, 如果需要修改该规则文件需要安装re2c才能重新编译,生成新的规则文件。Zend/zend_language_scanner.c会根据Zend/zend_language_scanner.l,来输入的 PHP代码进行词法分析,从而得到一个一个的“词”。

从PHP4.2开始提供了一个函数叫token_get_all,这个函数就可以将一段PHP代码 Scanning成Tokens;

我们用下面的代码使用token_get_all函数处理我们开头提到的PHP代码。

PHPCODE; // $tokens = token_get_all($phpcontent); // print_r($tokens); $tokens = token_get_all($phpcode); foreach ($tokens as $key => $token) { $tokens[$key][0] = token_name($token[0]); } print_r($tokens); ?>

注:为了便于理解和查看,我使用token_name函数将解析器代号修改成了符号名称说明。

如果有的童鞋想要看原始的,可以将上面代码中的第10,11行代码注释去掉。

解释器代号列表详见:http://www.php.net/manual/zh/tokens.php

得到的结果如下:

Array ( [0] => Array ( [0] => T_OPEN_TAG [1] => 1 ) [1] => Array ( [0] => T_WHITESPACE [1] => [2] => 2 ) [2] => Array ( [0] => T_ECHO [1] => echo [2] => 2 ) [3] => Array ( [0] => T_WHITESPACE [1] => [2] => 2 ) [4] => Array ( [0] => T_CONSTANT_ENCAPSED_STRING [1] => "Hello World!" [2] => 2 ) [5] => [6] => Array ( [0] => T_WHITESPACE [1] => [2] => 2 ) [7] => [8] => Array ( [0] => T_WHITESPACE [1] => [2] => 3 ) [9] => Array ( [0] => T_LNUMBER [1] => 1 [2] => 3 ) [10] => Array ( [0] => T_WHITESPACE [1] => [2] => 3 ) [11] => [12] => Array ( [0] => T_WHITESPACE [1] => [2] => 3 ) [13] => Array ( [0] => T_LNUMBER [1] => 1 [2] => 3 ) [14] => [15] => Array ( [0] => T_WHITESPACE [1] => [2] => 3 ) [16] => Array ( [0] => T_ECHO [1] => echo [2] => 4 ) [17] => Array ( [0] => T_WHITESPACE [1] => [2] => 4 ) [18] => [19] => Array ( [0] => T_WHITESPACE [1] => [2] => 4 ) [20] => Array ( [0] => T_CLOSE_TAG [1] => ?> [2] => 5 ) )

分析这个返回结果我们可以发现,源码中的字符串,字符,空格都会原样返回。

每个源代码中的字符,都会出现在相应的顺序处。

而其他的,比如标签,操作符,语句,都会被转换成一个包含三部分的

1、Token ID解释器代号 (也就是在Zend内部的改Token的对应码,比如,T_ECHO,T_STRING)

2、源码中的原来的内容

3、该词在源码中是第几行。

2. Parsing, 将Tokens转换成简单而有意义的表达式

接下来,就是Parsing阶段了,Parsing首先会丢弃Tokens Array中的多于的空格,

然后将剩余的Tokens转换成一个一个的简单的表达式

1.echo a constant string 2.add two numbers together 3.store the result of the prior expression to a variable 4.echo a variable

Bison是一种通用目的的分析器生成器。它将LALR(1)上下文无关文法的描述转化成分析该文法的C程序。 使用它可以生成解释器,编译器,协议实现等多种程序。 Bison向上兼容Yacc,所有书写正确的Yacc语法都应该可以不加修改地在Bison下工作。 它不但与Yacc兼容还具有许多Yacc不具备的特性。

企业建站2800元起,携手武汉肥猫科技,做一个有见地的颜值派!更多优惠请戳:孝感SEO http://xiaogan.raoyu.net

  • 上一篇:asp.net中c# byte[] 转换为 IntPtr几种方法
  • 下一篇:最后一页
  •