PHP源码阅读笔记二十八:类结构和继承

PHP源码阅读笔记二十八:类结构和继承
作为面向对象中一个非常关键也非常纠结的特性,我们需要了解一些
在PHP5中,从一开始就有了继承的概念,今天我们从PHP源码出发,了解他是怎么实现的。
在了解类的继承之前,我们需要知道类在PHP源码中是以哪种方式存储的。
找到zend/zend.h 418行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
 
struct _zend_class_entry {
	char type;
	char *name;	/* 类名 */
	zend_uint name_length;	/* 类名字符串长度 */
	struct _zend_class_entry *parent; /* 父类 */
	int refcount; /* 引用计数 */
	zend_bool constants_updated;
	zend_uint ce_flags;	/* 类的访问控制 */
 
	HashTable function_table;	/*	类的成员函数 */
	HashTable default_properties;	/*	类的默认属性 */
	HashTable properties_info;	/*	类的属性信息 如访问控制等 */
	HashTable default_static_members;/*	静态成员列表 */
	HashTable *static_members;
	HashTable constants_table;	/* 常量列表 */
	const struct _zend_function_entry *builtin_functions;
 
	union _zend_function *constructor;	/*	构造函数*/
	union _zend_function *destructor;	/*	析构函数*/
	union _zend_function *clone;		/*	克隆方法*/
 
	/*	魔术方法 */
	union _zend_function *__get;
	union _zend_function *__set;
	union _zend_function *__unset;
	union _zend_function *__isset;
	union _zend_function *__call;
	union _zend_function *__callstatic;
	union _zend_function *__tostring;
	union _zend_function *serialize_func;
	union _zend_function *unserialize_func;
 
	zend_class_iterator_funcs iterator_funcs;
 
	/* handlers */
	zend_object_value (*create_object)(zend_class_entry *class_type TSRMLS_DC);
	zend_object_iterator *(*get_iterator)(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC);
	int (*interface_gets_implemented)(zend_class_entry *iface, zend_class_entry *class_type TSRMLS_DC); /* a class implements this interface */
	union _zend_function *(*get_static_method)(zend_class_entry *ce, char* method, int method_len TSRMLS_DC);
 
	/* serializer callbacks */
	int (*serialize)(zval *object, unsigned char **buffer, zend_uint *buf_len, zend_serialize_data *data TSRMLS_DC);
	int (*unserialize)(zval **object, zend_class_entry *ce, const unsigned char *buf, zend_uint buf_len, zend_unserialize_data *data TSRMLS_DC);
 
	zend_class_entry **interfaces;	/*	类实现的接口 */
	zend_uint num_interfaces;	/*	类实现的接口数 */
 
	/*	类所在文件信息 */
	char *filename;
	zend_uint line_start;
	zend_uint line_end;
	char *doc_comment;
	zend_uint doc_comment_len;
 
	struct _zend_module_entry *module;
};

从PHP自带的SPL中,我们可以看到有类的继承,从这里出发,可以找到我们所需要的实现过程
从手册中选择CachingIterator类作为切入点。
CachingIterator extends IteratorIterator implements OuterIterator , Traversable , Iterator , ArrayAccess , Countable
跟踪过程如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
//在ext/spl/spl_iterators.c 3246行,
REGISTER_SPL_SUB_CLASS_EX(CachingIterator, IteratorIterator, spl_dual_it_new, spl_funcs_CachingIterator);
 
//    ext/spl/spl_functions.h 34行
#define REGISTER_SPL_SUB_CLASS_EX(class_name, parent_class_name, obj_ctor, funcs) \
    spl_register_sub_class(&spl_ce_ ## class_name, spl_ce_ ## parent_class_name, # class_name, obj_ctor, funcs TSRMLS_CC);
 
//    ext/spl/spl_functions.c 56行
PHPAPI void spl_register_sub_class(zend_class_entry ** ppce, zend_class_entry * parent_ce, char * class_name, void *obj_ctor, const zend_function_entry * function_list TSRMLS_DC)
*ppce = zend_register_internal_class_ex(&ce, parent_ce, NULL TSRMLS_CC);
 
//    zend/zend_API.c  2196行
ZEND_API zend_class_entry *zend_register_internal_class_ex(zend_class_entry *class_entry, zend_class_entry *parent_ce, char *parent_name TSRMLS_DC)
zend_do_inheritance(register_class, parent_ce TSRMLS_CC);
 
//    zend/zend_compile.c 2784行
 
ZEND_API void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent_ce TSRMLS_DC)
{
    /* 接口不能继承类 */
    if ((ce->ce_flags & ZEND_ACC_INTERFACE)
   	 && !(parent_ce->ce_flags & ZEND_ACC_INTERFACE)) {
   	 zend_error(E_COMPILE_ERROR, "Interface %s may not inherit from class (%s)", ce->name, parent_ce->name);
    }
 
    /* final类不能继承 */
    if (parent_ce->ce_flags & ZEND_ACC_FINAL_CLASS) {
   	 zend_error(E_COMPILE_ERROR, "Class %s may not inherit from final class (%s)", ce->name, parent_ce->name);
    }
 
    ce->parent = parent_ce;
    /* 拷贝序列化和反序列化回调函数 */
    if (!ce->serialize) {
   	 ce->serialize   = parent_ce->serialize;
    }
    if (!ce->unserialize) {
   	 ce->unserialize = parent_ce->unserialize;
    }
 
    /* 继承父类的接口 在此处有停下来思考,为何要这么做 */
    zend_do_inherit_interfaces(ce, parent_ce TSRMLS_CC);
 
    /* 继承父类的属性  */
    zend_hash_merge(&ce->default_properties, &parent_ce->default_properties, (void (*)(void *)) zval_add_ref, NULL, sizeof(zval *), 0);
    if (parent_ce->type != ce->type) {
   	 /* 用户自定义的类从内部类继承 */
   	 zend_update_class_constants(parent_ce  TSRMLS_CC);
   	 zend_hash_apply_with_arguments(CE_STATIC_MEMBERS(parent_ce) TSRMLS_CC, (apply_func_args_t)inherit_static_prop, 1, &ce->default_static_members);
    } else {
   	 zend_hash_apply_with_arguments(&parent_ce->default_static_members TSRMLS_CC, (apply_func_args_t)inherit_static_prop, 1, &ce->default_static_members);
    }
    zend_hash_merge_ex(&ce->properties_info, &parent_ce->properties_info, (copy_ctor_func_t) (ce->type & ZEND_INTERNAL_CLASS ? zend_duplicate_property_info_internal : zend_duplicate_property_info), sizeof(zend_property_info), (merge_checker_func_t) do_inherit_property_access_check, ce);
 
    /* 合并常量和成员函数 */
    zend_hash_merge(&ce->constants_table, &parent_ce->constants_table, (void (*)(void *)) zval_add_ref, NULL, sizeof(zval *), 0);
    zend_hash_merge_ex(&ce->function_table, &parent_ce->function_table, (copy_ctor_func_t) do_inherit_method, sizeof(zend_function), (merge_checker_func_t) do_inherit_method_check, ce);
 
    do_inherit_parent_constructor(ce);
 
    if (ce->ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS && ce->type == ZEND_INTERNAL_CLASS) {
   	 ce->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS;
    } else if (!(ce->ce_flags & ZEND_ACC_IMPLEMENT_INTERFACES)) {
   	 /* The verification will be done in runtime by ZEND_VERIFY_ABSTRACT_CLASS */
   	 zend_verify_abstract_class(ce TSRMLS_CC);
    }
}

关于上面do_inherit_parent_constructor(ce)
此方法实现魔术方法继承,如果子类中没有相关的魔术方法,则继承父类的对应方法。如下所示的PHP代码为子类没构造函数的情况

1
2
3
4
5
6
7
8
9
10
11
class Base {
	public function __construct() {
    	echo 'Base __construct<br />';
	}
}
 
class Foo extends Base {
 
}
 
$foo = new Foo();

如上,会输出:Base __construct
显然继承了父类的构造方法,如果子类有自己的构造方法,并且需要调用父类的构造方法时,需要在子类的构造方法中调用父类的构造方法,PHP不会自动调用。

PHP源码阅读笔记二十八:类结构和继承》上有3条评论

  1. Pingback引用通告: PHP源码阅读笔记二十九:接口的继承 | PHP源码阅读,PHP设计模式,PHP学习笔记-胖子的空间

  2. Pingback引用通告: Thinking In LAMP Blog » Blog Archive » PHP每月通讯(2010年12月)

  3. Pingback引用通告: PHP源码阅读笔记二十九:接口的继承 ” PHP菜鸟阁_php教程下载

发表评论

电子邮件地址不会被公开。 必填项已用*标注


*

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>