요즘 너무 바빠서.. 글 쓸 시간이 없네요.. 주말에 글 몇개 더 쓰겠습니다.
현재 대부분의 언어는 수업을 지원합니다.
클래스란 무엇인가요? 클래스는 객체 지향, 영어로 OOP입니다.
객체 지향이란 무엇인가요?
OOP의 기본 원리는 컴퓨터입니다. 프로그램은 서브루틴으로 작동할 수 있는 단일 단위 또는 객체로 구성됩니다. OOP는 소프트웨어 엔지니어링의 세 가지 목표를 달성합니다: 재사용성, 유연성 및 확장성
여기서는 간단한 설명을 말하는 것이 아닙니다. 클래스가 무엇인지, 객체지향이 무엇인지 모릅니다... 그렇다면 이 글은 현재
classPerson{
};
위는 PHP Class를 생성하는 것입니다. class는 PHP에서 키워드로 Zend가 클래스를 생성하는 방법을 알 수 있습니다.'}'{ zend_do_end_class_declaration(&$1 , &$2 TSRMLS_CC); { zend_do_begin_class_declaration(&$1 , &$2, NULL TSRMLS_CC) }
인터페이스_확장 목록
class_statement_list
~ > $2 TSRMLS_CC); }
;
class_entry_type:
T_ABSTRACT T_CLASS { $ $.u.opline_num = CG(zend_lineno); $$.u.EA.type = ZEND_ACC_EXPLICIT_ABSTRACT_CLASS; }
| T_FINAL T_CLASS { $$.u.opline_num = CG(zend_lineno) }
; >
T_CLASS, T_ABSTRACT T_CLASS 및 T_FINAL은 PHP의 세 가지 모드입니다.
T_CLASS:T_ABSTRACT: 추상 클래스를 선언합니다. 🎜>T_FINAL: 상속과 확장을 허용하지 않는 클래스를 선언합니다.
물론 인터페이스도 있습니다Zend/zend_complie.h 파일에 정의되어 있습니다. Medium
#define ZEND_ACC_INTERFACE 0x80 //인터페이스
이 세 가지 규칙은 현재 행을 기록하고 클래스 유형을 설정합니다.
클래스를 정의할 때 zend_do_begin_class_declaration 및 zend_do_end_class_declaration 두 가지 메소드가 호출됩니다.
클래스의 키워드와 클래스 이름. 상속된 부모 클래스는 이 두 함수에 매개변수로 전달됩니다.
zend_do_begin_class_declaration은 클래스를 선언하고, 유형을 설정하고,
zend_do_end_class_declaration을 생성하여 클래스의 속성과 메서드를 처리하는 데 사용됩니다. 두 함수에 대해 이야기하기 전에 먼저 Zend/zend.h
chartype;
char*name;//클래스 이름
zend_uint name_length;
struct_zend_class_entry *parent;//상속됨 상위 클래스
intrefcount ; //참조 수
zend_bool Constants_updated; zend_ Table
HashTable default_properties;//Properties
HashTable Properties_info; 함수 수준
HashTable default_static_members;//Static 멤버
Hash Table *static_members ;//Static 멤버, 사용자가 선언한 클래스가 default_static_members와 같을 때 내장 클래스는 NULL입니다.
HashTable Constants_table; ??네. 마법의 함수가 여기에 있습니다..
Union_zend_function *constructor; Union_zend_function * __get;
Union_zend_function *__set;
Union_zend_function *__unset;
Union_zend_function *__isset;
Union_zen d_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;
/* 핸들러 */
zend_object_value (*create_object)(zend_class_entry *class_type TSRMLS_DC);
zend_object_iterator *(*get_iterator)( zend_class_entry *ce, zval *object,intby_ref TSRMLS_DC);
int(*interface_gets_implemented )(zend_class_entry *iface, zend_class_entry *class_type TSRMLS_DC);/* 클래스는 이 인터페이스를 구현합니다 */ 메소드) (zend_class_entry *ce,char* 메소드,intmethod_len TSRMLS_DC);
/* 직렬 변환기 콜백 */
int(*serialize)(zval *object, unsignedchar** buffer, zend_uint *buf_len, zend_serialize_data *data TSRMLS_DC);
int(*unserialize)(zval ** object, zend_class_entry *ce,constunsignedchar*buf, zend_uint buf_len, zend_unserialize_data *data TSRMLS_DC);
zend_class_entry **인터페이스;
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;
};
清楚了这个结构之后来看看zend_do_begin_class_declaration函数
voidzend_do_begin_class_declaration(constznode *class_token, znode *class_name,constznode *parent_class_name TSRMLS_DC)/* {{{ */
{
zend_op *opline ;
intdoing_inheritance = 0;
zend_class_entry *new_class_entry;
char*lcname;
inerror = 0;
zval ** ns_name;
if(CG(active_class_entry)) {
zend_error(E_COMPILE_ERROR,"클래스 선언이 중첩될 수 없습니다.");
반품;
}
lcname = zend_str_tolower_dup(class_name->u.constant.value.str.val, class_name->u.constant.value.str.len );
if(!(strcmp(lcname,"self") &&strcmp(lcname,"parent"))) {
efree(lcname);
zend_error(E_COMPILE_ERROR,"'%s'은(는) 예약되어 있으므로 클래스 이름으로 사용할 수 없습니다.", class_name->u.constant.value.str.val);
}
/* 클래스 이름은 가져오기 이름과 충돌해서는 안 됩니다. */
if(CG(current_import) &&
zend_hash_find(CG(current_im 포트), lc이름, Z_STRLEN( class_name->u.constant)+1, (void**)&ns_name) == 성공) {
오류 = 1;
}
if(CG( current_namespace)) {
/* 현재 네임스페이스 이름으로 클래스 이름 접두사 */
znode tmp;
tmp.u.constant = * CG(current_namespace);
zval_copy_ctor(&tmp.u.constant);
zend_do_build_namespace_name(&tmp, &tmp, class_name TSRMLS_CC);
class_name = &tmp;
efree(lcname);
lcname = zend_str_tolower_dup(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant));
}
if(error) {
char*tmp = zend_str_tolower_dup(Z_STRVAL_PP(ns_name), Z_STRLEN_PP(ns_name));
인 경우 (Z_STRLEN_PP(ns_name) != Z_STRLEN(class_name->u.constant) ||
memcmp(tmp, lcname, Z_STRLEN(class_name->u.constant))) {
> efree(tmp ); } new_class_entry = emalloc(sizeof(zend_class_entry)); new_class_entry->type = ZEND_USER_CLASS; new_class_entry->name = class_name->u.constant.value.str.val; new_class_entry->name_length = class_name->u.constant.value.str.len;zend_initialize_class_data(new_class_entry, 1 TSRMLS_CC); new_class_entry->filename = zend_get_compiled_filename(TSRMLS_C); new_class_entry->line_start = class_token-> u.opline_num; new_class_entry->ce_flags |= class_token->u.EA.type;if(parent_class_name && parent_class_name->op_type != IS_UNUSED) {
스위치(parent_class_name->u.EA.type) { caseZEND_FETCH_CLASS_SELF: zend_error(E_COMPILE_ERROR,"'self'는 예약되어 있으므로 클래스 이름으로 사용할 수 없습니다."); break; caseZEND_FETCH_CLASS_PARENT: zend_error(E_COMPILE_ERROR,"'부모'는 예약되어 있으므로 클래스 이름으로 사용할 수 없습니다."); break; caseZEND_FETCH_CLASS_STATIC: zend_error(E_COMPILE_ERROR,"'정적'은 예약되어 있으므로 클래스 이름으로 사용할 수 없습니다. "); break; 기본값: break; } doing_inheritance = 1; } opline = get_next_op(CG( active_op_array) TSRMLS_CC); opline->op1.op_type = IS_CONST; build_runtime_definition_function_key(&opline->op1.u.constant, lcname, new_class_entry->name_length TSRMLS_CC);
opline->op2.op_type = IS_CONST;
opline->op2.u.constant.type = IS_STRING;
Z_SET_REFCOUNT(opline->op2.u.constant , 1);
if(doing_inheritance) {
opline->extended_value = parent_class_name->u.var;
오프라인-> ;opcode = ZEND_DECLARE_INHERITED_CLASS;
}else{
opline->opcode = ZEND_DECLARE_CLASS;
}
opline->op2.u.constant .value.str.val = lcname;
opline->op2.u.constant.value.str.len = new_class_entry->name_length;
zend_hash_update (CG(class_table), opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, &new_class_entry,sizeof(zend_class_entry *), NULL);
CG(active_class_entry) = new_class_entry;
opline->result.u.var = get_temporary_variable(CG(active_op_array));
오프라인- >result.op_type = IS_VAR;
CG(implementing_class) = opline->result;
if(CG(doc_comment)) {
> CG(doc_comment) = NULL;
CG(doc_comment_len) = 0;
}
lcname = up(class_name->if (!(strcmp(lcname, “self”) && strcmp(lcname, “parent”))) {
efree(lcname);zend_error(E_COMPILE_ERROR, “'%s'을(를) 클래스로 사용할 수 없습니다 예약된 이름입니다”, class_name->u.constant.value.str.val);
}类的name字不能是selfhwaparent.
第23-26行 用来检测类name是否复复定义.
제27-37行 用来设置命name 空间,这是PHP5.3의 새로운 특질
第39-47行 用来抛复定义的错误
第49-57行 初始化保存类的结构
zend_initialize_class_data(new_class_entry, 1 TSRMLS_CC);函数是用来初始化结构里면적 HashTable, 실행 방법.
这个函数里면也 유상면提到( HashTable *static_members; //静态成员,当是사용户声명명한类等于default_static_members,内置的类为NULL)의 원본
第58-73行 同样检测父类的类name是否包含关键字 자기,부모,정적
剩下的就是用来生成一个OP,
是内部类:那么生成的OP中间代码就是 ZEND_DECLARE_INHERITED_CLASS
是用户类:OP中间代码就是ZEND_DECLARE _CLASS
현재 这之后..Zend引擎会调用zend_execute函数执行OP 中间代码ZEND_DECLARE_CLASS_SPEC_HANDLER
它定义在Zend/zend_vm_execute.h中.
这个函数将执行关键代码
EX_T( opline->result.u.var).class_entry = do_bind_class (opline, EG(class_table), 0 TSRMLS_CC) ;
do_bind_class会将此类放到class_table中.当然 ,현재 这个函数里还会判断该类是否存재.不存会抛存孙误
내부 젠드 오류 – %s에 대한 클래스 정보가 누락되었습니다
如果存在 则会添加成功
那么到这里类就创建成功了.
下一张节就要深入到 类内부 了으…
以上就是原创:PHP内核研究之类的实现的内容,更多更关内容请关注PHP中文网(www.php.cn)!