正在面向工具言语中,城市内置一些言语内置提供的根本性能类,比方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保存类及非凡类的具体内容,更多请存眷资源魔其它相干文章!
标签: php开发教程 php开发资料 php开发自学 PHP保留类 特殊类
抱歉,评论功能暂时关闭!