PHP保留類及特殊類是什么

這篇文章主要介紹PHP保留類及特殊類是什么,文中介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要看完!

創(chuàng)新互聯(lián)是一家專業(yè)提供晉城企業(yè)網站建設,專注與網站設計、做網站、成都h5網站建設、小程序制作等業(yè)務。10年已為晉城眾多企業(yè)、政府機構等服務。創(chuàng)新互聯(lián)專業(yè)網站建設公司優(yōu)惠進行中。

在面向對象語言中,都會內置一些語言內置提供的基本功能類,比如JavaScript中的Array,Number等類,PHP中也有很多這種類,比如Directory,stdClass,Exception等類,同時一些標準擴展比如PDO等擴展中也會定義一些類,PHP中類是不允許重復定義的,所以在編寫代碼時不允許定義已經存在的類。

同時PHP中有一些特殊的類:selfstaticparent,相信讀者對這self和parent都比較熟悉了,而static特殊類是PHP5.3才引入的。

PHP中的static關鍵字非常多義:

● 在函數(shù)體內的修飾變量的static關鍵字用于定義靜態(tài)局部變量。

● 用于修飾類成員函數(shù)和成員變量時用于聲明靜態(tài)成員。

● (PHP5.3)在作用域解析符(::)前又表示靜態(tài)延遲綁定的特殊類。

這個關鍵字修飾的意義都表示"靜態(tài)",在PHP手冊中提到self,parent和static這幾個關鍵字,但實際上除了static是關鍵字以外,其他兩個均不是關鍵字,在手冊的關鍵字列表中也沒有這兩個關鍵字,要驗證這一點很簡單:

<?php
[var_dump](http://www.php.net/var_dump)(self); // -> string(4) "self"

上面的代碼并沒有報錯,如果你把error_reporting(E_ALL)打開,就能看到實際是什么情況了:運行這段代碼會出現(xiàn)“ 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

不同語言中的關鍵字的意義會有些區(qū)別,Wikipedia上的解釋是: 具有特殊含義的標示符或者單詞,從這個意義上說$this也算是一個關鍵字,但在PHP的關鍵字列表中并沒有。 PHP的關鍵字和C/C++一樣屬于保留字(關鍵字),關鍵字用于表示特定的語法形式,例如函數(shù)定義,流程控制等結構。 這些關鍵字有他們的特定的使用場景,而上面提到的self和parent并沒有這樣的限制。

self,parent,static類

前面已經說過self的特殊性。self是一個特殊類,它指向當前類,但只有在類定義內部才有效,但也并不一定指向類本身這個特殊類,比如前面的代碼,如果放在類方法體內運行,echo self; 還是會輸出常量self的值,而不是當前類,它不止要求在類的定義內部,還要求在類的上下文環(huán)境,比如 new self()的時候,這時self就指向當前類,或者self::$static_varible,self::CONSTANT類似的作用域解析符號(::),這時的self才會作為指向本身的類而存在。

同理parent也和self類似。下面先看看在在類的環(huán)境下的編譯吧$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); }
;

在需要獲取類名時會執(zhí)行zend_do_fetch_class()函數(shù):

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()函數(shù)獲取到的。

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引擎編譯類相關操作的代碼,下面就到執(zhí)行階段了,self,parent等類的指向會在執(zhí)行時進行獲取,找到執(zhí)行opcode為ZEND_FETCH_CLASS的執(zhí)行函數(shù):

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;
}

從這個函數(shù)就能看出端倪了,當需要獲取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會在執(zhí)行過程中將當前執(zhí)行的類賦值給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()執(zhí)行的時候,實際執(zhí)行的是B的父類A中定義的funcA函數(shù),A::funcA()執(zhí)行時當前的類(scope)指向的是類A,而這個方法是從B類開始調用的,called_scope指向的是類B,static特殊類指向的正是called_scope,也就是當前類(觸發(fā)方法調用的類),這也是延遲綁定的原理。

以上是PHP保留類及特殊類是什么的所有內容,感謝各位的閱讀!希望分享的內容對大家有幫助,更多相關知識,歡迎關注創(chuàng)新互聯(lián)行業(yè)資訊頻道!

網站標題:PHP保留類及特殊類是什么
網站網址:http://muchs.cn/article20/ihjgjo.html

成都網站建設公司_創(chuàng)新互聯(lián),為您提供網頁設計公司網站設計公司、網站維護、定制開發(fā)用戶體驗

廣告

聲明:本網站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)

小程序開發(fā)