>  기사  >  백엔드 개발  >  원본: PHP 커널 연구 및 기타 구현

원본: PHP 커널 연구 및 기타 구현

黄舟
黄舟원래의
2016-12-22 09:56:421161검색

요즘 너무 바빠서.. 글 쓸 시간이 없네요.. 주말에 글 몇개 더 쓰겠습니다.
현재 대부분의 언어는 수업을 지원합니다.
클래스란 무엇인가요? 클래스는 객체 지향, 영어로 OOP입니다.
객체 지향이란 무엇인가요?
OOP의 기본 원리는 컴퓨터입니다. 프로그램은 서브루틴으로 작동할 수 있는 단일 단위 또는 객체로 구성됩니다. OOP는 소프트웨어 엔지니어링의 세 가지 목표를 달성합니다: 재사용성, 유연성 및 확장성
여기서는 간단한 설명을 말하는 것이 아닙니다. 클래스가 무엇인지, 객체지향이 무엇인지 모릅니다... 그렇다면 이 글은 현재

classPerson{

};

위는 PHP Class를 생성하는 것입니다. class는 PHP에서 키워드로 Zend가 클래스를 생성하는 방법을 알 수 있습니다.


unticked_class_declaration_statement:

class_entry_type T_STRING extends_from

                                         implementations_list

>

                  '}'{ 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

의 구조에 대해 이야기해 보겠습니다. >
struct_zend_class_entry {

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)!



성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.