ホームページ  >  記事  >  バックエンド開発  >  オリジナル: PHP カーネルの研究とその他の実装

オリジナル: PHP カーネルの研究とその他の実装

黄舟
黄舟オリジナル
2016-12-22 09:56:421126ブラウズ

最近はとても忙しくて、週末にまた記事を書きます
クラスはオブジェクト指向です。 OOP の略称。英語名は Object Oriented Programming です。
オブジェクト指向とは何ですか?
OOP の基本原理は、サブルーチンとして機能する単一のユニットまたはオブジェクトで構成されるということです。 . OOP は、再利用性、柔軟性、拡張性というソフトウェア エンジニアリングの 3 つの目標を達成します
ここで話していることは、クラスとは何か、オブジェクト指向とは何かを知らない場合は、この記事は現時点では適切ではありません。

classperson{

};

上記は、PHP クラスの作成方法を示しています。 Zendは、class_T_STRINGを作成しますZEND_ACC_EXPLICIT_ABSTRACT_CLASS; }

|

T_CLASS、T_ABSTRACT T_CLASS、T_FINAL は PHP の 3 つのモードです
​​T_CLASS: 標準クラスを宣言します

T_ABSTRACT: 抽象クラスを宣言します

T_FINAL:継承を許可する

もちろんインターフェースもあります

それらはファイル /zend_complie.h で Zend で定義されています

#define ZEND_ACC_IMPLICIT_ABSTRACT_CLASS 0x10 //抽象として宣言されていませんが、内部に抽象メソッドがあります

#define ZEND_ACC_EXPLICIT_ABSTRACT_CLASS 0x 20 //抽象

#define ZEND _ACC_FINAL_CLASS 0x40 //最終

#define ZEND_ACC_INTERFACE 0x80 /​​/インターフェース

これらの 3 つのルールは、現在の行を記録し、クラスのタイプを設定します。
クラスを定義するときに、2 つのメソッド zend_do_begin_class_declaration と zend_do_end_class_declaration が呼び出されます。
クラスのキーワード、クラスの名前、および継承された親クラスが渡されます。
zend_do_begin_class_declaration は、クラスの宣言、型の設定、およびクラス内の属性とメソッドを処理するための
zend_do_end_class_declaration の作成に使用されます
2 つの関数について説明する前に、まず構造について説明する必要があります。保存されたクラス zend_class_entry の


struct_zend_class_entry を定義します

struct_zend_class_entry {

struct_zend_class_entry *parent;//継承された親クラス

intrefcount; // 参照数

zend_bool constants_updatedハッシュテーブルのdefault_properties; // Hashtable Properties_info;

Union_zend_function *__ GET;

Union_zend_function *__set;

Union_zend_function *__unset;

union_ zend_function *__call;

Union_zend_function *__tostring;

with with with with with with with with, with zend_class_iterator_funcs iterator_funcs ;

を使用してください‐ ‑ ‑ (*get_iterator)(zend_class_entry *ce, zval *object,intby_ref TSRMLS_DC);

int (*interface_gets_implemented)(zend_class_エントリ *iface、zend_class_entry *class_type TSRMLS_DC );/* クラスはこのインターフェイスを実装します */

union_zend_function *(*get_static_method)(zend_class_entry *ce,char* method,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) ; 文字*filename;//クラスのファイルアドレスを宣言します

Line zend_uint line_end; // クラス終了行

char*doc_comment;

-

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;

interror = 0;

zval **ns_name;

if( CG(active_class_entry)) {

zend_error(E_COMPILE_ERROR,"クラス宣言はネストできません");

return;

lcname = zend_str_to lower_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_import), lcname, Z_STRLEN(class_name->u.constant)+1, (void**)&ns_name) == SU CCESS) {

error = 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_to lower_dup(Z_STRVAL(class_name) ->u.constant), Z_STRLEN(class_name->u.constant));

}

if(error) {

char*tmp = Z_STRVAL_PP(ns_name)、Z_STRLEN_PP(ns_name)) ;

if(Z_STRLEN_PP(ns_name) != Z_STRLEN(class_name->u.constant) ||

memcmp(tmp, lcname, EN(クラス名->u.定数))) {

zend_error(E_COMPILE_ERROR,"その名前はすでに使用されているため、クラス %s を宣言できません", Z_STRVAL(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 = クラス名->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) {

switch(parent) _クラス名->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,"「static」は予約されているため、クラス名として使用できません");

break;

def結果:

Break;

}

doing_inheritance = 1;

}

opline = TSRMLS_CC);

opline->op1.op_type = IS_CONST;

build_runtime_define_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;

opline->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));

opline->result.op_type = IS_VAR;

CG(imple menting_class) = opline->result ;

if(CG(doc_comment)) {

CG(active_class_entry)->doc_comment = CG(doc_comment);

CG(active_class_entry) ->doc_comment_len = CG(doc_comment_len);

CG(doc_comment ) = NULL;

CG(doc_comment_len) = 0;

}

}

lcname = zend_str_to lower_dup(class_name->u.cons) tant.value.str.val、class_name->u.constant .value.str.len);
すべての種類のすべての转换は小写处処理です。これは何かということですPHP大小写不感受性の原因です。
if (!(strcmp(lcname, “self”) && strcmp(lcname, “parent” ))) {
efree(lcname);
zend_error(E_COMPILE_ERROR, “「%s」は予約されているため、クラス名として使用できません”, class_name->u.constant.value.str.val);
}
类の名前はselfとparentであることはできません。
第23-26行は、クラス名が重複しているかどうかを検査するために使用します。
第27-37行は、設定命名空間を設定するために使用します。これはPHP5.3の新特性です
第39-47行は、使用します来襲定常的错误
第49-57行 初期化保存型の構造
zend_initialize_class_data(new_class_entry, 1 TSRMLS_CC);関数は初期化のための構造空間のHashTable、魔术メソッドです。上提示( HashTable *静的メンバー; //静态成员,当是用户推奨のクラスに相当するdefault_static_members,内部配置のクラスがNULL)の原因
第58-73行同伴用に检测父类のクラス名に保持关字が含まれているかどうかself,parent,static
剩下つまり、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会当然、この関数の中にこのクラスが存在するかどうか判断します。存在しない場合は、内部 Zend エラー – %s のクラス情報が欠落しています
結果が存在します。就创建成功。
次の节就は内部完了哦に深入りします…

以上は原文:PHP内核研究の类的内容、更なる相关内容请关注PHP中文网(www.php.cn) )!

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。