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 }