Home > Article > Backend Development > Original: PHP kernel research and other implementations
I’ve been quite busy these days. I don’t have time to write. I’ll write a few more articles during the weekend.
Most languages currently support classes.
What are classes? Classes are object-oriented, or OOP for short. The English name is Object Oriented Programming.
What is object-oriented? It is a programming architecture.
A basic principle of OOP is that a computer program is composed of a single unit or object that can function as a subroutine. OOP achieves three goals of software engineering: Reusability , flexibility and scalability.
Because what we are talking about is not just a simple description here. If you don’t know what a class is and what is object-oriented... then this article is not suitable for you at the moment.
classPerson{
};
The above is to create a PHP class. class is the keyword of PHP. Through it we can find out how Zend creates the class. class_entry_type T_STRING extends_from
LS_CC); }
| interface_entry T_STRING TSRMLS_CC); }
T_CLASS, T_ABSTRACT T_CLASS and T_FINAL are the three modes of PHP
T_CLASS: It is a standard class.T_ABSTRACT: It declares an abstract class
T_FINAL: It declares a class that does not allow inheritance and extension.Of course there is also interface
They are defined in Zend In the file /zend_complie.h #define ZEND_ACC_IMPLICIT_ABSTRACT_CLASS 0x10 //Not declared as abstract, but there are abstract methods inside #define ZEND_ACC_EXPLICIT_ABSTRACT_CLASS 0x20 //Abstract#define ZEND _ACC_FINAL_CLASS 0x40 //Final#define ZEND_ACC_INTERFACE 0x80 //InterfaceThese three rules record the current line and set the type of the class.
When defining the class, the two methods zend_do_begin_class_declaration and zend_do_end_class_declaration are called.
The keyword of the class, the name of the class and the inherited parent class are passed as parameters to this Two functions.
zend_do_begin_class_declaration is used to declare a class, set the type, and create a
zend_do_end_class_declaration to process the attributes and methods in the class.
Before talking about the two functions, we must first talk about the structure of the saved class zend_class_entry
It defines In Zend/zend.h
struct_zend_class_entry {
struct_zend_class_entry *parent;//Inherited parent class
intrefcount; //Number of references
zend_bool constants_updated HashTable default_properties;//Properties
B Hashtable Properties_info; // The access level of the function hashtable default_Static_members; // Static members havetable *static_members; _Static_members, the built -in class is null hashtable constants_table;C Construct_zend_function_ENTRY *Builtin_functions;
// Is it familiar ??? The magic function is here ...
union_function *constructor; UCTOR; n Union_zend_function *Clone;
Union_zend_function *__ GET;
union_zend_function *__set;
union_zend_function *__unset;
union_zend_function *__isset;
union_zend_function *__call;
union_zend_function *__tostring;
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_entry *iface, zend_class_entry *class_type TSRMLS_DC);/* a class implements this interface */
union_zend_function *(*get_static_method)(zend_class_entry *ce,char* method,intmethod_len TSRMLS_DC);
/ * serializer callbacks */
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); char*filename; //Declare the file address of the class
zend_uint line_start; // Class start Line
zend_uint line_end; // Class end line
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,"Class declarations may not be nested");
return;
}
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,"Cannot use '%s' as class name as it is reserved", class_name->u.constant.value.str.val);
}
/* Class name must not conflict with import names */
if(CG(current_import) &&
zend_hash_find(CG(current_import), lcname, Z_STRLEN(class_name->u.constant)+1, (void**)&ns_name) == SUCCESS) {
error = 1;
}
if(CG(current_namespace)) {
/* Prefix class name with name of 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));
if(Z_STRLEN_PP(ns_name) != Z_STRLEN(class_name->u.constant) ||
memcmp(tmp, lcname, Z_STRLEN(class_name->u.constant))) {
zend_error(E_COMPILE_ERROR,"Cannot declare class %s because the name is already in use", 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 = 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) {
switch(parent_class_name->u.EA.type) {
caseZEND_FETCH_CLASS_SELF:
zend_error(E_COMPILE_ERROR,"Cannot use 'self' as class name as it is reserved");
break;
caseZEND_FETCH_CLASS_PARENT:
zend_error(E_COMPILE_ERROR,"Cannot use 'parent' as class name as it is reserved");
break;
caseZEND_FETCH_CLASS_STATIC:
zend_error(E_COMPILE_ERROR,"Cannot use 'static' as class name as it is reserved");
break;
default:
break;
}
doing_inheritance = 1;
}
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
opline->op1.op_type = IS_CONST;
build_runtime_defined_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(implementing_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_tolower_dup(class_name->u.constant.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, “Cannot use ‘%s’ as class name as it is reserved”, 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 *static_members; //静态成员,当是用户声明的类等于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会将此类放到class_table中.当然 ,在这个函数里还会判断该类是否存在.不存在会抛出错误
Internal Zend error – Missing class information for %s
如果存在 则会添加成功
那么到这里类就创建成功了.
下一张节就要深入到 类内部了哦…
以上就是原创:PHP内核研究之类的实现的内容,更多相关内容请关注PHP中文网(www.php.cn)!