php内置函数分析range()
1 PHP_FUNCTION(range) 2 { 3 zval *zlow, *zhigh, *zstep = NULL, tmp; 4 int err = 0, is_step_double = 0; 5 double step = 1.0; // 步长默认为1 6 7 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz|z", &zlow, &zhigh, &zstep) == FAILURE) { 8 RETURN_FALSE; 9 } 10 11 // 步长 12 if (zstep) { 13 if (Z_TYPE_P(zstep) == IS_DOUBLE || 14 (Z_TYPE_P(zstep) == IS_STRING && is_numeric_string(Z_STRVAL_P(zstep), Z_STRLEN_P(zstep), NULL, NULL, 0) == IS_DOUBLE) 15 ) { 16 is_step_double = 1; 17 } 18 19 step = zval_get_double(zstep); 20 21 // 步长可以为负数。取绝对值 22 /* We only want positive step values. */ 23 if (step < 0.0) { 24 step *= -1; 25 } 26 } 27 28 /* If the range is given as strings, generate an array of characters. */ 29 /* start、end是字符串 */ 30 if (Z_TYPE_P(zlow) == IS_STRING && Z_TYPE_P(zhigh) == IS_STRING && Z_STRLEN_P(zlow) >= 1 && Z_STRLEN_P(zhigh) >= 1) { 31 int type1, type2; 32 unsigned char low, high; 33 zend_long lstep = (zend_long) step; 34 35 type1 = is_numeric_string(Z_STRVAL_P(zlow), Z_STRLEN_P(zlow), NULL, NULL, 0); 36 type2 = is_numeric_string(Z_STRVAL_P(zhigh), Z_STRLEN_P(zhigh), NULL, NULL, 0); 37 38 /* 填充数字 */ 39 if (type1 == IS_DOUBLE || type2 == IS_DOUBLE || is_step_double) { 40 goto double_str; 41 } else if (type1 == IS_LONG || type2 == IS_LONG) { 42 goto long_str; 43 } 44 45 /* 填充字符,只取字符串start和字符串end的第一个字符 */ 46 low = (unsigned char)Z_STRVAL_P(zlow)[0]; 47 high = (unsigned char)Z_STRVAL_P(zhigh)[0]; 48 49 if (low > high) { /* Negative Steps */ 50 if (lstep <= 0) { 51 err = 1; 52 goto err; 53 } 54 /* Initialize the return_value as an array. */ 55 array_init_size(return_value, (uint32_t)(((low - high) / lstep) + 1)); 56 zend_hash_real_init(Z_ARRVAL_P(return_value), 1); 57 ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) { 58 for (; low >= high; low -= (unsigned int)lstep) { 59 if (CG(one_char_string)[low]) { 60 ZVAL_INTERNED_STR(&tmp, CG(one_char_string)[low]); 61 } else { 62 ZVAL_STRINGL(&tmp, (char*)&low, 1); 63 } 64 ZEND_HASH_FILL_ADD(&tmp); 65 if (((signed int)low - lstep) < 0) { 66 break; 67 } 68 } 69 } ZEND_HASH_FILL_END(); 70 } else if (high > low) { /* Positive Steps */ 71 if (lstep <= 0) { 72 err = 1; 73 goto err; 74 } 75 // 初始化返回的数组 76 array_init_size(return_value, (uint32_t)(((high - low) / lstep) + 1)); 77 zend_hash_real_init(Z_ARRVAL_P(return_value), 1); 78 ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) { 79 // 将字符插入返回的数组 80 for (; low <= high; low += (unsigned int)lstep) { 81 if (CG(one_char_string)[low]) { 82 ZVAL_INTERNED_STR(&tmp, CG(one_char_string)[low]); 83 } else { 84 ZVAL_STRINGL(&tmp, (char*)&low, 1); 85 } 86 ZEND_HASH_FILL_ADD(&tmp); 87 if (((signed int)low + lstep) > 255) { 88 break; 89 } 90 } 91 } ZEND_HASH_FILL_END(); 92 } else { 93 array_init(return_value); 94 if (CG(one_char_string)[low]) { 95 ZVAL_INTERNED_STR(&tmp, CG(one_char_string)[low]); 96 } else { 97 ZVAL_STRINGL(&tmp, (char*)&low, 1); 98 } 99 zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp); 100 } 101 } else if (Z_TYPE_P(zlow) == IS_DOUBLE || Z_TYPE_P(zhigh) == IS_DOUBLE || is_step_double) { // start、end是浮点数 102 double low, high, value; 103 zend_long i; 104 double_str: 105 low = zval_get_double(zlow); 106 high = zval_get_double(zhigh); 107 i = 0; 108 109 // 浮点数范围检查 110 if (zend_isinf(high) || zend_isinf(low)) { 111 php_error_docref(NULL, E_WARNING, "Invalid range supplied: start=%0.0f end=%0.0f", low, high); 112 RETURN_FALSE; 113 } 114 115 Z_TYPE_INFO(tmp) = IS_DOUBLE; 116 if (low > high) { /* Negative steps 第一个参数比第二大*/ 117 if (low - high < step || step <= 0) { // 范围差小于步长或步长取绝对值之后仍小于0。则报WARNING错误。 118 err = 1; 119 goto err; 120 } 121 122 // 检查并初始化返回的数组 123 RANGE_CHECK_INIT_ARRAY(low, high); 124 // 向返回的数组中填充值,降序 125 ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) { 126 for (value = low; value >= (high - DOUBLE_DRIFT_FIX); value = low - (++i * step)) { 127 Z_DVAL(tmp) = value; 128 ZEND_HASH_FILL_ADD(&tmp); 129 } 130 } ZEND_HASH_FILL_END(); 131 } else if (high > low) { /* Positive steps 第一个参数比第二个小*/ 132 if (high - low < step || step <= 0) { 133 err = 1; 134 goto err; 135 } 136 137 // 检查并初始化返回的数组 138 RANGE_CHECK_INIT_ARRAY(high, low); 139 // 向返回的数组中填充值,升序 140 ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) { 141 for (value = low; value <= (high + DOUBLE_DRIFT_FIX); value = low + (++i * step)) { 142 Z_DVAL(tmp) = value; 143 ZEND_HASH_FILL_ADD(&tmp); 144 } 145 } ZEND_HASH_FILL_END(); 146 } else { // low == high。则返回的数组只用一个元素:array(0=>low) 147 array_init(return_value); 148 Z_DVAL(tmp) = low; 149 zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp); 150 } 151 } else { // start、end是整数 152 double low, high; 153 zend_long lstep; 154 long_str: 155 low = zval_get_double(zlow); 156 high = zval_get_double(zhigh); 157 lstep = (zend_long) step; 158 159 Z_TYPE_INFO(tmp) = IS_LONG; 160 if (low > high) { /* Negative steps */ 161 if (low - high < lstep || lstep <= 0) { 162 err = 1; 163 goto err; 164 } 165 166 RANGE_CHECK_INIT_ARRAY(low, high); 167 ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) { 168 for (; low >= high; low -= lstep) { 169 Z_LVAL(tmp) = (zend_long)low; 170 ZEND_HASH_FILL_ADD(&tmp); 171 } 172 } ZEND_HASH_FILL_END(); 173 } else if (high > low) { /* Positive steps */ 174 if (high - low < lstep || lstep <= 0) { 175 err = 1; 176 goto err; 177 } 178 179 RANGE_CHECK_INIT_ARRAY(high, low); 180 ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) { 181 for (; low <= high; low += lstep) { 182 Z_LVAL(tmp) = (zend_long)low; 183 ZEND_HASH_FILL_ADD(&tmp); 184 } 185 } ZEND_HASH_FILL_END(); 186 } else { 187 array_init(return_value); 188 Z_LVAL(tmp) = (zend_long)low; 189 zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp); 190 } 191 } 192 err: 193 if (err) { 194 php_error_docref(NULL, E_WARNING, "step exceeds the specified range"); 195 RETURN_FALSE; 196 } 197 }