1·、PHP变量的底层实现

PHP代码执行图解

1.1:变量在内存中的存储结构

PHP变量是通过zval结构体来存储的,文件: Zend/zend.h 316行左右

1.2:值的存储

PHP变量的值是放在zval结构体中的value段中的,文件: Zend/zend.h

1.3:结构体的字段解释

struct _zval_struct {

/* Variable information */

zvalue_value value; /*变量的值,是个联合体*/

zend_uint refcount__gc; /*指向次数*/

zend_uchar type; /* 变量类型 */

zend_uchar is_ref__gc; /*是否引用*/

};

type字段的值为以下常量

IS_NULL, IS_BOOL,IS_LONG,IS_DOUBLE

IS_STRING,IS_ARRAY,IS_OBJECT

IS_RESOURCE

1.4:联合体中的值

typedef union _zvalue_value {

long lval; /* long value */

double dval; /* double value */

struct {

char *val;

int len;

} str;

HashTable *ht; /* hash table value */

zend_object_value obj;

} zvalue_value;

联合中为什么只列出了5种值?

NULL不用,zval的type为IS_NULL即可

Bool以1,0存储在lval上

resource的type为resource,其resource的内容用long来标志(资源标记)

1.5:变量的结构图

1.6:变量的创建

创建变量的步骤: $str = "hello";

1:创建zval结构,并设置其类型 IS_STRING

2:设置其值为 hello

3:讲其加入符号表

{

zval *fooval;

MAKE_STD_ZVAL(fooval);

ZVAL_STRING(fooval, "hello", 1);

ZEND_SET_SYMBOL( EG(active_symbol_table) ,  "foo" , fooval);

}

1.7:符号表 symbol_table

符号表是什么?

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

// zend/zend_globals.h 182行

struct _zend_executor_globals {

...

...

HashTable *active_symbol_table; /*活动符号表*/

HashTable symbol_table; /* 全局符号表 */

HashTable included_files; /* files already included */

1.8:符号表与函数

Zend/zend_compiles.h

struct _zend_execute_data {

...

zend_op_array *op_array; //函数的执行步骤

HashTable *symbol_table; // 此函数的符号表地址

zend_class_entry *current_scope;

zval *current_this;

zval *current_object;

...

};

上面这个,是当前函数执行时的符号表

1.9:符号表与作用域

当执行到函数时,会生成函数的"执行环境结构体",包含函数名,参数,执行步骤,所在的类(如果是方法),以及为这个函数生成一个符号表.符号表统一放在栈上.并把active_symbol_table指向刚产生的符号表

1.10:函数中静态变量的实现

2.0:常量-常量结构体

结构体 Zend/constants.h 33行

typedef struct _zend_constant {

zval value;  //变量结构体

int flags;    //标志,是否大小写敏感等

char *name; //常量名

uint name_len;

int module_number;//模块名

} zend_constant;

2.1:常量的生成

int zend_register_constant(zend_constant *c TSRMLS_DC) {

...

...

zend_hash_add(EG(zend_constants), name, c->name_len, (void *) c, sizeof(zend_constant), NULL)==FAILURE)

...

...

}

2.2:define函数的实现

define函数当然是调用zend_register_constant声明的常量 :)

具体如下 Zend/zend_builtin_functions.c

关键代码:

c.value = *val;

zval_copy_ctor(&c.value);

if (val_free) {

zval_ptr_dtor(&val_free);

}

c.flags = case_sensitive; /* non persistent */

c.name = zend_strndup(name, name_len);

c.name_len = name_len+1;

c.module_number = PHP_USER_CONSTANT;

if (zend_register_constant(&c TSRMLS_CC) == SUCCESS) {

RETURN_TRUE;

} else {

RETURN_FALSE;

}

2.3:有趣的测试

1:常量并没有检测名字...

define('^_^',"laugh");

2:常量的第2个参数还可以是对象,与手册上介绍的不同

define('obj',new className());

(当然,对象要有toString方法等着)

2.4:常量为什么是全局有效的?

很简单,常量的哈希表只有一个

EG(zend_constants)

3.0:内存管理与垃圾回收

PHP封装了对系统内存的请求,不要直接用malloc直接请求内存

3.1:PHP的hashtable太强大

3.2:引用计数

$a = 1;

$b = $a;

?>

$a,$b的值及类型 都一样,有必要再申请一个zval结构吗?

3.3:引用计数解释

$a = 1;

$b = $a;

?>

当$a的值赋给$b时,并没有为$b生成一个新的zval结构体.而是$b与$a共享一个结构体.

3.4:copy-on-write 写时复制

$a = 1;

$b = $a;

$b=6

?>

3.5:引用传值发生了什么?

$a = 1;

$b = &$a;

?>

3.6:引用传值为什么影响了2个值

$a = 1;

$b = &$a;

$b = 6;

?>

内核修改zval的值时,发现is_ref_gc为1,则直接修改该value,而不是复制一份.如下图:

php 结构体_PHP底层原理知其然知其所以然相关推荐

  1. 知行合一:知其然知其所以然

    知行合一:知其然知其所以然. 一个事情做成了,并不意味着你知道做成这件事背后蕴藏的原理. 只有使用冥思.事上练的方法了,将背后的原理提取出来,才能说做到了执行合一. 这个过程是行对知的精进过程. 转载 ...

  2. set集合 结构体_Redis底层数据结构

    Redis作为Key-value存储系统,数据结构如下: Redis底层数据结构.png Redis没有表的概念,Redis实例所对应的DB以编号区分,DB本身就是key的命名空间,例如:user:1 ...

  3. php 结构体_php基础知识集合

    微信公众号:PHP在线 源码 PHP 独特的语法混合了 C.Java.Perl 以及 PHP 自创新的语法 编译器 编译器就是将"一种语言(通常为高级语言)"翻译为"另一 ...

  4. struct 结构体解析(原)

    (一)基本概念 结构体是一个或是多个变量的集合,这些变量可能为不同的类型,为了处理的方便而将这些变量组合在一个名字之下.我们将关键字struct引入了结构声明中.结构声明包含在花括号内的一系列声明组成 ...

  5. redis zset转set 反序列化失败_关于Redis中的五种数据结构,要知其然知其所以然...

    Redis作为Nosql的代表,想必大家已经再熟悉不过了,除了作为缓存来使用,Redis还提供了其他很多有用的功能,例如可作为消息队列.分布式锁.不隆过滤器.限流等功能使用.今天先来说一说redis作 ...

  6. bootstraptable获取所有数据_关于Redis中的五种数据结构,要知其然知其所以然

    Redis作为Nosql的代表,想必大家已经再熟悉不过了,除了作为缓存来使用,Redis还提供了其他很多有用的功能,例如可作为消息队列.分布式锁.不隆过滤器.限流等功能使用.今天先来说一说redis作 ...

  7. 锁,知其然知其所以然

    ​ Taken by iCola 今天,从一个小问题聊起. 假设你账户上原来有100元钱,你用微信支付100元,与此同时你女票用支付宝给你转100元零花钱,你帐户的余额有没有可能变成200元或者0元? ...

  8. 算出当前系统后某个月的日期_Python3.7知其然知其所以然-第十八章 日期函数

    时光不可追,往事不可回.以往创建的数据,如若没有日期做标识,不堪回首.几乎任何一个产品都会用到日期,如登录日期.创建日期.修改日期等.正因如此,编程语言中,几乎都有内置日期函数. 18.1 当前日期 ...

  9. 字符串去掉两端的引号_Python3.7知其然知其所以然-第六章 字符串

    在开发过程中,经常会用到字符串来存储字符内容.在其他编程语言中用成对双引号" "声明字符串,用成对单引号' '声明单个字符,而Python没有这种区别,它无论单个或多个字符都用字符 ...

最新文章

  1. php mysql study_phpStudy 升级 MySQL5.7
  2. Unity3D安卓程序中常用静态方法封装
  3. python 只能将最后一行写入excel_Python 应用 办公自动化之 Excel(上)
  4. 人与计算机的未来_身边的很多人都在学习计算机,学习计算机到底能带来哪些好处...
  5. canvas粒子动画
  6. GPU Gems1 - 23 景深技术综述
  7. 树形dp小胖守皇宫(vijosP1144)
  8. java hibernate 表关联_Hibernate多表关联
  9. 7个习惯可以改变一个人和他的一生
  10. LATEX数学式哪种字号比较漂亮
  11. jieba中文处理的学习
  12. 从源码角度理解 FragmentTransaction实现
  13. c语言控制led以1s速度,C语言使用定时器的方法控制LED灯以1S的速度闪亮
  14. linux输入字符串到文件,[Linux文件]将用户输入的字符串写入文件实例
  15. js让网页标题闪动效果(记)
  16. 动态服务器值 回放报错 没有关联到_LR之关联
  17. 全国各省市经纬度范围
  18. 车辆检测技术的应用分析
  19. 如何自己编写一个交通仿真软件 (开篇) 走火入魔。
  20. npm安装报错(npm ERR! code EPERM npm ERR! syscall mkdir npm ERR! path C:\Program Files\nodejs\node_ca...)

热门文章

  1. FPGA多功能应用处理器
  2. Relay外部库使用
  3. 服务化部署框架Paddle Serving
  4. 将深度学习低延迟推理性能提高一倍
  5. 摄像头与毫米波雷达(Radar)融合
  6. The destination folder does not exist or is not writeable
  7. .net平台性能很不错的轻型ORM类Dapper(转)
  8. logrus学习笔记
  9. 【分布式架构】“高并发” -- 详解
  10. 第七篇 JVM核心机制之JVM运行和类加载全过程(二)