PHP源码阅读笔记二十九:接口的继承

PHP源码阅读笔记二十九:接口的继承
在之前有看过PHP源码中类的继承,今天我们看下PHP中的接口继承是如何实现的。
同样我们从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
/* ArrayAccess接口的继承实现 */
REGISTER_SPL_IMPLEMENTS(CachingIterator, ArrayAccess);
 
//    ext/spl/spl_functions.h 41行
#define REGISTER_SPL_IMPLEMENTS(class_name, interface_name) \
	zend_class_implements(spl_ce_ ## class_name TSRMLS_CC, 1, spl_ce_ ## interface_name);
 
//	zend/zend_API.c 2218行
ZEND_API void zend_class_implements(zend_class_entry *class_entry TSRMLS_DC, int num_interfaces, ...) /* {{{ */
{
	zend_class_entry *interface_entry;
	va_list interface_list;
	va_start(interface_list, num_interfaces);
 
	while (num_interfaces--) {
		interface_entry = va_arg(interface_list, zend_class_entry *);
		zend_do_implement_interface(class_entry, interface_entry TSRMLS_CC);
	}
 
	va_end(interface_list);
}
/* }}} */
 
 
 
//	zend/zend_complie.c 2887行
ZEND_API void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry *iface TSRMLS_DC) /* {{{ */
{
	zend_uint i, ignore = 0;
	zend_uint current_iface_num = ce->num_interfaces;
	zend_uint parent_iface_num  = ce->parent ? ce->parent->num_interfaces : 0;
 
	for (i = 0; i < ce->num_interfaces; i++) {
		if (ce->interfaces[i] == NULL) {
			memmove(ce->interfaces + i, ce->interfaces + i + 1, sizeof(zend_class_entry*) * (--ce->num_interfaces - i));
			i--;
		} else if (ce->interfaces[i] == iface) {	/* 已存在此接口 */
			if (i < parent_iface_num) {
				ignore = 1;
			} else {
				zend_error(E_COMPILE_ERROR, "Class %s cannot implement previously implemented interface %s", ce->name, iface->name);
			}
		}
	}
	if (!ignore) {
		if (ce->num_interfaces >= current_iface_num) {
			if (ce->type == ZEND_INTERNAL_CLASS) {
				ce->interfaces = (zend_class_entry **) realloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num));
			} else {
				ce->interfaces = (zend_class_entry **) erealloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num));
			}
		}
		ce->interfaces[ce->num_interfaces++] = iface;	//	接口数加1,将接口加入接口列表中
 
		/* 合并接口中的常量列表和方法列表 */
		zend_hash_merge_ex(&ce->constants_table, &iface->constants_table, (copy_ctor_func_t) zval_add_ref, sizeof(zval *), (merge_checker_func_t) do_inherit_constant_check, iface);
		zend_hash_merge_ex(&ce->function_table, &iface->function_table, (copy_ctor_func_t) do_inherit_method, sizeof(zend_function), (merge_checker_func_t) do_inherit_method_check, ce);
 
		do_implement_interface(ce, iface TSRMLS_CC);
		zend_do_inherit_interfaces(ce, iface TSRMLS_CC);
	}
}

从zend_do_implement_interface函数的合并接口中的常量列表和方法列表操作,我们可以猜想这也许是接口中不能有变量可以有常量的原因之一吧
在接口继承的过程中有对当前类的接口中是否存在同样接口的判断操作,如果已经存在了同样的接口,则此接口将不会继承。
如下所示php代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
interface FooInterface {
	public function method1();
}
 
class Base implements FooInterface {
	public function method1() {
		echo 'ss';
	}
}
 
class Foo extends Base implements FooInterface {
 
}
 
$foo = new Foo();
$foo->method1();

PHP源码阅读笔记二十九:接口的继承》上有3条评论

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

  2. Pingback引用通告: PHP源码分析文章整理 | 牛腩五花肉的博客-linux系统编程

  3. xiaolei

    请教看了关于zend 内存管理这部分
    #define ZEND_MM_SMALL_FREE_BUCKET(heap, index) \
    (zend_mm_free_block*) ((char*)&heap->free_buckets[index * 2] + \
    sizeof(zend_mm_free_block*) * 2 – \
    sizeof(zend_mm_small_free_block))

    不理解最后减去sizeof(zend_mm_small_free_block))这个结构的意义何在?
    谢谢了

    回复

xiaolei进行回复 取消回复

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


*

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