您好,欢迎访问一九零五行业门户网

PHP内核探索:变量存储与类型使用说明

这篇文章主要介绍了php内核探索:变量存储与类型的相关资料,需要的朋友可以参考下
先回答前面一节的那个问题吧。
复制代码 代码如下:
程序输出 11 20。原因是,方法内部无法访问$bar变量,所以它的值还是20。使用global之后,可以取得$foo的值,自增后$foo的值就是11。
global的作用是定义全局变量,但是这个全局变量不是应用于整个网站,而是应用于当前页面,包括include或require的所有文件。
前言中提到变量的三个基本特性,其中的有一个特性为变量的类型,变量都有特定的类型, 如:字符串、数组、对象等等。编程语言的类型系统可以分为强类型和弱类型两种:
强类型语言是一旦某个变量被申明为某个类型的变量,则在程序运行过程中,该不能将该变量的类型以外的值赋予给它 (当然并不完全如此,这可能会涉及到类型的转换,后面的小节会有相应介绍),c/c++/java等语言就属于这类。
php及ruby,javascript等脚本语言属于弱类型语言:一个变量可以表示任意的数据类型。
php之所以成为一个简单而强大的语言,很大一部分的原因是它拥有弱类型的变量。 但是有些时候这也是一把双刃剑,使用不当也会带来一些问题。就像仪器一样,越是功能强大, 出现错误的可能性也就越大。
在官方的php实现内部,所有变量使用同一种数据结构(zval)来保存,而这个结构同时表示php中的各种数据类型。 它不仅仅包含变量的值,也包含变量的类型。这就是php弱类型的核心。
那zval结构具体是如何实现弱类型的呢,下面我们一起来揭开面纱。
变量存储结构
php在声明或使用变量的时候,并不需要显式指明其数据类型。
php是弱类型语言,这并不表示php没有类型,在php中,存在8种变量类型,可以分为三类
* 标量类型:boolean、integer、float(double)、string
* 复合类型: array、object
* 特殊类型: resource、null
官方php是用c实现的,而c是强类型的语言,那这是怎么实现php中的弱类型的呢?
变量的值存储到以下所示zval结构体中。 zval结构体定义在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在存储变量时将php用户空间的变量类型也保存在同一个结构体中。这样我们就能通过这些信息获取到变量的类型。
zval结构体中有四个字段,其含义分别为:
属性名含义默认值
refcount__gc表示引用计数1
is_ref__gc表示是否为引用0
value存储变量的值
type变量具体的类型
在php5.3之后,引入了新的垃圾收集机制,引用计数和引用的字段名改为refcount__gc和is_ref__gc。在此之前为refcount和is__ref。
而变量的值则存储在另外一个结构体zvalue_value中。值存储见下面的介绍。
php用户空间指的在php语言这一层面,而本书中大部分地方都在探讨php的实现。 这些实现可以理解为内核空间。由于php使用c实现,而这个空间的范畴就会限制在c语言。 而php用户空间则会受限于php语法及功能提供的范畴之内。 例如有些php扩展会提供一些php函数或者类,这就是向php用户空间导出了方法或类。
变量类型
zval结构体的type字段就是实现弱类型最关键的字段了,type的值可以为: is_null、is_bool、is_long、is_double、is_string、is_array、is_object和is_resource 之一。 从字面上就很好理解,他们只是类型的唯一标示,根据类型的不同将不同的值存储到value字段。 除此之外,,和他们定义在一起的类型还有is_constant和is_constant_array。
这和我们设计数据库时的做法类似,为了避免重复设计类似的表,使用一个标示字段来记录不同类型的数据。
变量的值存储
前面提到变量的值存储在zvalue_value联合体中,结构体定义如下:
复制代码 代码如下:
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;
这里使用联合体而不是用结构体是出于空间利用率的考虑,因为一个变量同时只能属于一种类型。 如果使用结构体的话将会不必要的浪费空间,而php中的所有逻辑都围绕变量来进行的,这样的话, 内存浪费将是十分大的。这种做法成本小但收益非常大。
各种类型的数据会使用不同的方法来进行变量值的存储,其对应赋值方式如下:
1. 一般类型
变量类型宏?
booleanzval_bool布尔型/整型的变量值存储于(zval).value.lval中,其类型也会以相应的is_*进行存储。
z_type_p(z)=is_bool/long; z_lval_p(z)=((b)!=0);
integerzval_long
floatzval_double
nullzval_nullnull值的变量值不需要存储,只需要把(zval).type标为is_null。
z_type_p(z)=is_null;
其它类似信息

推荐信息