详解php5对象2013-09-08php5对象将php5的对象和它的先辈php4对象进行比较实在有些不公平, 不过php5对象使用的API函数还是遵循php4的API构建的. 如果你已经阅读了第10章"php4对象", 你将会对本章内容多少有些熟悉. 在开始本章之前, 可以像第10章开始时一样, 重命名扩展为sample3并清理多余的代码, 只保留扩展的骨架代码.进化史在php5对象变量中有两个关键的组件. 第一个是一个数值的标识, 它和第9章"资源数据类型"中介绍的数值资源ID非常相似, 扮演了一个用来在对应表中查找对象实例的key的角色. 在这个实例表中的元素包含了到zend_class_entry的引用以及内部的属性表.第二个元素是对象变量的句柄表, 使用它可以自定义Zend引擎对实例的处理方式. 在本章后面你将看到这个句柄表.zend_class_entry类条目是你在用户空间定义的类的内部表示. 正如你在前一章所见, 这个结构通过调用INIT_CLASS_ENTRY()初始化, 参数为类名和它的函数表. 接着在MINIT阶段使用zend_register_internal_class()注册.
zend_class_entry *php_sample3_sc_entry;#define PHP_SAMPLE3_SC_NAME "Sample3_SecondClass"static function_entry php_sample3_sc_functions[] = {{ NULL, NULL, NULL }};PHP_MINIT_FUNCTION(sample3){zend_class_entry ce;INIT_CLASS_ENTRY(ce, PHP_SAMPLE3_SC_NAME,php_sample3_sc_functions);php_sample3_sc_entry =zend_register_internal_class(&ce TSRMLS_CC);return SUCCESS;}方法如果你已经阅读了上一章, 你可能就会想"到现在为止看起来几乎一样啊?", 到现在为止, 你是对的. 现在我们开始定义一些对象方法. 你将开始看到一些非常确定的并且大受欢迎的不同.
PHP_METHOD(Sample3_SecondClass, helloWorld){php_printf("Hello World
");}在Zend引擎2中引入了PHP_METHOD()宏, 它是对PHP_FUNCTION()宏的封装, 将类名和方法名联合起来, 不用像php4中手动定义方法名了. 通过使用这个宏, 在扩展中你的代码和其他维护者的代码的名字空间解析规范就保持一致了.定义定义一个方法的实现, 和其他函数一样, 只不过是将它连接到类的函数表中. 除了用于实现的PHP_METHOD()宏, 还有一些新的宏可以用在函数列表的定义中.PHP_ME(classname, methodname, arg_info, flags)PHP_ME()相比于第5章"你的第一个扩展"中介绍的PHP_FE()宏, 增加了一个classname参数, 以及末尾的一个flags参数(用来提供public, protected, private, static等访问控制, 以及abstract和其他一些选项). 比如要定义helloWorld方法, 就可以如下定义:PHP_ME(Sample3_SecondClass,helloWorld,NULL,ZEND_ACC_PUBLIC)PHP_MALIAS(classname, name, alias, arg_info, flags)和PHP_FALIAS()宏很像, 这个宏允许你给alias参数描述的方法(同一个类中的)实现提供一个name指定的新名字. 例如, 要复制你的helloWorld方法则可以如下定义
PHP_MALIAS(Sample3_SecondClass, sayHi, helloWorld,NULL, ZEND_ACC_PUBLIC)
PHP_ABSTRACT_ME(classname, methodname, arg_info)内部类中的抽象方法很像用户空间的抽象方法. 在父类中它只是一个占位符, 期望它的子类提供真正的实现. 你将在接口一节中使用这个宏, 接口是一种特殊的class_entry.PHP_ME_MAPPING(methodname, functionname, arg_info)最后一种方法定义的宏是针对同时暴露OOP和非OOP接口的扩展(比如mysqli既有过程化的mysqli_query(), 也有面向对象的MySQLite::query(), 它们都使用了相同的实现.)的. 假定你已经有了一个过程化函数, 比如第5章写的sample_hello_world(), 你就可以使用这个宏以下面的方式将它附加为一个类的方法(要注意, 映射的方法总是public, 非static, 非final的):PHP_ME_MAPPING(hello, sample_hello_world, NULL)现在为止, 你看到的方法定义都使用了ZEND_ACC_PUBLIC作为它的flags参数. 实际上, 这个值可以是下面两张表的任意值的位域运算组合, 并且它还可以和本章后面"特殊方法"一节中要介绍的一个特殊方法标记使用位域运算组合.

比如, 由于你前面定义的Sample3_SecondClass::helloWorld()方法不需要对象实例, 你就可以将它的定义从简单的ZEND_ACC_PUBLIC修改为ZEND_ACC_PUBLIC | ZEND_ACC_STATIC, 这样引擎知道了就不会去提供(实例)了.