<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國際加速解決方案。 廣告
                ## 4.1 類型轉換 PHP是弱類型語言,不需要明確的定義變量的類型,變量的類型根據使用時的上下文所決定,也就是變量會根據不同表達式所需要的類型自動轉換,比如求和,PHP會將兩個相加的值轉為long、double再進行加和。每種類型轉為另外一種類型都有固定的規則,當某個操作發現類型不符時就會按照這個規則進行轉換,這個規則正是弱類型實現的基礎。 除了自動類型轉換,PHP還提供了一種強制的轉換方式: * (int)/(integer):轉換為整形 integer * (bool)/(boolean):轉換為布爾類型 boolean * (float)/(double)/(real):轉換為浮點型 float * (string):轉換為字符串 string * (array):轉換為數組 array * (object):轉換為對象 object * (unset):轉換為 NULL 無論是自動類型轉換還是強制類型轉換,不是每種類型都可以轉為任意其他類型。 ### 4.1.1 轉換為NULL 這種轉換比較簡單,任意類型都可以轉為NULL,轉換時直接將新的zval類型設置為`IS_NULL`即可。 ### 4.1.2 轉換為布爾型 當轉換為 boolean 時,根據原值的TRUE、FALSE決定轉換后的結果,以下值被認為是 FALSE: * 布爾值 FALSE 本身 * 整型值 0 * 浮點型值 0.0 * 空字符串,以及字符串 "0" * 空數組 * NULL 所有其它值都被認為是 TRUE,比如資源、對象(這里指默認情況下,因為可以通過擴展改變這個規則)。 判斷一個值是否為true的操作: ```c static zend_always_inline int i_zend_is_true(zval *op) { int result = 0; again: switch (Z_TYPE_P(op)) { case IS_TRUE: result = 1; break; case IS_LONG: //非0即真 if (Z_LVAL_P(op)) { result = 1; } break; case IS_DOUBLE: if (Z_DVAL_P(op)) { result = 1; } break; case IS_STRING: //非空字符串及"0"外都為true if (Z_STRLEN_P(op) > 1 || (Z_STRLEN_P(op) && Z_STRVAL_P(op)[0] != '0')) { result = 1; } break; case IS_ARRAY: //非空數組為true if (zend_hash_num_elements(Z_ARRVAL_P(op))) { result = 1; } break; case IS_OBJECT: //默認情況下始終返回true result = zend_object_is_true(op); break; case IS_RESOURCE: //合法資源就是true if (EXPECTED(Z_RES_HANDLE_P(op))) { result = 1; } case IS_REFERENCE: op = Z_REFVAL_P(op); goto again; break; default: break; } return result; } ``` 在擴展中可以通過`convert_to_boolean()`這個函數直接將原zval轉為bool型,轉換時的判斷邏輯與`i_zend_is_true()`一致。 ### 4.1.3 轉換為整型 其它類型轉為整形的轉換規則: * NULL:轉為0 * 布爾型:false轉為0,true轉為1 * 浮點型:向下取整,比如:`(int)2.8 => 2` * 字符串:就是C語言strtoll()的規則,如果字符串以合法的數值開始,則使用該數值,否則其值為 0(零),合法數值由可選的正負號,后面跟著一個或多個數字(可能有小數點),再跟著可選的指數部分 * 數組:很多操作不支持將一個數組自動整形處理,比如:`array() + 2`,將報error錯誤,但可以強制把數組轉為整形,非空數組轉為1,空數組轉為0,沒有其他值 * 對象:與數組類似,很多操作也不支持將對象自動轉為整形,但有些操作只會拋一個warning警告,還是會把對象轉為1操作的,這個需要看不同操作的處理情況 * 資源:轉為分配給這個資源的唯一編號 具體處理: ```c ZEND_API zend_long ZEND_FASTCALL _zval_get_long_func(zval *op) { try_again: switch (Z_TYPE_P(op)) { case IS_NULL: case IS_FALSE: return 0; case IS_TRUE: return 1; case IS_RESOURCE: //資源將轉為zend_resource->handler return Z_RES_HANDLE_P(op); case IS_LONG: return Z_LVAL_P(op); case IS_DOUBLE: return zend_dval_to_lval(Z_DVAL_P(op)); case IS_STRING: //字符串的轉換調用C語言的strtoll()處理 return ZEND_STRTOL(Z_STRVAL_P(op), NULL, 10); case IS_ARRAY: //根據數組是否為空轉為0,1 return zend_hash_num_elements(Z_ARRVAL_P(op)) ? 1 : 0; case IS_OBJECT: { zval dst; convert_object_to_type(op, &dst, IS_LONG, convert_to_long); if (Z_TYPE(dst) == IS_LONG) { return Z_LVAL(dst); } else { //默認情況就是1 return 1; } } case IS_REFERENCE: op = Z_REFVAL_P(op); goto try_again; EMPTY_SWITCH_DEFAULT_CASE() } return 0; } ``` ### 4.1.4 轉換為浮點型 除字符串類型外,其它類型轉換規則與整形基本一致,就是整形轉換結果加了一位小數,字符串轉為浮點數由`zend_strtod()`完成,這個函數非常長,定義在`zend_strtod.c`中,這里不作說明。 ### 4.1.5 轉換為字符串 一個值可以通過在其前面加上 (string) 或用 strval() 函數來轉變成字符串。在一個需要字符串的表達式中,會自動轉換為 string,比如在使用函數 echo 或 print 時,或在一個變量和一個 string 進行比較時,就會發生這種轉換。 ```c ZEND_API zend_string* ZEND_FASTCALL _zval_get_string_func(zval *op) { try_again: switch (Z_TYPE_P(op)) { case IS_UNDEF: case IS_NULL: case IS_FALSE: //轉為空字符串"" return ZSTR_EMPTY_ALLOC(); case IS_TRUE: //轉為"1" ... return zend_string_init("1", 1, 0); case IS_RESOURCE: { //轉為"Resource id #xxx" ... len = snprintf(buf, sizeof(buf), "Resource id #" ZEND_LONG_FMT, (zend_long)Z_RES_HANDLE_P(op)); return zend_string_init(buf, len, 0); } case IS_LONG: { return zend_long_to_str(Z_LVAL_P(op)); } case IS_DOUBLE: { return zend_strpprintf(0, "%.*G", (int) EG(precision), Z_DVAL_P(op)); } case IS_ARRAY: //轉為"Array",但是報Notice zend_error(E_NOTICE, "Array to string conversion"); return zend_string_init("Array", sizeof("Array")-1, 0); case IS_OBJECT: { //報Error錯誤 zval tmp; ... zend_error(EG(exception) ? E_ERROR : E_RECOVERABLE_ERROR, "Object of class %s could not be converted to string", ZSTR_VAL(Z_OBJCE_P(op)->name)); return ZSTR_EMPTY_ALLOC(); } case IS_REFERENCE: op = Z_REFVAL_P(op); goto try_again; case IS_STRING: return zend_string_copy(Z_STR_P(op)); EMPTY_SWITCH_DEFAULT_CASE() } return NULL; } ``` ### 4.1.6 轉換為數組 如果將一個null、integer、float、string、boolean 和 resource 類型的值轉換為數組,將得到一個僅有一個元素的數組,其下標為 0,該元素即為此標量的值。換句話說,(array)$scalarValue 與 array($scalarValue) 完全一樣。 如果一個 object 類型轉換為 array,則結果為一個數組,數組元素為該對象的全部屬性,包括public、private、protected,其中private的屬性轉換后的key加上了類名作為前綴,protected屬性的key加上了"*"作為前綴,但是這個前綴并不是轉為數組時單獨加上的,而是類編譯生成屬性zend_property_info時就已經加上了,也就是說這其實是成員屬性本身的一個特點,舉例來看: ```c class test { private $a = 123; public $b = "bbb"; protected $c = "ccc"; } $obj = new test; print_r((array)$obj); ====================== Array ( [testa] => 123 [b] => bbb [*c] => ccc ) ``` 轉換時的處理: ```c ZEND_API void ZEND_FASTCALL convert_to_array(zval *op) { try_again: switch (Z_TYPE_P(op)) { case IS_ARRAY: break; case IS_OBJECT: ... if (Z_OBJ_HT_P(op)->get_properties) { //獲取所有屬性數組 HashTable *obj_ht = Z_OBJ_HT_P(op)->get_properties(op); //將數組內容拷貝到新數組 ... } case IS_NULL: ZVAL_NEW_ARR(op); //轉為空數組 zend_hash_init(Z_ARRVAL_P(op), 8, NULL, ZVAL_PTR_DTOR, 0); break; case IS_REFERENCE: zend_unwrap_reference(op); goto try_again; default: convert_scalar_to_array(op); break; } } //其他標量類型轉array static void convert_scalar_to_array(zval *op) { zval entry; ZVAL_COPY_VALUE(&entry, op); //新分配一個數組,將原值插入數組 ZVAL_NEW_ARR(op); zend_hash_init(Z_ARRVAL_P(op), 8, NULL, ZVAL_PTR_DTOR, 0); zend_hash_index_add_new(Z_ARRVAL_P(op), 0, &entry); } ``` ### 4.1.7 轉換為對象 如果其它任何類型的值被轉換成對象,將會創建一個內置類 stdClass 的實例:如果該值為 NULL,則新的實例為空;array轉換成object將以鍵名成為屬性名并具有相對應的值,數值索引的元素也將轉為屬性,但是無法通過"->"訪問,只能遍歷獲取;對于其他值,會以scalar作為屬性名。 ```c ZEND_API void ZEND_FASTCALL convert_to_object(zval *op) { try_again: switch (Z_TYPE_P(op)) { case IS_ARRAY: { HashTable *ht = Z_ARR_P(op); ... //以key為屬性名,將數組元素拷貝到對象屬性 object_and_properties_init(op, zend_standard_class_def, ht); break; } case IS_OBJECT: break; case IS_NULL: object_init(op); break; case IS_REFERENCE: zend_unwrap_reference(op); goto try_again; default: { zval tmp; ZVAL_COPY_VALUE(&tmp, op); object_init(op); //以scalar作為屬性名 zend_hash_str_add_new(Z_OBJPROP_P(op), "scalar", sizeof("scalar")-1, &tmp); break; } } } ``` ### 4.1.8 轉換為資源 無法將其他類型轉為資源。
                  <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>

                              哎呀哎呀视频在线观看