PHP保存类及特别类
在面向对象说话中,都会内置一些说话内置供给的根本功效类,比方JavaScript中的Array,Number等类,PHP中也有许多这品种,比方Directory,stdClass,Exception等类,同时一些标准扩展比方PDO等扩展中也会定义一些类,PHP中类是不同意反复定义的,所以在编写代码时不同意定义已经存在的类。
同时PHP中有一些非凡的类:self
,static
和parent
,信赖读者对这self和parent都比力熟知了,而static非凡类是PHP5.3才引入的。
PHP中的static关键字非常多义:
● 在函数体内的润饰变量的static关键字用于定义静态部分变量。
● 用于润饰类成员函数和成员变量时用于声明静态成员。
● (PHP5.3)在作用域解析符(::)前又表示静态延迟绑定的非凡类。
这个关键字润饰的意义都表示"静态",在PHP手册中提到self,parent和static这几个关键字,但实际上除了static是关键字之外,其他两个均不是关键字,在手册的关键字列表中也没有这两个关键字,要验证这一点很简便:
<?php [var_dump](http://www.php.net/var_dump)(self); // -> string(4) "self"
上面的代码并没有报错,假如你把error_reporting(E_ALL)翻开,就能看到实际是啥状况了:运转这段代码会显现“ Notice: Use of undefined constant self - assumed 'self'“,也就是说PHP把self当做一个一般常量了,尝试不决义的常量会把产量本身当做一个字符串,例如上例的”self",不外同时会出一个NOTICE,这就是说self这个标示符并没有什么非凡的。
<?php [define](http://www.php.net/define)('self',"stdClass"); [echo](http://www.php.net/echo) self; // stdClass
不一样说话中的关键字的意义会有些不同,Wikipedia上的说明是: 具有非凡含义的标示符或者单词,从这个意义上说$this也算是一个关键字,但在PHP的关键字列表中并没有。 PHP的关键字和C/C++一样属于保存字(关键字),关键字用于表示特定的语法情势,例如函数定义,流程操纵等构造。 这些关键字有他们的特定的使用处景,而上面提到的self和parent并没有这样的限制。
self,parent,static类
前面已经说过self的非凡性。self是一个非凡类,它指向当前类,但只要在类定义内部才有效,但也并不必然指向类本身这个非凡类,比方前面的代码,假如放在类办法体内运转,echo self; 还是会输出常量self的值,而不是当前类,它不止要求在类的定义内部,还要求在类的上下文环境,比方 new self()的时候,这时self就指向当前类,或者self::$static_varible,self::CONSTANT相似的作用域解析符号(::),这时的self才会作为指向本身的类而存在。
同理parent也和self相似。下面先看看在在类的环境下的编译吧$PHP_SRC/Zend/zend_language_parser.y:
class_name_reference: class_name { zend_do_fetch_class(&$$, &$1 TSRMLS_CC); } | dynamic_class_name_reference { zend_do_end_variable_parse(&$1, BP_VAR_R, 0 TSRMLS_CC); zend_do_fetch_class(&$$, &$1 TSRMLS_CC); } ;
在需要猎取类名时会施行zend_do_fetch_class()函数:
void zend_do_fetch_class(znode *result, znode *class_name TSRMLS_DC) { // ... opline->opcode = ZEND_FETCH_CLASS; if (class_name->op_type == IS_CONST) { int fetch_type; fetch_type = zend_get_class_fetch_type(class_name->u.constant.value.str.val, class_name->u.constant.value.str.len); switch (fetch_type) { case ZEND_FETCH_CLASS_SELF: case ZEND_FETCH_CLASS_PARENT: case ZEND_FETCH_CLASS_STATIC: SET_UNUSED(opline->op2); opline->extended_value = fetch_type; zval_dtor(&class_name->u.constant); break; default: zend_resolve_class_name(class_name, &opline->extended_value, 0 TSRMLS_CC); opline->op2 = *class_name; break; } } else { opline->op2 = *class_name; } // ... }
上面省略了一些无关的代码,重点关注fetch_type变量。这是通过zend_get_class_fetch_type()函数猎取到的。
int zend_get_class_fetch_type(const char *class_name, uint class_name_len) { if ((class_name_len == sizeof("self")-1) && !memcmp(class_name, "self", sizeof("self")-1)) { return ZEND_FETCH_CLASS_SELF; } else if ((class_name_len == sizeof("parent")-1) && !memcmp(class_name, "parent", sizeof("parent")-1)) { return ZEND_FETCH_CLASS_PARENT; } else if ((class_name_len == sizeof("static")-1) && !memcmp(class_name, "static", sizeof("static")-1)) { return ZEND_FETCH_CLASS_STATIC; } else { return ZEND_FETCH_CLASS_DEFAULT; } }
前面的代码是Zend引擎编译类相关操纵的代码,下面就到施行阶段了,self,parent等类的指向会在施行时停止猎取,寻到施行opcode为ZEND_FETCH_CLASS的施行函数:
zend_class_entry *zend_fetch_class(const char *class_name, uint class_name_len, int fetch_type TSRMLS_DC) { zend_class_entry **pce; int use_autoload = (fetch_type & ZEND_FETCH_CLASS_NO_AUTOLOAD) == 0; int silent = (fetch_type & ZEND_FETCH_CLASS_SILENT) != 0; fetch_type &= ZEND_FETCH_CLASS_MASK; check_fetch_type: switch (fetch_type) { case ZEND_FETCH_CLASS_SELF: if (!EG(scope)) { zend_error(E_ERROR, "Cannot access self:: when no class scope is active"); } return EG(scope); case ZEND_FETCH_CLASS_PARENT: if (!EG(scope)) { zend_error(E_ERROR, "Cannot access parent:: when no class scope is active"); } if (!EG(scope)->parent) { zend_error(E_ERROR, "Cannot access parent:: when current class scope has no parent"); } return EG(scope)->parent; case ZEND_FETCH_CLASS_STATIC: if (!EG(called_scope)) { zend_error(E_ERROR, "Cannot access static:: when no class scope is active"); } return EG(called_scope); case ZEND_FETCH_CLASS_AUTO: { fetch_type = zend_get_class_fetch_type(class_name, class_name_len); if (fetch_type!=ZEND_FETCH_CLASS_DEFAULT) { goto check_fetch_type; } } break; } if (zend_lookup_class_ex(class_name, class_name_len, use_autoload, &pce TSRMLS_CC) == FAILURE) { if (use_autoload) { if (!silent && !EG(exception)) { if (fetch_type == ZEND_FETCH_CLASS_INTERFACE) { zend_error(E_ERROR, "Interface '%s' not found", class_name); } else { zend_error(E_ERROR, "Class '%s' not found", class_name); } } } } return NULL; } return *pce; }
从这个函数就能看出端倪了,当需要猎取self类的时候,则将EG(scope)类返回,而EG(scope)指向的正是当前类。假如时parent类的话则从去EG(scope)->parent也就是当前类的父类,而static猎取的时EG(called_scope),离别说说EG宏的这几个字段,前面已经介绍过EG宏,它可以展开为如下这个构造体:
struct _zend_executor_globals { // ... zend_class_entry *scope; zend_class_entry *called_scope; /* Scope of the calling class */ // ... } struct _zend_class_entry { char type; char *name; zend_uint name_length; struct _zend_class_entry *parent; } #define struct _zend_class_entry zend_class_entry
其中的zend_class_entry就是PHP中类的内部构造表示,zend_class_entry有一个parent字段,也就是该类的父类。在EG构造体中的中called_scope会在施行历程中将当前施行的类赋值给called_scope,例如如下代码:
<?php class A { public [static](http://www.php.net/static) funcA() { [static](http://www.php.net/static)::funcB(); } } class B { public [static](http://www.php.net/static) funcB() { [echo](http://www.php.net/echo) "B::funcB()"; } } B::funcA();
代码B::funcA()施行的时候,实际施行的是B的父类A中定义的funcA函数,A::funcA()施行时当前的类(scope)指向的是类A,而这个办法是从B类开端调取的,called_scope指向的是类B,static非凡类指向的正是called_scope,也就是当前类(触发办法调取的类),这也是延迟绑定的道理。
以上就是PHP保存类及非凡类的具体内容,更多请关注百分百源码网其它相关文章!