이 글에서는 PHP 클래스의 멤버 속성과 메서드에 대해 자세히 설명하겠습니다.
이전 글에서는 zend_class_entry를 생성하고 초기화하는 데 사용되는 zend_do_begin_class_declaration 함수를 소개했습니다.
클래스가 저장되는 구조입니다.
1
2
3
classPerson{
public$name;
}
또한 이전 글에서 언급한 zend_initialize_class_data 함수를 기억해두셔도 상관없습니다.
zend_initialize_class_data(new_class_entry, 1 TSRMLS_CC);
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
ZEND_APIvoidzend_initialize_class_data(zend_class_entry *ce , zend_bool nullify_handlers TSRMLS_DC)/ * {{ { */
{
zend_bool persist_hashes = (ce->type == ZEND_INTERNAL_CLASS) ?ZVAL_INTERNAL_PTR_DTOR: ZVAL_PTR_ DTOR) ;
ce->refcount = 1;
ce->constants_updated = 0;
ce->ce_fla gs = 0 ;
ash_init_ex(&ce ->default_properties, 0, NULL, zval_ptr_dtor_func, persist_hashes, 0);
zend_hash_init_ex(&ce->properties_info, 0, NULL, (dtor_func_t) (percious_hashes ? ternal: zend_destroy_property_info) , 영구_해시, 0);
zend_hash_init_ex(&ce->default_static_members, 0, NULL, zval_ptr_dtor_func, persist_hashes, 0); zend_hash_init_ex(&ce->constants_table, 0, NULL, zval_ptr_dtor_func, persist_hashes, 0);
zend_hash_init_ex(&ce->function_table, 0, NULL, ZEND_FUNCTION_DTOR, persist_hashes, 0);
if(ce->type == ZEND_INTERNAL_CLASS) {
# ifdef ZTS
intn = zend_hash_num_elements(CG(class_table));
if(CG(static_members) && n >= CG(last_static_member)) {
/* 런타임 선언 지원: dl() CG(static_members) =realloc(CG(static_members), (n+1)*sizeof(HashTable*));
CG(static_members)[n] = NULL;
}
ce->static_members = (HashTable *)(zend_intptr_t)n;
#else
ce->static_members = NULL 🎜> ce->static_members = &ce->default_static_members;
}
if(nullify_handlers) {
ce->constructor = NULL;
ce->destructor = NULL;
ce->clone = NULL;
ce->__get = NULL;
ce->__set = NULL;
ce->__unset = NULL;
ce- >__isset = NULL;
ce->__call = NULL;
ce->__callstatic = NULL;
ce->__ tostring = NULL;
ce->create_object = NULL;
ce->get_iterator = NULL;
ce->iterator_funcs.funcs = NULL;
ce- >interface_gets_implemented = NULL;
ce->get_static_method = NULL;
ce->parent = NULL;
ce->num_interfaces = 0;
ce->인터페이스 = NULL;
ce->모듈 = NULL;
ce->serialize = NULL;
ce-> unserialize = NULL;
ce->serialize_func = NULL;
ce->unserialize_func = NULL;
ce->builtin_functions = NULL;
}
}
zend_bool persist_hashes = (ce->type == ZEND_INTERNAL_CLASS) ? 1 : 0;
普什么会有区别呢???我还没来得及研究哦..^.^
注意看13-1 6행.
zend_hash_init_ex(&ce->default_properties, 0, NULL, zval_ptr_dtor_func, persist_hashes, 0);
zend_hash_init_ex(&ce->default_static_members, 0, NULL, zval_ptr_dtor_func, persist_hashes, 0);
zend _hash_init_ex(&ce- >constants_table, 0, NULL, zval_ptr_dtor_func, persist_hashes, 0);
zend_hash_init_ex(&ce->function_table, 0, NULL, ZEND_FUNCTION_DTOR, persist_hashes, 0);
如果你看过之前的文章,那么你肯 정정지식은 HashTable을 기반으로 합니다.
是的..确实是这样,
default_properties,default_static_members等TU是HashTable은 指针.所以初始化当然要zend_h ash_init了.
第36-61行初始化魔术방법
不过这里只是初始化哦..好image并没有设置属性.$name属性是如何添加到属性表里的呢???
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
unticked_class_declaration_statement:
class_entry_type T_STRING
에서{ zend_do_begin_class_declaration(&$1, &$2, &$3 TSRMLS_CC); }
implements_list
'{'
class_statement_list
'}'{ zend_do_end_class_declaration(&$1, &$2 TSRMLS_CC); }
| interface_entry T_STRING
{ zend_do_begin_class_declaration(&$1, &$2, NULL TSRMLS_CC); }
interface_extends_list
'{'
class_statement_list
'}'{ zend_do_end_class_declaration(&$1, &$2 TSRMLS_CC); }
;
class_statement:
variable_modifiers { CG(access_type) = Z_LVAL($1.u.constant); } class_variable_declaration';'
| class_constant_declaration';'
| method_modifiers 함수 is_reference T_STRING { zend_do_begin_function_declaration(&$2, &$4, 1, $3.op_type, &$1 TSRMLS_CC); }'('
parameter_list')'method_body { zend_do_abstract_method(&$4, &$1, &$9 TSRMLS_CC); zend_do_end_function_declaration(&$2 TSRMLS_CC); }
;
class_variable_declaration:
class_variable_declaration','T_VARIABLE { _declare_property(&$3, NULL, CG(access_type) TSRMLS_CC); }
| class_variable_declaration','T_VARIABLE'='static_scalar { zend_do_declare_property(&$3, &$5, CG(access_type) TSRMLS_CC); }
| T_VARIABLE { zend_do_declare_property(&$1, NULL, CG(access_type) TSRMLS_CC); }
| T_VARIABLE'='static_scalar { zend_do_declare_property(&$1, &$3, CG(access_type) TSRMLS_CC); }
;
这个还记得吧?
类初始化成功后类里平东西当然要执行class_statement _list这个啦.. ^.^
类体里会调사용 zend_do_declare_property处리.
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
voidzend_do_declare_property(constznode *var_name,constznode *value, zend_uint access_type TSRMLS_DC)/* {{{ */
{
zval *property;
zend_property_info *exist ing_property_info;
char*comment = NULL;
intcomment_len = 0;
if(CG(active_class_entry)->ce_flags & ZEND_ACC_INTERFACE)
zend_error(E_COMPILE_ERROR,"인터페이스에 멤버 변수가 포함될 수 없습니다.");
}
if(access_type & ZEND_ACC_ABSTRACT) {
zend_error (E_COMPILE_ERROR,"속성은 추상적으로 선언할 수 없습니다.");
}
if(access_type & ZEND_ACC_FINAL) {
zend _error(E_COMPILE_ERROR,"할 수 없습니다 %s::$%s final 속성을 선언하세요. final 수정자는 메서드 및 클래스에만 허용됩니다.",
CG(active_class_entry)->name, var_name->u.constant.value.str. val);
}
if(zend_hash_find(&CG(active_class_entry)->properties_info, var_name->u.constant.value.str.val, var_name ->u.constant.value.str.len+1, (void**) &existing_property_info)==SUCCESS) {
if(!(existing_property_info->flags & ZEND_ACC_IMPLICIT_PUBLIC)) {
zend_error(E_COMPILE_ERROR,"%s::$%s을(를) 다시 선언할 수 없습니다", CG(active_class_entry)->name, var_name->u.constant.value.str.val);
}
}
ALLOC_ZVAL(속성);
if(값) {
*적절 ty = 값 -> u. 상수;
}else{
INIT_PZVAL(속성);
Z_TYPE_P(속성) = IS_NULL;
}
> CG(doc_comment) = NULL ; CG(doc_comment_len) = 0; } zend_declare_property_ex(CG(active_class_entry), var_name->u.constant.value. str.val, var_name->u.constant.value.str.len, 속성, access_type, comment, comment_len TSRMLS_CC); efree(var_name->u.constant.value.str.val) ;}
8-25행:
클래스가 인터페이스를 선언하면 인터페이스는 속성을 가질 수 없으며 인터페이스는 멤버 변수를 포함할 수 없습니다.
클래스의 속성이 추상으로 설정되면 다음이 발생합니다. throw 속성은 추상으로 선언할 수 없습니다
클래스의 속성이 final로 설정되면 throw Cannot 선언 속성 %s::$%s final, final 수정자는 메서드 및 클래스에만 허용됩니다
모두 OK이면 zval 데이터가 할당됩니다.
속성에 초기 값이 있으면 데이터가 zval에 할당됩니다. 그렇지 않으면 INIT_PZVAL이 호출되어 zval을 초기화하고 유형이 IS_NULL로 설정됩니다.
마지막으로 zend_declare_property_ex가 호출됩니다. 지정된 active_class_entry에 zval을 추가합니다
클래스 메서드
1
2
3
4
5
classPerson{
publicfunctiontest(){
echo1;
}
}
메소드라면 어떻게 처리되나요?
규칙을 먼저 살펴보세요
1
2
3
4
5
class_statement:
CG(access_type) = Z_LVAL($1.u.constant); } class_variable_declaration';'
gin_function_declaration(&$2, &$4, " RMLS_CC); }
첫 번째가 속성이고, 세 번째가 메소드...
zend_do_begin_function_declaration이 낯익은 것 같나요?이전 내용을 읽어보셨다면 기사, 당신은 분명 친숙해 보인다
아직 읽지 않았다면 먼저 이 기사를 읽어보세요여기서는 자세히 설명하지 않겠습니다.
무슨 내용인지만 이야기하겠습니다. 해당 글에는 언급되지 않았습니다
이 기능에는
1
2
3
4에 판단이 있습니다.
5
6
7
8
9
10
11
if (is_method) {
if(CG(active_class_entry)->ce_flags & ZEND_ACC_INTERFACE) {
if((Z_LVAL(fn_flags_znode-&g) t;u.constant) & ~(ZEND_ACC_STATIC|ZEND_ACC_PUBLIC) :) .str.val);
나머지 파서 */
}
fn_flags = Z_LVAL( fn_flags_znode->u.constant); fn_flags = 0;
}
물론, 그럼 그것
3-5줄: 인터페이스 클래스의 속성을 private 또는 protected로 설정하면 인터페이스 메서드 %s::%s()에 대한 액세스 유형을 생략해야 합니다가 발생하고 그런 다음
if (zend_hash_add()가 호출됩니다 &CG(active_class_entry)->function_table, lcname, name_len+1, &op_array, sizeof(zend_op_array), (void **) &CG(active_op_array)) == FAILURE) {zend_error(E_COMPILE_ERROR, “Cannot redeclare %s: :%s()”, CG(active_class_entry)->name, name);
}function_table에 직접 메서드를 추가합니다.
다음 클래스 선언에 따라 다른 판단을 내리게 됩니다. 위 내용은 원본 내용입니다. PHP 커널 연구 및 기타 회원 속성 및 방법에 대한 자세한 내용은 PHP 중국어 홈페이지(www.php.cn)를 참고해주세요!