当前位置: 首页 > news >正文

PHP变量存储与赋值

【变量存储】

php变量保存在一个叫zval的变量容器中。zval变量容器是在变量赋值时创建的;
zval变量容器除了包含变量的类型和值,还包括两个字节的额外信息:

  • 第一个字节是‘is_ref’,BOOL值,标识变量是否属于引用集合(reference set)。php引擎通过该字节区分普通变量和引用变量;
  • 第二个字节是‘refcount’,表示指向该zval变量容器的标识(symbol)的个数。所有的标识都存放在一个标识表中,其中每个标识都有各自的作用域。当变量离开其作用域或对变量调用unset()时,其对应的refcount就会减1,当refcount变成0时,该zval容器将被销毁;
 1 //由于zvalue用来存放变量的实际数据,切要存放多种类型,所以通过union实现PHP的若类型
 2 type union _zvalue_value{
 3     long lval;    //long value
 4     double dval;    //double value
 5     struct{
 6         char *val;
 7         int len;
 8     }str;    //string value
 9     HashTable *ht;    //hash table value
10     zend_object_value obj;
11 } zvalue_value;
12 
13 //Variable information
14 struct _zval_struct{
15     zvalue_value value;    //value
16     zend_unit refcount;
17     zend_uchar type;    //active type
18     zend_uchar is_ref;
19 }
20 
21 typedef struct _zval_strct zval;
22 /*
23     type值与实际类型的对应关系:
24     IS_LONG -> lvalue;
25     IS_DOUBLE -> dvalue;
26     IS_ARRAY -> ht;
27     IS_STRING -> str;
28     IS_RESOURCE -> lvalue
29 
30     is_ref和refcount:用于实现引用计数;    
31 */
zval的数据结构

 

【查看变量信息】

前提

配置Xdebug(参考PHP常用配置)后,可以通过xdebug_debug_zval()函数查看变量信息;

 1 //查看php加载的所有Zent扩展
 2 print_r(get_loaded_extensions(true));
 3 //显示结果
 4 Array
 5 (
 6     [0] => Xdebug
 7 )
 8 
 9 //查看xdebug扩展的所有函数
10 print_r(get_extension_funcs('xdebug'));
11 //运行结果
12 Array
13 (
14     [0] => xdebug_get_stack_depth
15     [1] => xdebug_get_function_stack
16     [2] => xdebug_get_formatted_function_stack
17     [3] => xdebug_print_function_stack
18     [4] => xdebug_get_declared_vars
19     [5] => xdebug_call_class
20     [6] => xdebug_call_function
21     [7] => xdebug_call_file
22     [8] => xdebug_call_line
23     [9] => xdebug_var_dump
24     [10] => xdebug_debug_zval
25     [11] => xdebug_debug_zval_stdout
26     [12] => xdebug_enable
27     [13] => xdebug_disable
28     [14] => xdebug_is_enabled
29     [15] => xdebug_break
30     [16] => xdebug_start_trace
31     [17] => xdebug_stop_trace
32     [18] => xdebug_get_tracefile_name
33     [19] => xdebug_get_profiler_filename
34     [20] => xdebug_dump_aggr_profiling_data
35     [21] => xdebug_clear_aggr_profiling_data
36     [22] => xdebug_memory_usage
37     [23] => xdebug_peak_memory_usage
38     [24] => xdebug_time_index
39     [25] => xdebug_start_error_collection
40     [26] => xdebug_stop_error_collection
41     [27] => xdebug_get_collected_errors
42     [28] => xdebug_start_code_coverage
43     [29] => xdebug_stop_code_coverage
44     [30] => xdebug_get_code_coverage
45     [31] => xdebug_get_function_count
46     [32] => xdebug_dump_superglobals
47     [33] => xdebug_get_headers
48 )
查看是否加载Xdebug扩展及Xdebug相关函数

【查看简单类型的变量】

 1 //设置变量$a
 2 $a='new string';
 3 //显示$a相关信息
 4 xdebug_debug_zval('a');
 5 //运行结果
 6 a: (refcount=1, is_ref=0)='new string'
 7 
 8 //赋值NULL
 9 $a=null;
10 xdebug_debug_zval('a');
11 //运行结果
12 a: (refcount=1, is_ref=0)=NULL
13 
14 //unset()
15 unset($a);
16 xdebug_debug_zval('a');
17 //unset()后将消除zval容器,运行结果为空

【查看复合类型的变量】

复合类型的变量存储与简单类型不太一样。Array和Object类型的变量将其成员或属性保存在自己的标识表中。这意味着,一个复合类型的变量将创建多个zval容器。

 1 //显示数组信息
 2 $ary=array('name'=>'SM');
 3 xdebug_debug_zval('ary');
 4 //运行结果:ary: (refcount=1, is_ref=0)=array ('name' => (refcount=1, is_ref=0)='SM')
 5 
 6 $ary['reName']=$ary['name'];
 7 xdebug_debug_zval('ary');
 8 //运行结果:ary: (refcount=1, is_ref=0)=array ('name' => (refcount=2, is_ref=0)='SM', 'reName' => (refcount=2, is_ref=0)='SM')
 9 
10 $ary['self']=$ary;
11 xdebug_debug_zval('ary');
12 //运行结果(注意$ary和$ary['self']的refcount都是1):ary: (refcount=1, is_ref=0)=array ('name' => (refcount=4, is_ref=0)='SM', 'reName' => (refcount=4, is_ref=0)='SM', 'self' => (refcount=1, is_ref=0)=array ('name' => (refcount=4, is_ref=0)='SM', 'reName' => (refcount=4, is_ref=0)='SM'))
13 
14 unset($ary['reName']);
15 xdebug_debug_zval('ary');
16 //运行结果(注意$ary['self']):ary: (refcount=1, is_ref=0)=array ('name' => (refcount=3, is_ref=0)='SM', 'self' => (refcount=1, is_ref=0)=array ('name' => (refcount=3, is_ref=0)='SM', 'reName' => (refcount=3, is_ref=0)='SM'))

 

【变量赋值】

【传值赋值】

 1 //创建变量并赋值
 2 $a='string a';
 3 //创建zval容器保存字符串'string a'及其它相关信息。并且,系统产生一个唯一标识(在此记为IdA)指向该zval容器。变量名$a的存储单元所保存的内容是指向该zval容器的IdA。
 4 //查看$a相关信息
 5 xdebug_debug_zval('a');
 6 //运行结果
 7 a: (refcount=1, is_ref=0)='string a'    //只有$a保存IdA,所以'string a'的refcount=1
 8 
 9 //传值赋值
10 $b=$a;
11 //赋值后,将$a所保存的信息(IdA)复制到$b的存储单元中。此时,$a和$b存储单元中的内容都是IdA。
12 //查看$a和$b相关信息
13 xdebug_debug_zval('a');
14 xdebug_debug_zval('b);
15 //运行结果
16 a: (refcount=2, is_ref=0)='string a'    //$a和$b都保存IdA,所以'string a'的refcount=2
17 b: (refcount=2, is_ref=0)='string a'
18 
19 //创建$c并赋值给$b
20 $c='string c';
21 //此时将创建新的zval容器保存’string c'及其相关信息,并产生唯一标识(在此记为IdC)指向该zval容器。$c所分配的存储单元保存的信息即为IdC22 $b=$c;
23 //赋值过程是将$c存储单元中的IdC复制到$b的存储单元中。此时,$b保存的信息是IdC,而$a所保存的的信息仍然是IdA。
24 //查看$a,$b,$c
25 xdebug_debug_zval('a');
26 xdebug_debug_zval('b');
27 xdebug_debug_zval('c');
28 //运行结果
29 a: (refcount=1, is_ref=0)='string a'    //只有$a保存IdA,所以'string a'的refcount=1
30 b: (refcount=2, is_ref=0)='string c'    //$b和$c都保存IdC,所以'string c'的refcount=2
31 c: (refcount=2, is_ref=0)='string c'
32 
33 //为$b重新赋值
34 $b='string b';
35 //创建新的zval容器保存’string b'及其它相关信息,并产生唯一标识(在此记为IdB)指向该zval容器。此时$b存储但愿所保存的信息即为IdB。
36 //查看$a,$b,$c
37 xdebug_debug_zval('a');
38 xdebug_debug_zval('b');
39 xdebug_debug_zva('c');
40 //运行结果
41 a: (refcount=1, is_ref=0)='string a'    //只有$a保存IdA,所以'string a'的refcount=1
42 b: (refcount=1, is_ref=0)='string b'    //只有$b保存IdB,所以'string b'的refcount=1
43 c: (refcount=1, is_ref=0)='string c'    //只有$c保存IdC,所以'string c'的refcount=1

【引用赋值】

 1 //创建变量$a
 2 $a='string a';
 3 //显示$a相关信息
 4 xdebug_debug_zval('a');
 5 //运行结果
 6 a: (refcount=1, is_ref=0)='string a'
 7 
 8 //$a引用赋值给$b
 9 $b=&$a;
10 //显示$a,$b
11 xdebug_debug_zval('a');
12 xdebug_debug_zval('b');
13 //运行结果
14 a: (refcount=2, is_ref=1)='string a'
15 b: (refcount=2, is_ref=1)='string a'
16 
17 //$a传值赋值给$c
18 $c=$a
19 //显示$a,$b,$c
20 xdebug_debug_zval('a');
21 xdebug_debug_zval('b');
22 xdebug_debug_zval('c');
23 //运行结果
24 a: (refcount=2, is_ref=1)='string a'
25 b: (refcount=2, is_ref=1)='string a'
26 c: (refcount=1, is_ref=0)='string a'

【对象操作】

 1 class Persion {
 2     public $name='SM';
 3     public function GetName() {
 4     Return $this->name;
 5     }
 6 }
 7 
 8 $psn=new Persion;
 9 xdebug_debug_zval('psn');
10 //运行结果
11 //psn: (refcount=1, is_ref=0)=class Persion { public $name = (refcount=1, is_ref=0)='SM' }
12 
13 $psn1=$psn;
14 xdebug_debug_zval('psn');
15 xdebug_debug_zval('psn1');
16 //运行结果
17 //psn: (refcount=2, is_ref=0)=class Persion { public $name = (refcount=1, is_ref=0)='SM' }
18 //psn1: (refcount=2, is_ref=0)=class Persion { public $name = (refcount=1, is_ref=0)='SM' }
19 
20 $psn2=&$psn;
21 xdebug_debug_zval('psn');
22 xdebug_debug_zval('psn1');
23 xdebug_debug_zval('psn2');
24 //运行结果
25 //psn: (refcount=2, is_ref=1)=class Persion { public $name = (refcount=1, is_ref=0)='SM' }
26 //psn1: (refcount=1, is_ref=0)=class Persion { public $name = (refcount=1, is_ref=0)='SM' }
27 //psn2: (refcount=2, is_ref=1)=class Persion { public $name = (refcount=1, is_ref=0)='SM' }
28 
29 $psn1->name='SMS';
30 xdebug_debug_zval('psn');
31 xdebug_debug_zval('psn1');
32 xdebug_debug_zval('psn2');
33 //运行结果(注意$spn,$spn1,$spn2的name属性值都是'SMS')
34 //psn: (refcount=2, is_ref=1)=class Persion { public $name = (refcount=1, is_ref=0)='SMS' }
35 //psn1: (refcount=1, is_ref=0)=class Persion { public $name = (refcount=1, is_ref=0)='SMS' }
36 //psn2: (refcount=2, is_ref=1)=class Persion { public $name = (refcount=1, is_ref=0)='SMS' }

 

转载于:https://www.cnblogs.com/HACKEING/p/3148728.html

相关文章:

  • 设计模式学习笔记(1)组合
  • diskpart
  • 统一登录中心SSO 单点登录系统的构想
  • linux下的块设备驱动(一)
  • WeexSDK之注册Components
  • Linux操作系统常见安装方式
  • Android获取SD卡中选中图片的路径(URL)
  • Fragment结合ViewPager来回切换的问题
  • 如何判断某经纬度是否在地图不规则区域内(Objective-C 实现)
  • poj 1088 滑雪问题
  • 使用Jupyter Notebook编写技术文档
  • Nape的回调系统 nape.callbacks
  • Etcd集群与gRPC
  • 用友3.0时期,用友优普聚焦中型企业互联网化
  • 文件读写内容替换
  • 收藏网友的 源程序下载网
  • create-react-app项目添加less配置
  • Java-详解HashMap
  • Nodejs和JavaWeb协助开发
  • vue和cordova项目整合打包,并实现vue调用android的相机的demo
  • Webpack入门之遇到的那些坑,系列示例Demo
  • 紧急通知:《观止-微软》请在经管柜购买!
  • 前端代码风格自动化系列(二)之Commitlint
  • 微信小程序开发问题汇总
  • 用Canvas画一棵二叉树
  • ​​​​​​​ubuntu16.04 fastreid训练过程
  • #在线报价接单​再坚持一下 明天是真的周六.出现货 实单来谈
  • $GOPATH/go.mod exists but should not goland
  • (2/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序
  • (30)数组元素和与数字和的绝对差
  • (33)STM32——485实验笔记
  • (PHP)设置修改 Apache 文件根目录 (Document Root)(转帖)
  • (二十一)devops持续集成开发——使用jenkins的Docker Pipeline插件完成docker项目的pipeline流水线发布
  • (附源码)springboot优课在线教学系统 毕业设计 081251
  • (附源码)ssm高校实验室 毕业设计 800008
  • (接口自动化)Python3操作MySQL数据库
  • (转)Google的Objective-C编码规范
  • (转)jdk与jre的区别
  • .net MySql
  • .NET 中各种混淆(Obfuscation)的含义、原理、实际效果和不同级别的差异(使用 SmartAssembly)
  • .skip() 和 .only() 的使用
  • @autowired注解作用_Spring Boot进阶教程——注解大全(建议收藏!)
  • @TableId注解详细介绍 mybaits 实体类主键注解
  • [52PJ] Java面向对象笔记(转自52 1510988116)
  • [AutoSar]BSW_Com02 PDU详解
  • [BUUCTF 2018]Online Tool
  • [C#][DevPress]事件委托的使用
  • [emacs] CUA的矩形块操作很给力啊
  • [hdu 1247]Hat’s Words [Trie 图]
  • [hdu2196]Computer树的直径
  • [HJ56 完全数计算]
  • [IE9] 解决了傲游、搜狗浏览器在IE9下网页截图的问题
  • [Kubernetes]9. K8s ingress讲解借助ingress配置http,https访问k8s集群应用
  • [mit6.s081] 笔记 Lab2:system calls
  • [python] 之 函数简介