1 
2 /*
3   +------------------------------------------------------------------------+
4   | Zephir Language                                                        |
5   +------------------------------------------------------------------------+
6   | Copyright (c) 2011-2017 Phalcon Team (http://www.zephir-lang.com)       |
7   +------------------------------------------------------------------------+
8   | This source file is subject to the New BSD License that is bundled     |
9   | with this package in the file docs/LICENSE.txt.                        |
10   |                                                                        |
11   | If you did not receive a copy of the license and are unable to         |
12   | obtain it through the world-wide-web, please send an email             |
13   | to license@zephir-lang.com so we can send you a copy immediately.      |
14   +------------------------------------------------------------------------+
15   | Authors: Andres Gutierrez <andres@zephir-lang.com>                     |
16   |          Eduar Carvajal <eduar@zephir-lang.com>                        |
17   |          Vladimir Kolesnikov <vladimir@extrememember.com>              |
18   +------------------------------------------------------------------------+
19 */
20 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #include <php.h>
26 #include <ext/standard/php_string.h>
27 #include <ext/standard/php_math.h>
28 
29 #include "php_ext.h"
30 #include "kernel/main.h"
31 #include "kernel/memory.h"
32 #include "kernel/string.h"
33 #include "kernel/operators.h"
34 
35 #include "Zend/zend_operators.h"
36 
37 /**
38  * Appends the content of the right operator to the left operator
39  */
zephir_concat_self(zval * left,zval * right)40 void zephir_concat_self(zval *left, zval *right)
41 {
42 	zval left_copy, right_copy;
43 	size_t length, left_length, right_length;
44 	int use_copy_left = 0, use_copy_right = 0;
45 	zend_string *target;
46 
47 	if (Z_TYPE_P(right) != IS_STRING) {
48 		use_copy_right = zephir_make_printable_zval(right, &right_copy);
49 		if (use_copy_right) {
50 			right = &right_copy;
51 		}
52 	}
53 
54 	if (Z_TYPE_P(left) == IS_NULL) {
55 		ZVAL_STRINGL(left, Z_STRVAL_P(right), Z_STRLEN_P(right));
56 
57 		if (use_copy_right) {
58 			zval_dtor(&right_copy);
59 		}
60 
61 		return;
62 	}
63 
64 	if (Z_TYPE_P(left) != IS_STRING) {
65 		use_copy_left = zephir_make_printable_zval(left, &left_copy);
66 		if (use_copy_left) {
67 			ZEPHIR_CPY_WRT_CTOR(left, (&left_copy));
68 		}
69 	}
70 
71 	SEPARATE_ZVAL_IF_NOT_REF(left);
72 
73 	left_length = Z_STRLEN_P(left);
74 	right_length = Z_STRLEN_P(right);
75 	length = left_length + right_length;
76 	target = zend_string_extend(Z_STR_P(left), length, 0);
77 	ZVAL_NEW_STR(left, target);
78 	memcpy(ZSTR_VAL(target) + left_length, Z_STRVAL_P(right), right_length);
79 
80 	ZSTR_VAL(target)[length] = '\0';
81 
82 	if (use_copy_left) {
83 		zval_dtor(&left_copy);
84 	}
85 
86 	if (use_copy_right) {
87 		zval_dtor(&right_copy);
88 	}
89 }
90 
91 /**
92  * Appends the content of the right operator to the left operator
93  */
zephir_concat_self_char(zval * left,unsigned char right)94 void zephir_concat_self_char(zval *left, unsigned char right)
95 {
96 	zval left_copy;
97 	int use_copy = 0, length;
98 	zend_string *target;
99 
100 	if (Z_TYPE_P(left) == IS_NULL) {
101 		target = zend_string_alloc(1, 0);
102 		ZSTR_VAL(target)[0] = right;
103 		ZSTR_VAL(target)[1] = 0;
104 		ZVAL_STR(left, target);;
105 		return;
106 	}
107 
108 	if (Z_TYPE_P(left) != IS_STRING) {
109 		use_copy = zephir_make_printable_zval(left, &left_copy);
110 		if (use_copy) {
111 			ZEPHIR_CPY_WRT_CTOR(left, (&left_copy));
112 		}
113 	}
114 
115 	SEPARATE_ZVAL_IF_NOT_REF(left);
116 
117 	length = Z_STRLEN_P(left) + 1;
118 	target = zend_string_extend(Z_STR_P(left), length, 0);
119 	ZVAL_NEW_STR(left, target);
120 	ZSTR_VAL(target)[length - 1] = right;
121 	ZSTR_VAL(target)[length] = 0;
122 
123 	if (use_copy) {
124 		zval_dtor(&left_copy);
125 	}
126 }
127 
128 /**
129  * Appends the content of the right operator to the left operator
130  */
zephir_concat_self_str(zval * left,const char * right,int right_length)131 void zephir_concat_self_str(zval *left, const char *right, int right_length)
132 {
133 	zval left_copy;
134 	size_t length, left_length;
135 	int use_copy = 0;
136 	zend_string *target;
137 
138 	if (Z_TYPE_P(left) == IS_NULL) {
139 		ZVAL_STRINGL(left, right, right_length);
140 		return;
141 	}
142 
143 	if (Z_TYPE_P(left) != IS_STRING) {
144 		use_copy = zephir_make_printable_zval(left, &left_copy);
145 		if (use_copy) {
146 			ZEPHIR_CPY_WRT_CTOR(left, (&left_copy));
147 		}
148 	}
149 
150 	SEPARATE_ZVAL_IF_NOT_REF(left);
151 	left_length = Z_STRLEN_P(left);
152 	length = left_length + right_length;
153 	target = zend_string_extend(Z_STR_P(left), length, 0);
154 	ZVAL_NEW_STR(left, target);
155 	memcpy(ZSTR_VAL(target) + left_length, right, right_length);
156 	ZSTR_VAL(target)[length] = '\0';
157 
158 	if (use_copy) {
159 		zval_dtor(&left_copy);
160 	}
161 }
162 
163 /**
164  * Natural compare with long operandus on right
165  */
zephir_compare_strict_long(zval * op1,long op2)166 int zephir_compare_strict_long(zval *op1, long op2)
167 {
168 	switch (Z_TYPE_P(op1)) {
169 		case IS_LONG:
170 			return Z_LVAL_P(op1) == op2;
171 		case IS_DOUBLE:
172 			return Z_DVAL_P(op1) == (double) op2;
173 		case IS_NULL:
174 			return 0 == op2;
175 		case IS_TRUE:
176 		case IS_FALSE:
177 			if (Z_TYPE_P(op1) == IS_TRUE) {
178 				return 1 == op2;
179 			} else {
180 				return 0 == op2;
181 			}
182 		default:
183 			{
184 				zval result, op2_tmp;
185 				ZVAL_LONG(&op2_tmp, op2);
186 				is_equal_function(&result, op1, &op2_tmp);
187 				return Z_TYPE(result) == IS_TRUE ? 1 : 0;
188 			}
189 	}
190 
191 	return 0;
192 }
193 
194 /**
195  * Natural compare with bool operandus on right
196  */
zephir_compare_strict_bool(zval * op1,zend_bool op2)197 int zephir_compare_strict_bool(zval *op1, zend_bool op2)
198 {
199 	switch (Z_TYPE_P(op1)) {
200 		case IS_LONG:
201 			return (Z_LVAL_P(op1) ? 1 : 0) == op2;
202 		case IS_DOUBLE:
203 			return (Z_DVAL_P(op1) ? 1 : 0) == op2;
204 		case IS_NULL:
205 			return 0 == op2;
206 		case IS_TRUE:
207 			return 1 == op2;
208 		case IS_FALSE:
209 			return 0 == op2;
210 		default:
211 			{
212 				zval result, op2_tmp;
213 				ZVAL_BOOL(&op2_tmp, op2);
214 				is_equal_function(&result, op1, &op2_tmp);
215 				return Z_TYPE(result) == IS_TRUE;
216 			}
217 	}
218 
219 	return 0;
220 }
221 
222 /**
223  * Natural compare with string operandus on right
224  */
zephir_compare_strict_string(zval * op1,const char * op2,int op2_length)225 int zephir_compare_strict_string(zval *op1, const char *op2, int op2_length)
226 {
227 	switch (Z_TYPE_P(op1)) {
228 
229 		case IS_STRING:
230 			if (!Z_STRLEN_P(op1) && !op2_length) {
231 				return 1;
232 			}
233 			if (Z_STRLEN_P(op1) != op2_length) {
234 				return 0;
235 			}
236 			return !zend_binary_strcmp(Z_STRVAL_P(op1), Z_STRLEN_P(op1), op2, op2_length);
237 
238 		case IS_NULL:
239 			return !zend_binary_strcmp("", 0, op2, op2_length);
240 
241 		case IS_TRUE:
242 			return !zend_binary_strcmp("1", strlen("1"), op2, op2_length);
243 
244 		case IS_FALSE:
245 			return !zend_binary_strcmp("0", strlen("0"), op2, op2_length);
246 	}
247 
248 	return 0;
249 }
250 
zephir_negate(zval * z)251 void zephir_negate(zval *z)
252 {
253 	while (1) {
254 		switch (Z_TYPE_P(z)) {
255 			case IS_LONG:
256 				ZVAL_LONG(z, -Z_LVAL_P(z));
257 				return;
258 
259 			case IS_TRUE:
260 				ZVAL_LONG(z, -1);
261 				return;
262 
263 			case IS_DOUBLE:
264 				ZVAL_DOUBLE(z, -Z_DVAL_P(z));
265 				return;
266 
267 			case IS_NULL:
268 			case IS_FALSE:
269 				ZVAL_LONG(z, 0);
270 				return;
271 
272 			default:
273 				convert_scalar_to_number(z);
274 				assert(Z_TYPE_P(z) == IS_LONG || Z_TYPE_P(z) == IS_DOUBLE);
275 		}
276 	}
277 }
278 
zephir_convert_to_object(zval * op)279 void zephir_convert_to_object(zval *op)
280 {
281     convert_to_object(op);
282 }
283 
284 /**
285  * Returns the long value of a zval
286  */
zephir_get_intval_ex(const zval * op)287 long zephir_get_intval_ex(const zval *op)
288 {
289 	switch (Z_TYPE_P(op)) {
290 		case IS_ARRAY:
291 			return zend_hash_num_elements(Z_ARRVAL_P(op)) ? 1 : 0;
292 
293 		case IS_RESOURCE:
294 			return (zend_long)Z_RES_HANDLE_P(op);
295 
296 		case IS_CALLABLE:
297 		case IS_OBJECT:
298 			return 1;
299 
300 		case IS_LONG:
301 			return Z_LVAL_P(op);
302 
303 		case IS_TRUE:
304 			return 1;
305 
306 		case IS_FALSE:
307 			return 0;
308 
309 		case IS_DOUBLE:
310 			return (long) Z_DVAL_P(op);
311 
312 		case IS_STRING: {
313 			zend_uchar type;
314 			double double_value = 0;
315 			zend_long long_value = 0;
316 
317 			ASSUME(Z_STRVAL_P(op) != NULL);
318 			type = is_numeric_string(Z_STRVAL_P(op), Z_STRLEN_P(op), &long_value, &double_value, 0);
319 			if (type == IS_LONG) {
320 				return long_value;
321 			}
322 			if (type == IS_DOUBLE) {
323 				return (long) double_value;
324 			}
325 			return 0;
326 		}
327 	}
328 
329 	return 0;
330 }
331 
zephir_get_charval_ex(const zval * op)332 long zephir_get_charval_ex(const zval *op)
333 {
334 	switch (Z_TYPE_P(op)) {
335         case IS_ARRAY:
336 	    case IS_CALLABLE:
337 	    case IS_RESOURCE:
338 	    case IS_OBJECT:
339 	        return 0;
340 
341 		case IS_LONG:
342 			return Z_LVAL_P(op);
343 
344 		case IS_TRUE:
345 			return 1;
346 
347 		case IS_FALSE:
348 			return 0;
349 
350 		case IS_DOUBLE:
351 			return (long) Z_DVAL_P(op);
352 
353 		case IS_STRING: {
354 			if (Z_STRLEN_P(op) > 0) {
355 				return Z_STRVAL_P(op)[0];
356 			}
357 			return 0;
358 		}
359 	}
360 
361 	return 0;
362 }
363 
364 /**
365  * Returns the long value of a zval
366  */
zephir_get_doubleval_ex(const zval * op)367 double zephir_get_doubleval_ex(const zval *op)
368 {
369 	int type;
370 	zend_long long_value = 0;
371 	double double_value = 0;
372 
373 	switch (Z_TYPE_P(op)) {
374 
375         case IS_ARRAY:
376             return zend_hash_num_elements(Z_ARRVAL_P(op)) ? (double) 1 : 0;
377 
378 	    case IS_CALLABLE:
379 	    case IS_RESOURCE:
380 	    case IS_OBJECT:
381 	        return (double) 1;
382 
383 		case IS_LONG:
384 			return (double) Z_LVAL_P(op);
385 
386 		case IS_TRUE:
387 			return (double) 1;
388 
389 		case IS_FALSE:
390 			return (double) 0;
391 
392 		case IS_DOUBLE:
393 			return Z_DVAL_P(op);
394 
395 		case IS_STRING:
396 			if ((type = is_numeric_string(Z_STRVAL_P(op), Z_STRLEN_P(op), &long_value, &double_value, 0))) {
397 				if (type == IS_LONG) {
398 					return (double) long_value;
399 				} else {
400 					if (type == IS_DOUBLE) {
401 						return double_value;
402 					} else {
403 						return 0;
404 					}
405 				}
406 			}
407 	}
408 
409 	return 0;
410 }
411 
412 /**
413  * Returns the long value of a zval
414  */
zephir_get_boolval_ex(zval * op)415 zend_bool zephir_get_boolval_ex(zval *op)
416 {
417 	return (zend_bool) zend_is_true(op);
418 }
419 
420 /**
421  * Returns the long value of a zval
422  */
zephir_is_numeric_ex(const zval * op)423 int zephir_is_numeric_ex(const zval *op)
424 {
425 	int type;
426 
427 	switch (Z_TYPE_P(op)) {
428 
429 		case IS_LONG:
430 			return 1;
431 
432 		case IS_TRUE:
433 		case IS_FALSE:
434 			return 0;
435 
436 		case IS_DOUBLE:
437 			return 1;
438 
439 		case IS_STRING:
440 			if ((type = is_numeric_string(Z_STRVAL_P(op), Z_STRLEN_P(op), NULL, NULL, 0))) {
441 				if (type == IS_LONG || type == IS_DOUBLE) {
442 					return 1;
443 				}
444 			}
445 	}
446 
447 	return 0;
448 }
449 
450 /**
451  * Check if two zvals are equal
452  */
zephir_is_equal(zval * op1,zval * op2)453 int zephir_is_equal(zval *op1, zval *op2)
454 {
455 	zval result;
456 
457 	is_equal_function(&result, op1, op2);
458 	return Z_TYPE(result) == IS_TRUE;
459 }
460 
461 /**
462  * Check if a zval is less than other
463  */
zephir_less(zval * op1,zval * op2)464 int zephir_less(zval *op1, zval *op2)
465 {
466 	zval result;
467 	is_smaller_function(&result, op1, op2);
468 	return Z_TYPE(result) == IS_TRUE;
469 }
470 
471 /**
472  * Check if a zval is greater than other
473  */
zephir_greater(zval * op1,zval * op2)474 int zephir_greater(zval *op1, zval *op2)
475 {
476 	zval result;
477 	is_smaller_or_equal_function(&result, op1, op2);
478 	return Z_TYPE(result) == IS_FALSE;
479 }
480 
481 /**
482  * Check if two zvals are identical
483  */
zephir_is_identical(zval * op1,zval * op2)484 int zephir_is_identical(zval *op1, zval *op2)
485 {
486 	zval result;
487 	is_identical_function(&result, op1, op2);
488 	return Z_TYPE(result) == IS_TRUE;
489 }
490 
491 /**
492  * Do bitwise_and function
493  */
zephir_bitwise_and_function(zval * result,zval * op1,zval * op2)494 int zephir_bitwise_and_function(zval *result, zval *op1, zval *op2)
495 {
496 	int status;
497 	status = bitwise_and_function(result, op1, op2);
498 	return status;
499 }
500 
501 /**
502  * Do bitwise_or function
503  */
zephir_bitwise_or_function(zval * result,zval * op1,zval * op2)504 int zephir_bitwise_or_function(zval *result, zval *op1, zval *op2)
505 {
506 	int status;
507 	status = bitwise_or_function(result, op1, op2);
508 	return status;
509 }
510 
511 /**
512  * Do bitwise_xor function
513  */
zephir_bitwise_xor_function(zval * result,zval * op1,zval * op2)514 int zephir_bitwise_xor_function(zval *result, zval *op1, zval *op2)
515 {
516 	int status;
517 	status = bitwise_xor_function(result, op1, op2);
518 	return status;
519 }
520 
521 /**
522  * Check if a zval is less/equal than other
523  */
zephir_less_equal(zval * op1,zval * op2)524 int zephir_less_equal(zval *op1, zval *op2)
525 {
526 	zval result;
527 	is_smaller_or_equal_function(&result, op1, op2);
528 	return Z_TYPE(result) == IS_TRUE;
529 }
530 
531 /**
532  * Check if a zval is less than a long value
533  */
zephir_less_long(zval * op1,long op2)534 int zephir_less_long(zval *op1, long op2)
535 {
536 	zval result, op2_zval;
537 	ZVAL_LONG(&op2_zval, op2);
538 
539 	is_smaller_function(&result, op1, &op2_zval);
540 	return Z_TYPE(result) == IS_TRUE;
541 }
542 
zephir_less_double(zval * op1,double op2)543 int zephir_less_double(zval *op1, double op2)
544 {
545 	zval result, op2_zval;
546 	ZVAL_DOUBLE(&op2_zval, op2);
547 
548 	is_smaller_function(&result, op1, &op2_zval);
549 	return Z_TYPE(result) == IS_TRUE;
550 }
551 
zephir_less_equal_long(zval * op1,long op2)552 int zephir_less_equal_long(zval *op1, long op2)
553 {
554 	zval result, op2_zval;
555 	ZVAL_LONG(&op2_zval, op2);
556 
557 	is_smaller_or_equal_function(&result, op1, &op2_zval);
558 	return Z_TYPE(result) == IS_TRUE;
559 }
560 
561 /**
562  * Check if a zval is greater than a long value
563  */
zephir_greater_long(zval * op1,long op2)564 int zephir_greater_long(zval *op1, long op2)
565 {
566 	zval result, op2_zval;
567 	ZVAL_LONG(&op2_zval, op2);
568 
569 	is_smaller_or_equal_function(&result, op1, &op2_zval);
570 	return Z_TYPE(result) == IS_FALSE;
571 }
572 
zephir_greater_double(zval * op1,double op2)573 int zephir_greater_double(zval *op1, double op2)
574 {
575 	zval result, op2_zval;
576 	ZVAL_DOUBLE(&op2_zval, op2);
577 
578 	is_smaller_or_equal_function(&result, op1, &op2_zval);
579 	return Z_TYPE(result) == IS_FALSE;
580 }
581 
582 /**
583  * Check if a zval is greater/equal than other
584  */
zephir_greater_equal(zval * op1,zval * op2)585 int zephir_greater_equal(zval *op1, zval *op2)
586 {
587 	zval result;
588 	is_smaller_function(&result, op1, op2);
589 	return Z_TYPE(result) == IS_FALSE;
590 }
591 
592 /**
593  * Check for greater/equal
594  */
zephir_greater_equal_long(zval * op1,long op2)595 int zephir_greater_equal_long(zval *op1, long op2)
596 {
597 	zval result, op2_zval;
598 	ZVAL_LONG(&op2_zval, op2);
599 	is_smaller_function(&result, op1, &op2_zval);
600 	return Z_TYPE(result) == IS_FALSE;
601 }
602 
603 /**
604  * Do safe divisions between two longs
605  */
zephir_safe_div_long_long(long op1,long op2)606 double zephir_safe_div_long_long(long op1, long op2)
607 {
608 	if (!op2) {
609 		zend_error(E_WARNING, "Division by zero");
610 		return 0;
611 	}
612 	return (double) op1 / (double) op2;
613 }
614 
615 /**
616  * Do safe divisions between two long/double
617  */
zephir_safe_div_long_double(long op1,double op2)618 double zephir_safe_div_long_double(long op1, double op2)
619 {
620 	if (!op2) {
621 		zend_error(E_WARNING, "Division by zero");
622 		return 0;
623 	}
624 	return (double) op1 / op2;
625 }
626 
627 /**
628  * Do safe divisions between two double/zval
629  */
zephir_safe_div_double_zval(double op1,zval * op2)630 double zephir_safe_div_double_zval(double op1, zval *op2)
631 {
632 	if (!zephir_get_numberval(op2)) {
633 		zend_error(E_WARNING, "Division by zero");
634 		return 0;
635 	}
636 	switch (Z_TYPE_P(op2)) {
637 		case IS_ARRAY:
638 		case IS_OBJECT:
639 		case IS_RESOURCE:
640 			zend_error(E_WARNING, "Unsupported operand types");
641 			break;
642 	}
643 	return op1 / ((double) zephir_get_numberval(op2));
644 }
645 
646 /**
647  * Do safe divisions between two double/long
648  */
zephir_safe_div_double_long(double op1,long op2)649 double zephir_safe_div_double_long(double op1, long op2)
650 {
651 	if (!op2) {
652 		zend_error(E_WARNING, "Division by zero");
653 		return 0;
654 	}
655 	return op1 / (double) op2;
656 }
657 
658 /**
659  * Do safe divisions between two doubles
660  */
zephir_safe_div_double_double(double op1,double op2)661 double zephir_safe_div_double_double(double op1, double op2)
662 {
663 	if (!op2) {
664 		zend_error(E_WARNING, "Division by zero");
665 		return 0;
666 	}
667 	return op1 / op2;
668 }
669 
670 /**
671  * Do safe divisions between two zval/long
672  */
zephir_safe_div_zval_long(zval * op1,long op2)673 double zephir_safe_div_zval_long(zval *op1, long op2)
674 {
675 	if (!op2) {
676 		zend_error(E_WARNING, "Division by zero");
677 		return 0;
678 	}
679 	switch (Z_TYPE_P(op1)) {
680 		case IS_ARRAY:
681 		case IS_OBJECT:
682 		case IS_RESOURCE:
683 			zend_error(E_WARNING, "Unsupported operand types");
684 			break;
685 	}
686 	return ((double) zephir_get_numberval(op1)) / (double) op2;
687 }
688 
689 /**
690  * Do safe divisions between two long/zval
691  */
zephir_safe_div_long_zval(long op1,zval * op2)692 double zephir_safe_div_long_zval(long op1, zval *op2)
693 {
694 	if (!zephir_get_numberval(op2)) {
695 		zend_error(E_WARNING, "Division by zero");
696 		return 0;
697 	}
698 	switch (Z_TYPE_P(op2)) {
699 		case IS_ARRAY:
700 		case IS_OBJECT:
701 		case IS_RESOURCE:
702 			zend_error(E_WARNING, "Unsupported operand types");
703 			break;
704 	}
705 	return (double) op1 / ((double) zephir_get_numberval(op2));
706 }
707 
708 /**
709  * Do safe divisions between two zval/double
710  */
zephir_safe_div_zval_double(zval * op1,double op2)711 double zephir_safe_div_zval_double(zval *op1, double op2)
712 {
713 	if (!op2) {
714 		zend_error(E_WARNING, "Division by zero");
715 		return 0;
716 	}
717 	switch (Z_TYPE_P(op1)) {
718 		case IS_ARRAY:
719 		case IS_OBJECT:
720 		case IS_RESOURCE:
721 			zend_error(E_WARNING, "Unsupported operand types");
722 			break;
723 	}
724 	return ((double) zephir_get_numberval(op1)) / op2;
725 }
726 
727 /**
728  * Do safe divisions between two longs
729  */
zephir_safe_mod_long_long(long op1,long op2)730 long zephir_safe_mod_long_long(long op1, long op2)
731 {
732 	if (!op2) {
733 		zend_error(E_WARNING, "Division by zero");
734 		return 0;
735 	}
736 	return op1 % op2;
737 }
738 
739 /**
740  * Do safe divisions between two zval/long
741  */
zephir_safe_mod_zval_long(zval * op1,long op2)742 long zephir_safe_mod_zval_long(zval *op1, long op2)
743 {
744 	if (!op2) {
745 		zend_error(E_WARNING, "Division by zero");
746 		return 0;
747 	}
748 	switch (Z_TYPE_P(op1)) {
749 		case IS_ARRAY:
750 		case IS_OBJECT:
751 		case IS_RESOURCE:
752 			zend_error(E_WARNING, "Unsupported operand types");
753 			break;
754 	}
755 	return ((long) zephir_get_numberval(op1)) % (long) op2;
756 }
757