在PHP中,变量存储在一个名叫ZVAL的容器中。它也是PHP实现弱语言的关键因素之一。 这个容器是一个标记类型和记录所有PHP实现的类型的集合体。而对象作为其存储类型的一种, 以type=IS_OBJECT为标记,以zend_object_value结构体为值。但是zend_object_value的结构体仅有两个字段handle和handlers。 而这两个字段就是今天我们所要说的对象管理机制的关键点。
handle字段是zend_object_handle类型,而zend_object_handle仅仅是unsigned int的一个别名。 这个字段是干嘛用的呢?它是一个索引,是一个对象存储列表的索引。这个对象存储列表是PHP内核中对象的存储地, 或者我们可以称其为“对象池”。
在PHP的请求初始化阶段,PHP会初始化这个对象池,预先分配 1024 个存储对象的空间。 当我们使用 new 关键字创建一个对象时,PHP会将这个对象放入到对象池中,handle字段作为其索引返回。 如果总的对象个数小于1024(或现有列表长度的最大值),则handle会返回最后的一个值, 如果总的对象个数大于1024(或现有列表长度的最大值),则将列表的长度左移一位,将之前的top值作为handle字段返回。 当我们将对象的引用计数减小时,PHP最终会调用对象操作API中的引用计数减少操作函数,当对象的引用计数小于1时会执行垃圾回收机制。
PHP的这个对象存储机制,有点类似于在表设计时将一对多关系中的多的一边独立成一个表存储, 这样的设计不仅仅是低耦合的,而且在对象利用,节省内存等方面有一定的优化。
handlers字段是zend_object_handlers类型,这个类型是一个结构体,包括对象的所有处理函数。默认情况下,对象创建时使用标准处理函数。 对象的变量调用,引用计数处理,克隆,函数调用等等操作都包括在这个结构体中,这相当于是对象处理的统一接口。 对于不同的需求,也可以定制这些处理函数的实现,这又相当于是一个默认值,你可以选择非默认的自定义的处理函数。 如果从面向对象的角度思考这个设计,这应该是一个类似于门面模式 ,或者说是面向接口的编程原则。
对象池的相关操作的实现在 Zend/zend_object_API.c文件,对象的操作的标准实现基本上都在 Zend/zend_object_handlers.c文件。
关于对象的前前后后在即将发布的 TIPI 第五章类和面向对象中有详细说明。