<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                ### 3.4.4 動態屬性 前面介紹的成員屬性都是在類中明確的定義過的,這些屬性在實例化時會被拷貝到對象空間中去,PHP中除了顯示的在類中定義成員屬性外,還可以動態的創建非靜態成員屬性,這種屬性不需要在類中明確定義,可以直接通過:`$obj->property_name=xxx`、`$this->property_name = xxx`為對象設置一個屬性,這種屬性稱之為動態屬性,舉個例子: ```php class my_class { public $id = 123; public function test($name, $value){ $this->$name = $value; } } $obj = new my_class; $obj->test("prop_1", array(1,2,3)); //或者直接: //$obj->prop_1 = array(1,2,3); print_r($obj); ``` 在`test()`方法中直接操作了沒有定義的成員屬性,上面的例子將輸出: ``` my_class Object ( [id] => 123 [prop_1] => Array ( [0] => 1 [1] => 2 [2] => 3 ) ) ``` 前面類、對象兩節曾介紹,非靜態成員屬性值在實例化時保存到了對象中,屬性的操作按照編譯時按順序編好的序號操作,各對象對其非靜態成員屬性的操作互不干擾,那么動態屬性是在運行時創建的,它是如何存儲的呢? 與普通非靜態屬性不同,動態創建的屬性保存在`zend_object->properties`哈希表中,查找的時候首先按照普通屬性在`zend_class_entry.properties_info`找,沒有找到再去`zend_object->properties`繼續查找。動態屬性的創建過程(即:修改屬性的操作): ```c //zend_object->handlers->write_property: ZEND_API void zend_std_write_property(zval *object, zval *member, zval *value, void **cache_slot) { ... zobj = Z_OBJ_P(object); //先在zend_class_entry.properties_info查找此屬性 property_offset = zend_get_property_offset(zobj->ce, Z_STR_P(member), (zobj->ce->__set != NULL), cache_slot); if (EXPECTED(property_offset != ZEND_WRONG_PROPERTY_OFFSET)) { if (EXPECTED(property_offset != ZEND_DYNAMIC_PROPERTY_OFFSET)) { //普通屬性,直接根據根據屬性ofsset取出屬性值 } else if (EXPECTED(zobj->properties != NULL)) { //有動態屬性 ... //從動態屬性中查找 if ((variable_ptr = zend_hash_find(zobj->properties, Z_STR_P(member))) != NULL) { found: zend_assign_to_variable(variable_ptr, value, IS_CV); goto exit; } } } if (zobj->ce->__set) { //定義了__set()魔法函數 }else if (EXPECTED(property_offset != ZEND_WRONG_PROPERTY_OFFSET)){ if (EXPECTED(property_offset != ZEND_DYNAMIC_PROPERTY_OFFSET)) { ... } else { //首次創建動態屬性將在這里完成 if (!zobj->properties) { rebuild_object_properties(zobj); } //將動態屬性插入properties zend_hash_add_new(zobj->properties, Z_STR_P(member), value); } } } ``` 上面就是成員屬性的修改過程,普通屬性根據其offset再從對象中取出屬性值進行修改,而首次創建動態屬性將通過`rebuild_object_properties()`初始化`zend_object->properties`哈希表,后面再創建動態屬性直接插入此哈希表,`rebuild_object_properties()`過程并不僅僅是創建一個HashTable,還會將普通成員屬性值插入到這個數組中,與動態屬性不同,這里的插入并不是增加原zend_value的refcount,而是創建了一個IS_INDIRECT類型的zval,指向原屬性值zval,具體結構如下圖。 ![](https://box.kancloud.cn/19f9986d6b50fbff93a07693a1e76829_584x258.png) > __Note:__ 這里不清楚將原有屬性也插入properties的用意,已知用到的一個地方是在GC垃圾回收獲取對象所有屬性時(zend_std_get_gc()),如果有動態屬性則直接返回properties給GC遍歷,假如不把普通的顯式定義的屬性"拷貝"進來則需要返回、遍歷兩個數組。 > > 另外一個地方需要注意,把原屬性"轉移"到properties并不僅僅是創建動態屬性時觸發的,調用對象的get_properties(即:zend_std_get_properties())也會這么處理,比如將一個object轉為array時就會觸發這個動作: $arr = (array)$object,通過foreach遍歷一個對象時也會調用get_properties獲取屬性數組進行遍歷。 成員屬性的讀取通過`zend_object->handlers->read_property`(默認zend_std_read_property())函數完成,動態屬性的查找過程實際與`write_property`中相同: ```c zval *zend_std_read_property(zval *object, zval *member, int type, void **cache_slot, zval *rv) { ... zobj = Z_OBJ_P(object); //首先查找zend_class_entry.properties_info,普通屬性可以在這里找到 property_offset = zend_get_property_offset(zobj->ce, Z_STR_P(member), (type == BP_VAR_IS) || (zobj->ce->__get != NULL), cache_slot); if (EXPECTED(property_offset != ZEND_WRONG_PROPERTY_OFFSET)) { if (EXPECTED(property_offset != ZEND_DYNAMIC_PROPERTY_OFFSET)) { //普通屬性 retval = OBJ_PROP(zobj, property_offset); } else if (EXPECTED(zobj->properties != NULL)) { //動態屬性從zend_object->properties中查找 retval = zend_hash_find(zobj->properties, Z_STR_P(member)); if (EXPECTED(retval)) goto exit; } } ... } ```
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看