成员属性

3.4.1.3 成员属性

类的变量成员叫做“属性”。属性声明是由关键字 publicprotected 或者 private 开头,然后跟一个普通的变量声明来组成,关于这三个关键字这里不作讨论,后面分析可见性的章节再作说明。

> 【修饰符(public/private/protected/static)】【成员属性名】= 【属性默认值】;

属性中的变量可以初始化,但是初始化的值必须是常数,这里的常数是指 PHP 脚本在编译阶段时就可以得到其值,而不依赖于运行时的信息才能求值,比如public $time = time();这样定义一个属性就会触发语法错误。

成员属性又分为两类:普通属性静态属性。静态属性通过 static 声明,通过 self::$property类名::$property 访问;普通属性通过 $this->property$object->property 访问。

class my_class {
    //普通属性
    public $property = 初始化值;

    //静态属性
    public static $property_2 = 初始化值;
}

与常量的存储方式不同,成员属性的 初始化值 并不是 直接 用以"属性名"作为索引的哈希表存储的,而是通过数组保存的,普通属性、静态属性各有一个数组分别存储。

zend_class_property

看到这里可能有个疑问:使用时成员属性是如果找到的呢?

实际只是成员属性的 VALUE 通过数组存储的,访问时仍然是根据以"属性名"为索引的散列表查找具体VALUE的,这个散列表并没有按照普通属性、静态属性分为两个,而是只用了一个:__HashTable properties_info 。此哈希表存储元素的value类型为 zend_property_info__ 。

typedef struct _zend_property_info {
    uint32_t offset; //普通成员变量的内存偏移值
                     //静态成员变量的数组索引
    uint32_t flags;  //属性掩码,如public、private、protected及是否为静态属性
    zend_string *name; //属性名:并不是原始属性名
    zend_string *doc_comment;
    zend_class_entry *ce; //所属类
} zend_property_info;

//flags标识位
#define ZEND_ACC_PUBLIC     0x100
#define ZEND_ACC_PROTECTED  0x200
#define ZEND_ACC_PRIVATE    0x400

#define ZEND_ACC_STATIC         0x01
  • name:属性名,特别注意的是这里并不全是原始属性名,private会在原始属性名前加上类名,protected则会加上*作为前缀
  • offset:这个值记录的就是上面说的通过数组保存的属性值的索引,也就是说属性值保存在一个数组中,然后将其在数组中的位置保存在offset中,另外需要说明的一点的是普通属性、静态属性这个值用法是不一样的,静态属性是类的范畴,与对象无关,所以其offset为default_static_members_table数组的下标:0,、1、2......,而普通属性归属于对象,每个对象有其各自的属性,所以这个offset记录的实际是 各属性在object中偏移值 (在后面《3.4.2 对象》一节我们再具体说明普通属性的存储方式),其值是:40、56、72......是按照zval的内存大小偏移的
  • flags:bit位,标识的是属性的信息,如public、private、protected及是否为静态属性

所以访问成员属性时首先是根据属性名查找到此属性的存储位置,然后再进一步获取属性值。

举个例子:

class my_class {
    public $property_1 = "aa";
    public $property_2 = array();

    public static $property_3 = 110;
}

default_properties_tabledefault_static_properties_tableproperties_info 关系图:

zend_property_info

下面我们再看下普通成员属性与静态成员属性的不同:静态成员变量保存在类中,各对象共享同一份数据,而普通属性属于对象,各对象独享。

成员属性在类编译阶段就已经分配了zval,静态与普通的区别在于普通属性在创建一个对象时还会重新分配zval(这个过程类似zend引擎执行前分配在zend_execute_data后面的动态变量空间),对象对普通属性的操作都是在其自己的空间进行的,各对象隔离,而静态属性的操作始终是在类的空间内,各对象共享。

3.4.1.4 成员方法

每个类可以定义若干属于本类的函数(称之为成员方法),这种函数与普通的function相同,只是以类的维度进行管理,不是全局性的,所以成员方法保存在类中而不是EG(function_table)。

zend_class_function

> 成员方法的定义:

> 【修饰符(public/private/protected/static/abstruct/final)】function 【&】【成员方法名】(【参数列表】)【返回值类型】{【成员方法】};

成员方法也有静态、非静态之分,静态方法中不能使用$this,因为其操作的作用域全部都是类的而不是对象的,而非静态方法中可以通过$this访问属于本对象的成员属性。

静态方法也是通过static关键词定义:

class my_class {
    static public function test() {
        $a = "hi~";
        echo $a;
    }
}
//静态方法可以这么调用:
my_class::test();

//也可以这样:
$method = 'test';
my_class::$method();

静态方法中调用其它静态方法或静态变量可以通过 self 访问。

成员方法的调用与普通function过程基本相同,根据对象所属类或直接根据类取到method的zend_function,然后执行,具体的过程Zend引擎执行过程已经详细说过,这里不再重复。

联系我们

邮箱 626512443@qq.com
电话 18611320371(微信)
QQ群 235681453

Copyright © 2015-2024

备案号:京ICP备15003423号-3