类别:PHP教程 / 日期:2019-12-01 / 浏览:226 / 评论:0
在面向对象言语中,都邑内置一些言语内置供应的基本功能类,比方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保存类及特别类的细致内容,更多请关注ki4网别的相干文章!