PHP保留类及特殊类-php教程

资源魔 30 0

正在面向工具言语中,城市内置一些言语内置提供的根本性能类,比方JavaScript中的Array,Number等类,PHP中也有不少这类类,比方Directory,stdClass,Exception等类,同时一些规范扩大比方PDO等扩大中也会界说一些类,PHP中类是没有容许反复界说的,以是正在编写代码时没有容许界说曾经存正在的类。

同时PHP中有一些非凡的类:selfstatic以及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保留类 特殊类

抱歉,评论功能暂时关闭!