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 }

 

posted @ 2018-06-08 15:59  S3c0ldW4ng  阅读(660)  评论(0编辑  收藏  举报