原文地址:https://support.cloud.engineyard.com/hc/en-us/articles/205411888-PHP-Performance-I-Everything-You-Need-to-Know-About-OpCode-Caches

The Execution Life-cycle

  PHP is a scripting language, which most people take to mean that it is not compiled. While this is true in the traditional sense in that we are not calling a gcc or javac; instead we are compiling every time the script is requested. In fact, the PHP and Java compilation life cycles are pretty similar, because they both compile to an intermediary instruction set (opcodes, or bytecodes) which are then run in a virtual machine (Zend VM or JVM).

The parsing and compilation phases is slow. When we add an opcache, we short-circuit this process by storing the result of the parsing and compilation phases, leaving just the execution to run dynamically as always. In effect, we are closer to the Java life-cycle now; with the main differences being that we saved to shared memory instead of a file, and can automatically re-compile if changes occur to the script.

Tokens & OpCodes

Once PHP gets ahold of your code, it creates two representations of your code.  The first is tokens; this is a way to break down your code into consumable chunks for the engine to compile into it’s second representation, opcodes. The opcodes are the actual instructions for the Zend VM to execute.

The Worst Hello World Ever

Taking a simple code example, a vastly over-engineered hello world example, lets look at both tokens, and opcodes.

<?php
class Greeting {
public function sayHello($to)
{
echo "Hello $to";
}
}
$greeter = new Greeting();
$greeter->sayHello("World");
?>

  

Tokenizing

The first part of the compilation process parses the code into tokens. These are passed to the compiler to create OpCodes.

Token Name

Value

T_OPEN_TAG

<?php

T_CLASS

class

T_WHITESPACE

 

T_STRING

Greeting

T_WHITESPACE

 
 

{

T_WHITESPACE

 

T_PUBLIC

public

T_WHITESPACE

 

T_FUNCTION

function

T_WHITESPACE

 

T_STRING

sayHello

 

(

T_VARIABLE

$to

 

)

T_WHITESPACE

 
 

{

T_WHITESPACE

 

T_ECHO

echo

T_WHITESPACE

 
 

"

T_ENCAPSED_AND_WHITESPACE

Hello

T_VARIABLE

$to

 

"

 

;

T_WHITESPACE

 
 

}

T_WHITESPACE

 
 

}

T_WHITESPACE

 

T_VARIABLE

$greeter

T_WHITESPACE

 
 

=

T_WHITESPACE

 

T_NEW

new

T_WHITESPACE

 

T_STRING

Greeting

 

(

 

)

 

;

T_WHITESPACE

 

T_VARIABLE

$greeter

T_OBJECT_OPERATOR

->

T_STRING

sayHello

 

(

T_CONSTANT_ENCAPSED_STRING

"World"

 

)

 

;

T_WHITESPACE

 

T_CLOSE_TAG

?>

As you can see, most discrete piece of the code is given a name, starting with T_ and then a descriptive name. This is where the infamous T_PAAMAYIM_NEKUDOTAYIM error comes from: it represents the double colon.

Some tokens do not have a T_ name, this is because they are a single character — it would obviously wasteful to then assign them a much larger name — T_DOUBLE_QUOTE or T_SEMICOLON don’t make much sense.

It is also interesting to see the difference interpolation of variables makes; take the two strings, both double quotes, "Hello $to" and "World", the first, to account for the interpolated variables is split into 4 unique opcodes:

 

"

T_ENCAPSED_AND_WHITESPACE

Hello

T_VARIABLE

$to

 

"

and the non-interpolated string is simply one:

T_CONSTANT_ENCAPSED_STRING

"World"

With this view we can start to see how small choices we make start to affect performance in miniscule ways (and frankly, especiallyin this case, as with single Vs double quotes, it’s not worth caring about!)

You can see the script that was used to generate this list of tokens here.

OpCodes

Next, lets look at how this looks like once we have compiled to opcodes. This is what the OpCode caches store.

To get the opcodes, we run the script through VLD, the Vulcan Logic Dumper, a pecl extension for PHP. To install it simple run:

$ pecl install vld-beta

And make sure the following is added to your PHP config:

  extension=vld.so
view raw19-vld.ini hosted with ❤ by GitHub

Once you’ve done this, you can dump the opcodes for any code using the following on the command line:

$ php -dvld.active=1 -dvld.execute=0 <file>

VLD dumps global code (main script), global functions, and then class functions. However we’re going to look at our class functions first so as follow the same flow as the code itself.

Understanding VLD Dumps

A VLD dump is typically multiple dumps, one for the main script, then one for each global function and class function. Each dump is identical in structure.

First is the header which lists (if applicable) the class, and the function; then it lists the filename. Next it lists the function name (again, and only if applicable).

  Class Greeting:
  Function sayhello:
  filename: ./Greeting.php
  function name: sayHello
view raw21-vld-output-1.txt hosted with ❤ by GitHub

Next, it lists the total number of opcodes in the dump:

  number of ops: 8
view raw22-vld-output-2.txt hosted with ❤ by GitHub

And then it lists the compiled variables (see below for details):

  compiled vars: !0 = $to
view raw23-vld-output-3.txt hosted with ❤ by GitHub

This is particularly important to take notice of.

Finally, it actually lists the opcodes, one per line, under the heading row:

  line # * op fetch ext return operands
  ------------------------------------------------------------------------
view raw24-vld-output-4.txt hosted with ❤ by GitHub

Each opcode has the following:

  • line: The line number in the source file
  • #: The opcode number
  • *: entry (left aligned) and exit points (right aligned), indicated by greater than symbols (>)
  • op: The opcode name
  • fetch: Details on global variable fetches (super globals, or the use of the global keyword)
  • ext: Extra data associated with the opcode, for example the opcode to which it should JMP
  • return: The location where return data from the operation is stored
  • operands: the operands used by the opcode (e.g. two variables to concat)

Note: Not all columns are applicable to all opcodes.

Variables

There are multiple types of variables within the Zend Engine. All variables use numeric identifiers.

  1. Variable prefixed with an exclamation point (!) are compiled variables (CVs) — these are pointers to userland variables
  2. Variables prefixed with a tilde (~) are temporary variables used for temporary storage (TMP_VARs) of in-process operations
  3. Variables prefixed with a dollar ($) are another type of temporary variables (VARs) which are tied to userland variables like CVs and therefore require things like refcounting.
  4. Variables prefixed with a colon (:) are  temporary variables used for the storage of the result of lookups in the class hashtable

Dumping Hello World

  Class Greeting:
  Function sayhello:
  number of ops: 8
  compiled vars: !0 = $to
   
  line # * op fetch ext return operands
  ----------------------------------------------------------------------------
  3 0 > EXT_NOP
  1 RECV !0
  5 2 EXT_STMT
  3 ADD_STRING ~0 'Hello+'
  4 ADD_VAR ~0 ~0, !0
  5 ECHO ~0
  6 6 EXT_STMT
  7 > RETURN null

Reading this, we see that we’re in the function sayHello of the class Greeting, and that we have one compiled variable, $to, which is identified by !0.

Next, following the list of opcodes (ignoring the no-op), we can see that:

  • RECV: The function receives a value which is assigned to !0 (which represents $to)
  • ADD_STRING: Next we create a temporary variable identified by a ~~0 and assign the static string, 'Hello+', where the +represents a space
  • ADD_VAR: After this, we concat the contents our variable, !0 to our temporary variable, ~0
  • ECHO: Then we echo that temporary variable
  • RETURN: Finally we return nothing as the function ends

Next, lets look at the main script:

Here we see one compiled variable, $greeter, identified by !0. So lets walk through this, again we’ll ignore the no-op.

  • FETCH_CLASS: First we lookup the class, Greeter; we store this reference in :1
  • NEW: Then we instantiate an instance of the class (:1) and assign it to a VAR$2, and
  • DO_FCALL_BY_NAME: call the constructor
  • ASSIGN: Next we assign the resulting object (in VAR $2) to our CV (!0)
  • INIT_METHOD_CALL: We start calling the sayHello method, and
  • SEND_VAL: pass in 'World' to the method, and
  • DO_FCALL_BY_NAME: Actually execute the method
  • RETURN: The script ends successfully, with an implicit return of 1.

php script 的生命周期的更多相关文章

  1. react9 生命周期

    <body><!-- React 真实 DOM 将会插入到这里 --><div id="example"></div> <!- ...

  2. Vue实例及生命周期

    1,Vue实例生命周期. 有时候,我们需要在实例创建过程中进行一些初始化的工作,以帮助我们完成项目中更复杂更丰富的需求,开发,针对这样的需求,Vue提供给我们一系列的钩子函数 2,Vue生命周期的阶段 ...

  3. MonoBehaviour Lifecycle(生命周期/脚本执行顺序)

    脚本执行顺序 前言 搭建一个示例来验证Unity脚本的执行顺序,大概测试以下部分: 物理方面(Physics) 渲染(Scene rendering) 输入事件(InputEvent) 流程图 Uni ...

  4. ReactJS入门(二)—— 组件的生命周期

    如果你熟悉avalon,使用过 data-include-rendered 和 data-include-loaded 等回调方法,那么你会很好地理解React组件的各个生命周期. 说白了其实就是Re ...

  5. vue生命周期

    1.Vue1.0生命周期 1.1钩子函数: created ->   实例已经创建 √ beforeCompile ->   编译之前 compiled ->   编译之后 read ...

  6. 05-Vue入门系列之Vue实例详解与生命周期

    Vue的实例是Vue框架的入口,其实也就是前端的ViewModel,它包含了页面中的业务逻辑处理.数据模型等,当然它也有自己的一系列的生命周期的事件钩子,辅助我们进行对整个Vue实例生成.编译.挂着. ...

  7. Cordova - 使用Cordova开发iOS应用实战2(生命周期、使用Safari调试)

    Cordova - 使用Cordova开发iOS应用实战2(生命周期.使用Safari调试) 前文我们创建了一个简单的Cordova项目,结构如下: 1,Cordova生命周期事件 (1)device ...

  8. 理解AngularJS生命周期:利用ng-repeat动态解析自定义directive

    ng-repeat是AngularJS中一个非常重要和有意思的directive,常见的用法之一是将某种自定义directive和ng-repeat一起使用,循环地来渲染开发者所需要的组件.比如现在有 ...

  9. php会话(session)生命周期概念介绍及设置更改和回收

    http://www.169it.com/article/8429580816135935852.html https://my.oschina.net/jiec/blog/227252  sessi ...

随机推荐

  1. configure PUTTY to not time out

    To modify an existing session with "keep alives" to maintain your connection follow the st ...

  2. iOS使用NSMutableAttributedString

    在iOS开发中,常常会有一段文字显示不同的颜色和字体,或者给某几个文字加删除线或下划线的需求.之前在网上找了一些资料,有的是重绘UILabel的textLayer,有的是用html5实现的,都比较麻烦 ...

  3. Centos下 Nginx安装与配置

    网上找了好多资料.都很难找全,这里以这个目录为主,进行备注. Nginx是一款轻量级的网页服务器.反向代理服务器.相较于Apache.lighttpd具有占有内存少,稳定性高等优势.它最常的用途是提供 ...

  4. isPostBack原理

    从 到输入用户名,点击提交按钮 这个过程就叫做postback(是两个不同的状态)     利用ispostback原理,实现是否第一次进入处理程序(上一个用用户名判断的不好,会导致在用户名空的情况下 ...

  5. 判断数字 字母 isDigit(), isalpha()

    判断是否是数字 isdigit isNumber      二者区别http://www.cnblogs.com/xiashengwang/p/3219925.html     需要包含头文件  #i ...

  6. 20150627分享iOS开发笔记

    util是工具的意思:Ad Hoc是特别的,临时的意思;validate是验证的意思: 打包 苹果的键盘真好使 6和6 plus真机测试报错:No architectures to compile f ...

  7. 【滚动数组】 dp poj 1036

    题意:一群匪徒要进入一个酒店.酒店的门有k+1个状态,每个匪徒的参数是:进入时间,符合的状态,携带的钱. 酒店的门刚开始状态0,问最多这个酒店能得到的钱数. 思路: dp数组为DP[T][K]. 转移 ...

  8. 扫描局域网内的ip和主机名

    1. 目的 今天发现我配置的一台电脑ip被人占用了,所以准备写个程序扫描一下局域网内所有正在使用的ip和主机名 2. 实现--直接上代码 import time import threading im ...

  9. cell reuse & disposebag

    For my project I've made base cell class TableViewCell: UITableViewCell { private(set) var disposeBa ...

  10. Lucene入门教程(转载)

    http://blog.csdn.net/tianlincao/article/details/6867127 Lucene教程 1 lucene简介 1.1 什么是lucene     Lucene ...