类的变量成员叫做“属性”。属性声明是由关键字 public,protected 或者 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 = 初始化值;
}
与常量的存储方式不同,成员属性的 初始化值 并不是 直接 用以"属性名"作为索引的哈希表存储的,而是通过数组保存的,普通属性、静态属性各有一个数组分别存储。

看到这里可能有个疑问:使用时成员属性是如果找到的呢?
实际只是成员属性的 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
所以访问成员属性时首先是根据属性名查找到此属性的存储位置,然后再进一步获取属性值。
举个例子:
class my_class {
public $property_1 = "aa";
public $property_2 = array();
public static $property_3 = 110;
}
则 default_properties_table、default_static_properties_table、properties_info 关系图:

下面我们再看下普通成员属性与静态成员属性的不同:静态成员变量保存在类中,各对象共享同一份数据,而普通属性属于对象,各对象独享。
成员属性在类编译阶段就已经分配了zval,静态与普通的区别在于普通属性在创建一个对象时还会重新分配zval(这个过程类似zend引擎执行前分配在zend_execute_data后面的动态变量空间),对象对普通属性的操作都是在其自己的空间进行的,各对象隔离,而静态属性的操作始终是在类的空间内,各对象共享。
每个类可以定义若干属于本类的函数(称之为成员方法),这种函数与普通的function相同,只是以类的维度进行管理,不是全局性的,所以成员方法保存在类中而不是EG(function_table)。

> 成员方法的定义:
> 【修饰符(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引擎执行过程已经详细说过,这里不再重复。