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

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                ### 3.4.5 魔術方法 PHP在類的成員方法中預留了一些特殊的方法,它們會在一些特殊的時機被調用(比如創建對象之初、訪問成員屬性時...),這類方法稱為:魔術方法,包括:__construct()、__destruct()、__call()、__callStatic()、__get()、__set()、__isset()、__unset()、__sleep()、__wakeup()、__toString()、__invoke()、 __set_state()、 __clone() 和 __debugInfo(),關于這些方法的用法這里不作說明,不清楚的可以翻下官方文檔。 魔術方法實際是PHP提供的一些特殊操作時的鉤子函數,與普通成員方法無異,它們只是與一些操作的口頭約定,并沒有什么字段標識它們,比如我們定義了一個函數:my_function(),我們希望在這個函數處理對象時首先調用其成員方法my_magic(),那么my_magic()也可以認為是一個魔術方法。 魔術方法與普通成員方法一樣保存在`zend_class_entry.function_table`中,另外針對一些內核常用到的成員方法在zend_class_entry中還有一些單獨的指針指向具體的成員方法: ```c struct _zend_class_entry { ... 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; ... } ``` 在編譯成員方法時如果發現與這些魔術方法名稱一致,則除了插入`zend_class_entry.function_table`哈希表以外,還會設置zend_class_entry中對應的指針。 ![](https://box.kancloud.cn/4191cc336f9e212ad35932cb608e925e_552x281.png) 具體在編譯成員方法時設置:zend_begin_method_decl()。 ```c void zend_begin_method_decl(zend_op_array *op_array, zend_string *name, zend_bool has_body) { ... //插入類的function_table中 if (zend_hash_add_ptr(&ce->function_table, lcname, op_array) == NULL) { zend_error_noreturn(..); } if (!in_trait && zend_string_equals_ci(lcname, ce->name)) { if (!ce->constructor) { ce->constructor = (zend_function *) op_array; } } else if (zend_string_equals_literal(lcname, ZEND_CONSTRUCTOR_FUNC_NAME)) { ce->constructor = (zend_function *) op_array; } else if (zend_string_equals_literal(lcname, ZEND_DESTRUCTOR_FUNC_NAME)) { ce->destructor = (zend_function *) op_array; } else if (zend_string_equals_literal(lcname, ZEND_CLONE_FUNC_NAME)) { ce->clone = (zend_function *) op_array; } else if (zend_string_equals_literal(lcname, ZEND_CALL_FUNC_NAME)) { ce->__call = (zend_function *) op_array; } else if (zend_string_equals_literal(lcname, ZEND_CALLSTATIC_FUNC_NAME)) { ce->__callstatic = (zend_function *) op_array; } else if (...){ ... } ... } ``` 除了這幾個其它魔術方法都沒有單獨的指針指向,比如:__sleep()、__wakeup(),這兩個主要是serialize()、unserialize()序列化、反序列化時調用的,它們是在這倆函數中寫死的,我們簡單看下serialize()的實現,這個函數是通過擴展提供的: ```c //file: ext/standard/var.c PHP_FUNCTION(serialize) { zval *struc; php_serialize_data_t var_hash; smart_str buf = {0}; if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &struc) == FAILURE) { return; } php_var_serialize(&buf, struc, &var_hash); ... } ``` 最終由`php_var_serialize_intern()`處理,這個函數會根據不同的類型選擇不同的處理方式: ```c static void php_var_serialize_intern(smart_str *buf, zval *struc, php_serialize_data_t var_hash) { ... switch (Z_TYPE_P(struc)) { case IS_FALSE: ... case IS_TRUE: ... case IS_NULL: ... case IS_LONG: ... } } ``` 其中類型是對象時將先檢查`zend_class_function.function_table`中是否定義了`__sleep()`,如果有的話則調用: ```c //case IS_OBJEST: ... if (ce != PHP_IC_ENTRY && zend_hash_str_exists(&ce->function_table, "__sleep", sizeof("__sleep")-1)) { ZVAL_STRINGL(&fname, "__sleep", sizeof("__sleep") - 1); //調用用戶自定義的__sleep()方法 res = call_user_function_ex(CG(function_table), struc, &fname, &retval, 0, 0, 1, NULL); if (res == SUCCESS) { if (Z_TYPE(retval) != IS_UNDEF) { if (HASH_OF(&retval)) { php_var_serialize_class(buf, struc, &retval, var_hash); } else { smart_str_appendl(buf,"N;", 2); } zval_ptr_dtor(&retval); } return; } } //后面會走到IS_ARRAY分支繼續序列化處理 ... ``` 其它魔術方法與__sleep()類似,都是在一些特殊操作中固定調用的。
                  <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>

                              哎呀哎呀视频在线观看