PHP底层原理

一、PHP底层原理--知其然知其所以然,先看一张图

1、我们写的PHP代码是不能直接运行的,它首先经过词法分析器-语法分析器和编译器

这里你可能会觉得,PHP怎么会是编译性语言呢?一般认为PHP是脚本语言,是的。但严格的说来,PHP也是一种编译语言,它会将PHP编译为opcode的一个中间语言,有点像JAVA中的class文件。

2、生成cpcode之后再由zend公司开发的执行引擎执行


我们来做一个比较

C、C++语言
JAVA
编译成机器码(二进制)来运行先把JAVA文件编译成.class,被称为bytecode,然后再用jvm来运行
所以JAVA是不可以跨平台的,而是jvm是跨平台的
解释语言
PHP
解释器解释执行,最经典的如:linux shell
解释器逐条来执行命令
PHP有特殊,虽然它是一个脚本语言,但不是靠解释器解释执行。
而是zend虚拟机屏蔽了操作系统
PHP代码编译成opcode.由虚拟机来执行opcode
但是--opcode,PHP脚本一结束,opcode就清除了(java可以将.class打包发布)

3、那么opcode是否可以缓存呢?

PHP本身不支持,但是apc,xcache等加速器实现了这样的效果(如果一生成就扔掉就太浪费了)我们看看一个总结

zend编译器(PHP->opcode)
zend虚拟机(执行opcode)
操作系统层面 win/linux/mac

二、PHP变量的底层实现

PHP底层用C语言来实现的,C语言是强类型,而PHP是弱类型语言(如必须加上变量类型)。那么PHP是如何实现的呢?

我们解压PHP的源代码包,看到如下的目录:如图所示


我们来分析

我们打开Zend文件,然后找到zend.h文件

找到

typedef struct _zval_struct zval 的结构体

再看看它的实现

struct _zval_struct {

    /* Variable information */

    zvalue_value value;     /* value */

    zend_uint refcount__gc;

    zend_uchar type;        /* active type */

    zend_uchar is_ref__gc;

}

PHP变量实现的核心就在上面的几行代码之中

PHP变量的值就是用上面的结构体来描述的

它由四个字段组成

分析第一个,zvalue_value value;  

typedef union _zvalue_value { // 联合(枚举)

    long lval;

    double dval;

    struct {

        char *val;

        int len;

    };

    HashTable *ht;

    zend_object_value obj;

} zvalue_value;


分析第二个,zend_uchar type; 

它有可能是IS_NULL, IS_BOOL


所以判断一个变量的类型是什么,是根据zend_uchar type来决定的

它的值是多少是通过typedef union _zvalue_value它的联合体来决定的


我们来分析一段代码,看看PHP中的变量是怎么实现的

$a = 3;

/***
一个结构体产生了
{ 
union_value {long 3}  // 描述值
type IS_LONG  // 描述类型
refcount_gc:1
is_ref_gc:0
}
***/

type字段的值以常量形式存在

我们看看它具体保存的是什么

IS_NULL, IS_BOOL, IS_LONG, IS_DOUBLE, IS_STRING, IS_ARRARY. IS_OBJECT, IS_RESOURCE

它其实对应了PHP数组中的八种数据类型

这里产生了一个问题,在zvalue_value中只提供了五中数据类型,下面是三种没有对应上的类型

1: NULL直接对应zval->type=IS_NULL,就可以表示不必设置value的置
2: BOOL型,zval->type=IS_BOOL,再设置zval_value.lval = 1/0
3: Resource型,资源型往往是服务器上打开的一个接口,如果文件读取接口
zval->type=IS_RESOURCE, zval->type.lval=服务器打开的接口的编号
  
这里需要我们特别注意一点:

PHP中,字符串类型,长度是已经缓存的,调用strlen不用计算,速度非常快;长度是直接放入其结构体中

$b = 'hello';
/**
{
    {
        char:'hello';
        len:5;
    }
    type: IS_STRING;
    refcount__gc:1
    is_ref__gc:0
}
**/

再问一个问题,变量的名放在哪里的

在PHP中,变量的名是放在符号表中的symbol_table

这里要闻,符号表是什么?

符号表就是一张哈希表,里面存储了变量名->变量的zval结构体的地址

Zend/zend_globals.h找到HashTable synbol_table;  /* main synbol table */

哈希表我们就可以把它作为一个关联数组


看一段代码,看见声明一个变量,就必须要想到的事情

$a = 5;
$b = 5.54321;
$c = 'hello';
/**
生成了3个结构体
同时,全局富豪表中,多了3条记录
a--> 0x123 --> 结构体 {5}
b--> 0x213 --> 结构体 {5.54321}
c--> 0x339 --> 结构体 {hello}
**/

上面是全局的符号表,一般由全局的必定有局部的符号表

HashTable *active_synbol_table

原理都是一样的


我们再看看变量的赋值与引用,先看如下代码:

$a = 3;

$b = $a

在底层是否生成了2个结构体呢?

是的,在PHP实现的过程中并没有生成一个新的结构体

$a = 3
/**
zvalue:3
type:IS_LONG
refount__gc=1
is_ref_gc:0
**/
$b = $a
/**
zvalue:3
type:IS_LONG
refcount__gc=2 这里发生变化
is_ref_gc:0
<pre name="code" class="php">它们在地址上都指向同一个结构体,节省空间,并没有发生结构体的复制
**/

 




123


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值