国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

(PHP7內(nèi)核剖析-8) 類

JohnLui / 1933人閱讀

摘要:父類方法為錯(cuò)誤,成員方法不得被重寫。父子類方法靜態(tài)屬性不一致父類方法為非靜態(tài)而子類的是靜態(tài)或相反,錯(cuò)誤。

1.類的結(jié)構(gòu)

類是編譯階段的產(chǎn)物,而對象是運(yùn)行時(shí)產(chǎn)生的,它們歸屬于不同階段。編譯完成后我們定義的每個(gè)類都會生成一個(gè)zend_class_entry,它保存著類的全部信息,在執(zhí)行階段所有類相關(guān)的操作都是用的這個(gè)結(jié)構(gòu),
struct _zend_class_entry {
    char type;          //類的類型:內(nèi)部類ZEND_INTERNAL_CLASS(1)、用戶自定義類ZEND_USER_CLASS(2)
    zend_string *name;  //類名,PHP類不區(qū)分大小寫,統(tǒng)一為小寫
    struct _zend_class_entry *parent; //父類
    uint32_t ce_flags;  //類掩碼,如普通類、抽象類、接口,

    int default_properties_count;        //普通屬性數(shù),包括public、private
    int default_static_members_count;    //靜態(tài)屬性數(shù),static
    HashTable properties_info; //成員屬性基本信息哈希表,key為成員名,value為zend_property_info
    zval *default_properties_table;      //普通屬性值數(shù)組
    zval *default_static_members_table;  //靜態(tài)屬性值數(shù)組
    HashTable function_table;  //成員方法哈希表
    HashTable constants_table; //常量哈希表,通過constant定義的

    //以下是構(gòu)造函授、析構(gòu)函數(shù)、魔術(shù)方法的指針
    union _zend_function *constructor;
    union _zend_function *destructor;
    union _zend_function *clone;
    union _zend_function *__get;
    union _zend_function *__set;
    union _zend_function *__unset;
    union _zend_function *__isset;
    union _zend_function *__call;
    union _zend_function *__callstatic;
    union _zend_function *__tostring;
    union _zend_function *__debugInfo;
    union _zend_function *serialize_func;
    union _zend_function *unserialize_func;
}
類的編譯:首先為類分配一個(gè)zend_class_entry結(jié)構(gòu),如果沒有繼承類則生成一條類聲明的opcode(ZEND_DECLARE_CLASS),有繼承類則生成兩條opcode(ZEND_FETCH_CLASS、ZEND_DECLARE_INHERITED_CLASS),然后再繼續(xù)編譯常量、成員屬性、成員方法注冊到zend_class_entry中,最后編譯完成后調(diào)用zend_do_early_binding()進(jìn)行 父子類關(guān)聯(lián) 以及 注冊到EG(class_table)符號表。


2.類常量

PHP中可以把在類中始終保持不變的值定義為常量,在定義和使用常量的時(shí)候不需要使用 $ 符號,常量的值必須是一個(gè)定值,它們通過zend_class_entry.constants_table進(jìn)行存儲,這是一個(gè)哈希結(jié)構(gòu)
常量的讀取:

class my_class {
    const A1 = "hi";
}
echo my_class::A1;

編譯到echo my_class::A1這行時(shí)首先會嘗試檢索下是否已經(jīng)編譯了my_class,如果能在CG(class_table)中找到,則進(jìn)一步從類的contants_table查找對應(yīng)的常量,找到的話則會復(fù)制其value替換常量,簡單的講就是類似C語言中的宏,編譯時(shí)替換為實(shí)際的值了,而不是在運(yùn)行時(shí)再去檢索。

echo my_class::A1;

class my_class {
    const A1 = "hi";
}

在運(yùn)行時(shí)再去檢索。替換成為實(shí)際的值


3.成員屬性

屬性中的變量可以初始化,但是初始化的值必須是常數(shù),這里的常數(shù)是指PHP腳本在編譯階段時(shí)就可以得到其值,而不依賴于運(yùn)行時(shí)的信息才能求值,比如public $time = time();這樣定義一個(gè)屬性就會觸發(fā)語法錯(cuò)誤。

成員屬性又分為兩類:普通屬性、靜態(tài)屬性,與常量的存儲方式不同,成員屬性的初始化值并不是直接用以"屬性名"作為索引的哈希表存儲的,而是通過數(shù)組保存的

實(shí)際只是成員屬性的VALUE通過數(shù)組存儲的,訪問時(shí)仍然是根據(jù)以"屬性名"為索引的散列表查找具體VALUE的,而這個(gè)散列表是zend_class_entry.properties_info
typedef struct _zend_property_info {
    uint32_t offset; //普通成員變量的內(nèi)存偏移值,靜態(tài)成員變量的數(shù)組索引
    uint32_t flags;  //屬性掩碼,如public、private、protected及是否為靜態(tài)屬性
    zend_string *name; //屬性名:并不是原始屬性名,private會在原始屬性名前加上類名,protected則會加上*作為前綴
    zend_class_entry *ce; //所屬類
} zend_property_info;

成員屬性在類編譯階段就已經(jīng)分配了zval,靜態(tài)與普通的區(qū)別在于普通屬性在創(chuàng)建一個(gè)對象時(shí)還會重新分配zval,對象對普通屬性的操作都是在其自己的空間進(jìn)行的,各對象隔離,而靜態(tài)屬性的操作始終是在類的空間內(nèi),各對象共享。


4.成員方法

每個(gè)類可以定義若干屬于本類的函數(shù)(稱之為成員方法),這種函數(shù)與普通的function相同,只是以類的維度進(jìn)行管理,不是全局性的,所以成員方法保存在類中而不是EG(function_table)

成員方法也有靜態(tài)、非靜態(tài)之分,靜態(tài)方法中不能使用$this,因?yàn)槠洳僮鞯淖饔糜蛉慷际穷惖亩皇菍ο蟮模庆o態(tài)方法中可以通過$this訪問屬于本對象的成員屬性


5.對象的數(shù)據(jù)結(jié)構(gòu)

typedef struct _zend_object     zend_object;

struct _zend_object {
    zend_refcounted_h gc; //引用計(jì)數(shù)
    uint32_t          handle; //對象編號
    zend_class_entry *ce; //所屬類
    const zend_object_handlers *handlers; //對象操作處理函數(shù)
    HashTable        *properties; //普通成員屬性哈希表,用于動態(tài)屬性
    zval              properties_table[1]; //普通屬性值數(shù)組
};
對象的創(chuàng)建:首先是根據(jù)類名在EG(class_table)中查找對應(yīng)zend_class_entry、然后是創(chuàng)建并初始化一個(gè)對象、最后是初始化調(diào)用構(gòu)造函數(shù)的zend_execute_data
實(shí)例化一個(gè)對象:
step1: 首先根據(jù)類名去EG(class_table)中找到具體的類,即zend_class_entry
step2: 分配zend_object結(jié)構(gòu),一起分配的還有普通非靜態(tài)屬性值的內(nèi)存
step3: 初始化對象的非靜態(tài)屬性,將屬性值從zend_class_entry淺復(fù)制(寫時(shí)分離)到對象中
step4: 查找當(dāng)前類是否定義了構(gòu)造函數(shù),如果沒有定義則跳過執(zhí)行構(gòu)造函數(shù)的opcode,否則為調(diào)用構(gòu)造函數(shù)的執(zhí)行進(jìn)行一些準(zhǔn)備工作(分配zend_execute_data)
step5: 實(shí)例化完成,返回新實(shí)例化的對象(如果返回的對象沒有變量使用則直接釋放掉了)


6.繼承

(a).繼承屬性

屬性從父類復(fù)制到子類 。子類會將父類的公共、受保護(hù)的屬性值數(shù)組全部合并到子類中,然后將全部屬性的zend_property_info哈希表也合并到子類中

(b).繼承常量

常量的合并策略比較簡單,如果父類與子類沖突時(shí)用子類的,不沖突時(shí)則將父類的常量合并到子類。

(c).繼承方法

與屬性一樣,子類可以繼承父類的公有、受保護(hù)的方法,方法的繼承比較復(fù)雜,因?yàn)闀性L問控制、抽象類、接口、Trait等多種限制條件。實(shí)現(xiàn)上與前面幾種相同,即父類的function_table合并到子類的function_table中。
如果父類是用戶自定義的類,且繼承的方法沒有靜態(tài)變量則不會硬拷貝,而是增加zend_function的引用計(jì)數(shù)(zend_op_array.refcount)。
子類重寫了父類的方法的檢查規(guī)則
(1)抽象子類的抽象方法與抽象父類的抽象方法沖突: 無法重寫,F(xiàn)atal錯(cuò)誤。
(2)父類方法為final: Fatal錯(cuò)誤,final成員方法不得被重寫。
(3)父子類方法靜態(tài)屬性不一致: 父類方法為非靜態(tài)而子類的是靜態(tài)(或相反),F(xiàn)atal錯(cuò)誤。
(4)抽象子類的抽象方法覆蓋父類非抽象方法: Fatal錯(cuò)誤。
(5)子類方法限制父類方法訪問權(quán)限: Fatal錯(cuò)誤,不允許派生類限制父類方法的訪問權(quán)限,如父類方法為public,
而子類試圖重寫為protected/private。
6)剩余檢查情況: 除了上面5中情形下無法重寫方法,剩下還有一步對函數(shù)參數(shù)的檢查


7. 動態(tài)屬性

class my_class {
    public $id = 123;
    public function test($name, $value){
        $this->$name = $value;
    }
}
非靜態(tài)成員屬性值在實(shí)例化時(shí)保存到了對象中,屬性的操作按照編譯時(shí)按順序編好的序號操作,各對象對其非靜態(tài)成員屬性的操作互不干擾,而動態(tài)屬性是在運(yùn)行時(shí)創(chuàng)建的,動態(tài)創(chuàng)建的屬性保存在zend_object->properties哈希表中
屬性查找:首先按照普通屬性在zend_class_entry.properties_info找,沒有找到再去zend_object->properties繼續(xù)查找
首次創(chuàng)建動態(tài)屬性將通過rebuild_object_properties()初始化zend_object->properties哈希表,后面再創(chuàng)建動態(tài)屬性直接插入此哈希表,rebuild_object_properties()過程并不僅僅是創(chuàng)建一個(gè)HashTable,還會將普通成員屬性值插入到這個(gè)數(shù)組中,與動態(tài)屬性不同,這里的插入并不是增加原zend_value的refcount,而是創(chuàng)建了一個(gè)IS_INDIRECT類型的zval,指向原屬性值zval

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/28585.html

相關(guān)文章

  • (PHP7內(nèi)核剖析-7) Zend引擎執(zhí)行過程

    1.EG(executor_globals/zend_executor_globals) PHP整個(gè)生命周期中最主要的一個(gè)結(jié)構(gòu),是一個(gè)全局變量,在main執(zhí)行前分配(非ZTS下),直到PHP退出,它記錄著當(dāng)前請求全部的信息 showImg(https://segmentfault.com/img/bV8fW0?w=960&h=777); 2.EX(execute_data/zend_execut...

    elisa.yang 評論0 收藏0
  • (PHP7內(nèi)核剖析-6) 函數(shù)

    摘要:引擎中定義了很多內(nèi)部函數(shù)供用戶在中使用,比如等等,除了引擎中定義的內(nèi)部函數(shù),擴(kuò)展中也提供了大量內(nèi)部函數(shù),我們也可以靈活的通過擴(kuò)展自行定制。頭部是一個(gè)與完全相同的結(jié)構(gòu)函數(shù)指針,展開 1.函數(shù)的存儲結(jié)構(gòu) typedef union _zend_function zend_function; union _zend_function { zend_uchar typ...

    crelaber 評論0 收藏0
  • (PHP7內(nèi)核剖析-9) 內(nèi)存管理

    摘要:但在多線程模式下會有多個(gè),也就是說每個(gè)線程都有一個(gè)獨(dú)立的內(nèi)存池內(nèi)存分配分配超過內(nèi)存的申請,與通用的內(nèi)存申請沒有太大差別,只是將申請的內(nèi)存塊通過單鏈表進(jìn)行了管理。的分配實(shí)際就是分配多個(gè),的分配也是內(nèi)存分配的基礎(chǔ),它是向系統(tǒng)申請內(nèi)存的唯一粒度。 1.Zend內(nèi)存池 內(nèi)存池是內(nèi)核中最底層的內(nèi)存操作,定義了三種粒度的內(nèi)存塊:chunk、page、slot,每個(gè)chunk的大小為2M,page大...

    ygyooo 評論0 收藏0
  • (PHP7內(nèi)核剖析-5) PHP代碼的編譯

    摘要:代碼的編譯的解析過程任務(wù)就是將代碼轉(zhuǎn)化為數(shù)組,代碼里的所有信息都保存在數(shù)組中,然后將數(shù)組交給引擎執(zhí)行,就是內(nèi)核具體執(zhí)行的命令,比如賦值加減操作函數(shù)調(diào)用等,每一條都對應(yīng)一個(gè)處理,這些是提前定義好的函數(shù)。 1.PHP代碼的編譯 PHP的解析過程任務(wù)就是將PHP代碼轉(zhuǎn)化為opcode數(shù)組,代碼里的所有信息都保存在opcode數(shù)組中,然后將opcode數(shù)組交給zend引擎執(zhí)行,opcode就是...

    DevTTL 評論0 收藏0
  • (PHP7內(nèi)核剖析-3) 變量

    摘要:插入一個(gè)元素時(shí)先將元素按先后順序插入數(shù)組,位置是,再根據(jù)的哈希值映射到散列表中的某個(gè)位置,將存入這個(gè)位置查找時(shí)先在散列表中映射到,得到在數(shù)組的位置,再從數(shù)組中取出元素。目前只有兩種類型會使用這種機(jī)制。 1.變量結(jié)構(gòu) typedef struct _zval_struct zval; typedef union _zend_value { zend_long ...

    RiverLi 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<