php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
bcmath.c
Go to the documentation of this file.
1/*
2 +----------------------------------------------------------------------+
3 | Copyright (c) The PHP Group |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | https://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Author: Andi Gutmans <andi@php.net> |
14 +----------------------------------------------------------------------+
15*/
16
17#ifdef HAVE_CONFIG_H
18#include <config.h>
19#endif
20
21#include "php.h"
22
23#ifdef HAVE_BCMATH
24
25#include "php_ini.h"
26#include "zend_exceptions.h"
27#include "zend_interfaces.h"
28#include "bcmath_arginfo.h"
29#include "ext/standard/info.h"
30#include "php_bcmath.h"
32
33/* Always pair SETUP with TEARDOWN, and do so in the outer scope!
34 * Should not be used when data can escape the function. */
35#define BC_ARENA_SETUP \
36 char bc_arena[BC_ARENA_SIZE]; \
37 BCG(arena) = bc_arena;
38
39#define BC_ARENA_TEARDOWN \
40 BCG(arena) = NULL; \
41 BCG(arena_offset) = 0;
42
44static PHP_GINIT_FUNCTION(bcmath);
45static PHP_GSHUTDOWN_FUNCTION(bcmath);
46static PHP_MINIT_FUNCTION(bcmath);
47static PHP_MSHUTDOWN_FUNCTION(bcmath);
48static PHP_MINFO_FUNCTION(bcmath);
49
52 "bcmath",
53 ext_functions,
54 PHP_MINIT(bcmath),
55 PHP_MSHUTDOWN(bcmath),
56 NULL,
57 NULL,
58 PHP_MINFO(bcmath),
60 PHP_MODULE_GLOBALS(bcmath),
61 PHP_GINIT(bcmath),
62 PHP_GSHUTDOWN(bcmath),
63 NULL,
65};
66
67#ifdef COMPILE_DL_BCMATH
68#ifdef ZTS
70#endif
71ZEND_GET_MODULE(bcmath)
72#endif
73
74ZEND_INI_MH(OnUpdateScale)
75{
76 int *p;
77 zend_long tmp;
78
79 tmp = zend_ini_parse_quantity_warn(new_value, entry->name);
80 if (tmp < 0 || tmp > INT_MAX) {
81 return FAILURE;
82 }
83
84 p = (int *) ZEND_INI_GET_ADDR();
85 *p = (int) tmp;
86
87 return SUCCESS;
88}
89
90/* {{{ PHP_INI */
92 STD_PHP_INI_ENTRY("bcmath.scale", "0", PHP_INI_ALL, OnUpdateScale, bc_precision, zend_bcmath_globals, bcmath_globals)
94/* }}} */
95
96/* {{{ PHP_GINIT_FUNCTION */
97static PHP_GINIT_FUNCTION(bcmath)
98{
99#if defined(COMPILE_DL_BCMATH) && defined(ZTS)
101#endif
102 bcmath_globals->bc_precision = 0;
103 bcmath_globals->arena = NULL;
104 bcmath_globals->arena_offset = 0;
106}
107/* }}} */
108
109/* {{{ PHP_GSHUTDOWN_FUNCTION */
110static PHP_GSHUTDOWN_FUNCTION(bcmath)
111{
112 bc_force_free_number(&bcmath_globals->_zero_);
113 bc_force_free_number(&bcmath_globals->_one_);
114 bc_force_free_number(&bcmath_globals->_two_);
115 bcmath_globals->arena = NULL;
116 bcmath_globals->arena_offset = 0;
117}
118/* }}} */
119
120static void bcmath_number_register_class(void);
121
122/* {{{ PHP_MINIT_FUNCTION */
123PHP_MINIT_FUNCTION(bcmath)
124{
126 bcmath_number_register_class();
127
128 return SUCCESS;
129}
130/* }}} */
131
132/* {{{ PHP_MSHUTDOWN_FUNCTION */
134{
136
137 return SUCCESS;
138}
139/* }}} */
140
141/* {{{ PHP_MINFO_FUNCTION */
142PHP_MINFO_FUNCTION(bcmath)
143{
145 php_info_print_table_row(2, "BCMath support", "enabled");
148}
149/* }}} */
150
151static zend_always_inline zend_result bcmath_check_scale(zend_long scale, uint32_t arg_num)
152{
153 if (UNEXPECTED(scale < 0 || scale > INT_MAX)) {
154 zend_argument_value_error(arg_num, "must be between 0 and %d", INT_MAX);
155 return FAILURE;
156 }
157 return SUCCESS;
158}
159
160static void php_long2num(bc_num *num, zend_long lval)
161{
162 *num = bc_long2num(lval);
163}
164
165static zend_result php_str2num_ex(bc_num *num, const zend_string *str, size_t *full_scale)
166{
167 if (!bc_str2num(num, ZSTR_VAL(str), ZSTR_VAL(str) + ZSTR_LEN(str), 0, full_scale, true)) {
168 return FAILURE;
169 }
170
171 return SUCCESS;
172}
173
174/* {{{ php_str2num
175 Convert to bc_num detecting scale */
176static zend_result php_str2num(bc_num *num, const zend_string *str)
177{
178 return php_str2num_ex(num, str, NULL);
179}
180/* }}} */
181
182/* {{{ Returns the sum of two arbitrary precision numbers */
184{
186 zend_long scale_param;
187 bool scale_param_is_null = 1;
188 bc_num first = NULL, second = NULL, result = NULL;
189 int scale;
190
195 Z_PARAM_LONG_OR_NULL(scale_param, scale_param_is_null)
197
198 if (scale_param_is_null) {
199 scale = BCG(bc_precision);
200 } else if (bcmath_check_scale(scale_param, 3) == FAILURE) {
202 } else {
203 scale = (int) scale_param;
204 }
205
206 BC_ARENA_SETUP;
207
208 if (php_str2num(&first, left) == FAILURE) {
209 zend_argument_value_error(1, "is not well-formed");
210 goto cleanup;
211 }
212
213 if (php_str2num(&second, right) == FAILURE) {
214 zend_argument_value_error(2, "is not well-formed");
215 goto cleanup;
216 }
217
218 result = bc_add (first, second, scale);
219
221
222 cleanup: {
223 bc_free_num(&first);
224 bc_free_num(&second);
226 BC_ARENA_TEARDOWN;
227 };
228}
229/* }}} */
230
231/* {{{ Returns the difference between two arbitrary precision numbers */
233{
235 zend_long scale_param;
236 bool scale_param_is_null = 1;
237 bc_num first = NULL, second = NULL, result = NULL;
238 int scale;
239
244 Z_PARAM_LONG_OR_NULL(scale_param, scale_param_is_null)
246
247 if (scale_param_is_null) {
248 scale = BCG(bc_precision);
249 } else if (bcmath_check_scale(scale_param, 3) == FAILURE) {
251 } else {
252 scale = (int) scale_param;
253 }
254
255 BC_ARENA_SETUP;
256
257 if (php_str2num(&first, left) == FAILURE) {
258 zend_argument_value_error(1, "is not well-formed");
259 goto cleanup;
260 }
261
262 if (php_str2num(&second, right) == FAILURE) {
263 zend_argument_value_error(2, "is not well-formed");
264 goto cleanup;
265 }
266
267 result = bc_sub (first, second, scale);
268
270
271 cleanup: {
272 bc_free_num(&first);
273 bc_free_num(&second);
275 BC_ARENA_TEARDOWN;
276 };
277}
278/* }}} */
279
280/* {{{ Returns the multiplication of two arbitrary precision numbers */
282{
284 zend_long scale_param;
285 bool scale_param_is_null = 1;
286 bc_num first = NULL, second = NULL, result = NULL;
287 int scale;
288
293 Z_PARAM_LONG_OR_NULL(scale_param, scale_param_is_null)
295
296 if (scale_param_is_null) {
297 scale = BCG(bc_precision);
298 } else if (bcmath_check_scale(scale_param, 3) == FAILURE) {
300 } else {
301 scale = (int) scale_param;
302 }
303
304 BC_ARENA_SETUP;
305
306 if (php_str2num(&first, left) == FAILURE) {
307 zend_argument_value_error(1, "is not well-formed");
308 goto cleanup;
309 }
310
311 if (php_str2num(&second, right) == FAILURE) {
312 zend_argument_value_error(2, "is not well-formed");
313 goto cleanup;
314 }
315
316 result = bc_multiply (first, second, scale);
317
319
320 cleanup: {
321 bc_free_num(&first);
322 bc_free_num(&second);
324 BC_ARENA_TEARDOWN;
325 };
326}
327/* }}} */
328
329/* {{{ Returns the quotient of two arbitrary precision numbers (division) */
331{
333 zend_long scale_param;
334 bool scale_param_is_null = 1;
335 bc_num first = NULL, second = NULL, result;
336 int scale = BCG(bc_precision);
337
342 Z_PARAM_LONG_OR_NULL(scale_param, scale_param_is_null)
344
345 if (scale_param_is_null) {
346 scale = BCG(bc_precision);
347 } else if (bcmath_check_scale(scale_param, 3) == FAILURE) {
349 } else {
350 scale = (int) scale_param;
351 }
352
353 BC_ARENA_SETUP;
354
356
357 if (php_str2num(&first, left) == FAILURE) {
358 zend_argument_value_error(1, "is not well-formed");
359 goto cleanup;
360 }
361
362 if (php_str2num(&second, right) == FAILURE) {
363 zend_argument_value_error(2, "is not well-formed");
364 goto cleanup;
365 }
366
367 if (!bc_divide(first, second, &result, scale)) {
369 goto cleanup;
370 }
371
373
374 cleanup: {
375 bc_free_num(&first);
376 bc_free_num(&second);
378 BC_ARENA_TEARDOWN;
379 };
380}
381/* }}} */
382
383/* {{{ Returns the modulus of the two arbitrary precision operands */
385{
387 zend_long scale_param;
388 bool scale_param_is_null = 1;
389 bc_num first = NULL, second = NULL, result;
390 int scale = BCG(bc_precision);
391
396 Z_PARAM_LONG_OR_NULL(scale_param, scale_param_is_null)
398
399 if (scale_param_is_null) {
400 scale = BCG(bc_precision);
401 } else if (bcmath_check_scale(scale_param, 3) == FAILURE) {
403 } else {
404 scale = (int) scale_param;
405 }
406
407 BC_ARENA_SETUP;
408
410
411 if (php_str2num(&first, left) == FAILURE) {
412 zend_argument_value_error(1, "is not well-formed");
413 goto cleanup;
414 }
415
416 if (php_str2num(&second, right) == FAILURE) {
417 zend_argument_value_error(2, "is not well-formed");
418 goto cleanup;
419 }
420
421 if (!bc_modulo(first, second, &result, scale)) {
423 goto cleanup;
424 }
425
427
428 cleanup: {
429 bc_free_num(&first);
430 bc_free_num(&second);
432 BC_ARENA_TEARDOWN;
433 };
434}
435/* }}} */
436
438{
440 zend_long scale_param;
441 bool scale_param_is_null = 1;
442 bc_num first = NULL, second = NULL, quot = NULL, rem = NULL;
443 int scale = BCG(bc_precision);
444
449 Z_PARAM_LONG_OR_NULL(scale_param, scale_param_is_null)
451
452 if (scale_param_is_null) {
453 scale = BCG(bc_precision);
454 } else if (bcmath_check_scale(scale_param, 3) == FAILURE) {
456 } else {
457 scale = (int) scale_param;
458 }
459
460 BC_ARENA_SETUP;
461
462 if (php_str2num(&first, left) == FAILURE) {
463 zend_argument_value_error(1, "is not well-formed");
464 goto cleanup;
465 }
466
467 if (php_str2num(&second, right) == FAILURE) {
468 zend_argument_value_error(2, "is not well-formed");
469 goto cleanup;
470 }
471
472 if (!bc_divmod(first, second, &quot, &rem, scale)) {
474 goto cleanup;
475 }
476
477 zval z_quot, z_rem;
478 ZVAL_STR(&z_quot, bc_num2str_ex(quot, 0));
479 ZVAL_STR(&z_rem, bc_num2str_ex(rem, scale));
480
481 RETVAL_ARR(zend_new_pair(&z_quot, &z_rem));
482
483 cleanup: {
484 bc_free_num(&first);
485 bc_free_num(&second);
486 bc_free_num(&quot);
487 bc_free_num(&rem);
488 BC_ARENA_TEARDOWN;
489 };
490}
491
492/* {{{ Returns the value of an arbitrary precision number raised to the power of another reduced by a modulus */
494{
495 zend_string *base_str, *exponent_str, *modulus_str;
496 zend_long scale_param;
497 bool scale_param_is_null = 1;
498 bc_num bc_base = NULL, bc_expo = NULL, bc_modulus = NULL, result;
499 int scale = BCG(bc_precision);
500
502 Z_PARAM_STR(base_str)
503 Z_PARAM_STR(exponent_str)
504 Z_PARAM_STR(modulus_str)
506 Z_PARAM_LONG_OR_NULL(scale_param, scale_param_is_null)
508
509 if (scale_param_is_null) {
510 scale = BCG(bc_precision);
511 } else if (bcmath_check_scale(scale_param, 4) == FAILURE) {
513 } else {
514 scale = (int) scale_param;
515 }
516
517 BC_ARENA_SETUP;
518
520
521 if (php_str2num(&bc_base, base_str) == FAILURE) {
522 zend_argument_value_error(1, "is not well-formed");
523 goto cleanup;
524 }
525
526 if (php_str2num(&bc_expo, exponent_str) == FAILURE) {
527 zend_argument_value_error(2, "is not well-formed");
528 goto cleanup;
529 }
530
531 if (php_str2num(&bc_modulus, modulus_str) == FAILURE) {
532 zend_argument_value_error(3, "is not well-formed");
533 goto cleanup;
534 }
535
536 raise_mod_status status = bc_raisemod(bc_base, bc_expo, bc_modulus, &result, scale);
537 switch (status) {
539 zend_argument_value_error(1, "cannot have a fractional part");
540 goto cleanup;
542 zend_argument_value_error(2, "cannot have a fractional part");
543 goto cleanup;
544 case EXPO_IS_NEGATIVE:
545 zend_argument_value_error(2, "must be greater than or equal to 0");
546 goto cleanup;
548 zend_argument_value_error(3, "cannot have a fractional part");
549 goto cleanup;
550 case MOD_IS_ZERO:
552 goto cleanup;
553 case OK:
555 break;
557 }
558
559 cleanup: {
560 bc_free_num(&bc_base);
561 bc_free_num(&bc_expo);
562 bc_free_num(&bc_modulus);
564 BC_ARENA_TEARDOWN;
565 };
566}
567/* }}} */
568
569/* {{{ Returns the value of an arbitrary precision number raised to the power of another */
571{
572 zend_string *base_str, *exponent_str;
573 zend_long scale_param;
574 bool scale_param_is_null = 1;
575 bc_num first = NULL, bc_exponent = NULL, result;
576 int scale = BCG(bc_precision);
577
579 Z_PARAM_STR(base_str)
580 Z_PARAM_STR(exponent_str)
582 Z_PARAM_LONG_OR_NULL(scale_param, scale_param_is_null)
584
585 if (scale_param_is_null) {
586 scale = BCG(bc_precision);
587 } else if (bcmath_check_scale(scale_param, 3) == FAILURE) {
589 } else {
590 scale = (int) scale_param;
591 }
592
593 BC_ARENA_SETUP;
594
596
597 if (php_str2num(&first, base_str) == FAILURE) {
598 zend_argument_value_error(1, "is not well-formed");
599 goto cleanup;
600 }
601
602 if (php_str2num(&bc_exponent, exponent_str) == FAILURE) {
603 zend_argument_value_error(2, "is not well-formed");
604 goto cleanup;
605 }
606
607 /* Check the exponent for scale digits and convert to a long. */
608 if (bc_exponent->n_scale != 0) {
609 zend_argument_value_error(2, "cannot have a fractional part");
610 goto cleanup;
611 }
612 long exponent = bc_num2long(bc_exponent);
613 if (exponent == 0 && (bc_exponent->n_len > 1 || bc_exponent->n_value[0] != 0)) {
614 zend_argument_value_error(2, "is too large");
615 goto cleanup;
616 }
617
618 if (!bc_raise(first, exponent, &result, scale)) {
619 zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Negative power of zero");
620 goto cleanup;
621 }
622
624
625 cleanup: {
626 bc_free_num(&first);
627 bc_free_num(&bc_exponent);
629 BC_ARENA_TEARDOWN;
630 };
631}
632/* }}} */
633
634/* {{{ Returns the square root of an arbitrary precision number */
636{
638 zend_long scale_param;
639 bool scale_param_is_null = 1;
641 int scale = BCG(bc_precision);
642
646 Z_PARAM_LONG_OR_NULL(scale_param, scale_param_is_null)
648
649 if (scale_param_is_null) {
650 scale = BCG(bc_precision);
651 } else if (bcmath_check_scale(scale_param, 2) == FAILURE) {
653 } else {
654 scale = (int) scale_param;
655 }
656
657 BC_ARENA_SETUP;
658
659 if (php_str2num(&result, left) == FAILURE) {
660 zend_argument_value_error(1, "is not well-formed");
661 goto cleanup;
662 }
663
664 if (bc_sqrt (&result, scale) != 0) {
666 } else {
667 zend_argument_value_error(1, "must be greater than or equal to 0");
668 }
669
670 cleanup: {
672 BC_ARENA_TEARDOWN;
673 };
674}
675/* }}} */
676
677/* {{{ Compares two arbitrary precision numbers */
679{
681 zend_long scale_param;
682 bool scale_param_is_null = 1;
683 bc_num first = NULL, second = NULL;
684 int scale = BCG(bc_precision);
685
690 Z_PARAM_LONG_OR_NULL(scale_param, scale_param_is_null)
692
693 if (scale_param_is_null) {
694 scale = BCG(bc_precision);
695 } else if (bcmath_check_scale(scale_param, 3) == FAILURE) {
697 } else {
698 scale = (int) scale_param;
699 }
700
701 BC_ARENA_SETUP;
702
703 if (!bc_str2num(&first, ZSTR_VAL(left), ZSTR_VAL(left) + ZSTR_LEN(left), scale, NULL, false)) {
704 zend_argument_value_error(1, "is not well-formed");
705 goto cleanup;
706 }
707
708 if (!bc_str2num(&second, ZSTR_VAL(right), ZSTR_VAL(right) + ZSTR_LEN(right), scale, NULL, false)) {
709 zend_argument_value_error(2, "is not well-formed");
710 goto cleanup;
711 }
712
713 RETVAL_LONG(bc_compare(first, second, scale));
714
715 cleanup: {
716 bc_free_num(&first);
717 bc_free_num(&second);
718 BC_ARENA_TEARDOWN;
719 };
720}
721/* }}} */
722
723/* {{{ floor or ceil */
724static void bcfloor_or_bcceil(INTERNAL_FUNCTION_PARAMETERS, bool is_floor)
725{
726 zend_string *numstr;
727 bc_num num = NULL, result = NULL;
728
730 Z_PARAM_STR(numstr)
732
733 BC_ARENA_SETUP;
734
735 if (php_str2num(&num, numstr) == FAILURE) {
736 zend_argument_value_error(1, "is not well-formed");
737 goto cleanup;
738 }
739
740 result = bc_floor_or_ceil(num, is_floor);
742
743 cleanup: {
744 bc_free_num(&num);
746 BC_ARENA_TEARDOWN;
747 };
748}
749/* }}} */
750
751/* {{{ Returns floor of num */
753{
754 bcfloor_or_bcceil(INTERNAL_FUNCTION_PARAM_PASSTHRU, true);
755}
756/* }}} */
757
758/* {{{ Returns ceil of num */
760{
761 bcfloor_or_bcceil(INTERNAL_FUNCTION_PARAM_PASSTHRU, false);
762}
763/* }}} */
764
765/* {{{ Returns num rounded to the digits specified by precision. */
767{
768 zend_string *numstr;
769 zend_long precision = 0;
771 zend_object *mode_object = NULL;
772 bc_num num = NULL, result;
773
775 Z_PARAM_STR(numstr)
777 Z_PARAM_LONG(precision)
780
781 if (mode_object != NULL) {
782 mode = php_math_round_mode_from_enum(mode_object);
783 }
784
785 switch (mode) {
791 case PHP_ROUND_FLOOR:
794 break;
795 default:
796 /* This is currently unreachable, but might become reachable when new modes are added. */
797 zend_argument_value_error(3, "is an unsupported rounding mode");
798 return;
799 }
800
801 BC_ARENA_SETUP;
802
804
805 if (php_str2num(&num, numstr) == FAILURE) {
806 zend_argument_value_error(1, "is not well-formed");
807 goto cleanup;
808 }
809
810 bc_round(num, precision, mode, &result);
812
813 cleanup: {
814 bc_free_num(&num);
816 BC_ARENA_TEARDOWN;
817 };
818}
819/* }}} */
820
821/* {{{ Sets default scale parameter for all bc math functions */
823{
824 zend_long old_scale, new_scale;
825 bool new_scale_is_null = 1;
826
829 Z_PARAM_LONG_OR_NULL(new_scale, new_scale_is_null)
831
832 old_scale = BCG(bc_precision);
833
834 if (!new_scale_is_null) {
835 if (bcmath_check_scale(new_scale, 1) == FAILURE) {
837 }
838
839 zend_string *ini_name = ZSTR_INIT_LITERAL("bcmath.scale", 0);
840 zend_string *new_scale_str = zend_long_to_str(new_scale);
842 zend_string_release(new_scale_str);
843 zend_string_release(ini_name);
844 }
845
846 RETURN_LONG(old_scale);
847}
848/* }}} */
849
850
851
852static zend_class_entry *bcmath_number_ce;
853static zend_object_handlers bcmath_number_obj_handlers;
854
855static zend_result bcmath_number_do_operation(uint8_t opcode, zval *ret_val, zval *op1, zval *op2);
856static int bcmath_number_compare(zval *op1, zval *op2);
857
858#if SIZEOF_SIZE_T >= 8
859# define CHECK_RET_SCALE_OVERFLOW(scale, origin_scale) (scale > INT_MAX)
860#else
861# define CHECK_RET_SCALE_OVERFLOW(scale, origin_scale) (scale > INT_MAX || scale < origin_scale)
862#endif
863#define CHECK_SCALE_OVERFLOW(scale) (scale > INT_MAX)
864
865static zend_always_inline bcmath_number_obj_t *get_bcmath_number_from_obj(const zend_object *obj)
866{
867 return (bcmath_number_obj_t*)((char*)(obj) - XtOffsetOf(bcmath_number_obj_t, std));
868}
869
870static zend_always_inline bcmath_number_obj_t *get_bcmath_number_from_zval(const zval *zv)
871{
872 return get_bcmath_number_from_obj(Z_OBJ_P(zv));
873}
874
875static zend_always_inline zend_string *bcmath_number_value_to_str(bcmath_number_obj_t *intern)
876{
877 if (intern->value == NULL) {
878 intern->value = bc_num2str_ex(intern->num, intern->scale);
879 }
880 return intern->value;
881}
882
883static zend_object *bcmath_number_create(zend_class_entry *ce)
884{
885 bcmath_number_obj_t *intern = zend_object_alloc(sizeof(bcmath_number_obj_t), ce);
886
887 zend_object_std_init(&intern->std, ce);
888 object_properties_init(&intern->std, ce);
889
890 intern->scale = 1;
891
892 return &intern->std;
893}
894
895static void bcmath_number_free(zend_object *obj)
896{
897 bcmath_number_obj_t *intern = get_bcmath_number_from_obj(obj);
898 if (intern->num) {
899 bc_free_num(&intern->num);
900 intern->num = NULL;
901 }
902 if (intern->value) {
903 zend_string_release(intern->value);
904 intern->value = NULL;
905 }
906 zend_object_std_dtor(&intern->std);
907}
908
909static zend_object *bcmath_number_clone(zend_object *obj)
910{
911 bcmath_number_obj_t *original = get_bcmath_number_from_obj(obj);
912 bcmath_number_obj_t *clone = get_bcmath_number_from_obj(bcmath_number_create(bcmath_number_ce));
913
914 clone->num = bc_copy_num(original->num);
915 if (original->value) {
916 clone->value = zend_string_copy(original->value);
917 }
918 clone->scale = original->scale;
919
920 return &clone->std;
921}
922
923static HashTable *bcmath_number_get_properties_for(zend_object *obj, zend_prop_purpose purpose)
924{
925 zval zv;
926 bcmath_number_obj_t *intern = get_bcmath_number_from_obj(obj);
928
929 ZVAL_STR_COPY(&zv, bcmath_number_value_to_str(intern));
930 zend_hash_update(props, ZSTR_KNOWN(ZEND_STR_VALUE), &zv);
931 ZVAL_LONG(&zv, intern->scale);
932 zend_hash_str_update(props, ZEND_STRL("scale"), &zv);
933
934 return props;
935}
936
937static zval *bcmath_number_write_property(zend_object *obj, zend_string *name, zval *value, void **cache_slot)
938{
939 if (zend_string_equals(name, ZSTR_KNOWN(ZEND_STR_VALUE)) || zend_string_equals_literal(name, "scale")) {
941 return &EG(error_zval);
942 }
943
944 return zend_std_write_property(obj, name, value, cache_slot);
945}
946
947static void bcmath_number_unset_property(zend_object *obj, zend_string *name, void **cache_slot)
948{
949 if (zend_string_equals(name, ZSTR_KNOWN(ZEND_STR_VALUE)) || zend_string_equals_literal(name, "scale")) {
950 zend_throw_error(NULL, "Cannot unset readonly property %s::$%s", ZSTR_VAL(obj->ce->name), ZSTR_VAL(name));
951 return;
952 }
953
954 zend_std_unset_property(obj, name, cache_slot);
955}
956
957static zval *bcmath_number_read_property(zend_object *obj, zend_string *name, int type, void **cache_slot, zval *rv)
958{
959 bcmath_number_obj_t *intern = get_bcmath_number_from_obj(obj);
960
961 if (zend_string_equals(name, ZSTR_KNOWN(ZEND_STR_VALUE))) {
962 ZVAL_STR_COPY(rv, bcmath_number_value_to_str(intern));
963 return rv;
964 }
965
966 if (zend_string_equals_literal(name, "scale")) {
967 ZVAL_LONG(rv, intern->scale);
968 return rv;
969 }
970
971 return zend_std_read_property(obj, name, type, cache_slot, rv);
972}
973
974static int bcmath_number_has_property(zend_object *obj, zend_string *name, int check_empty, void **cache_slot)
975{
976 if (check_empty == ZEND_PROPERTY_NOT_EMPTY) {
977 bcmath_number_obj_t *intern = get_bcmath_number_from_obj(obj);
978
979 if (zend_string_equals(name, ZSTR_KNOWN(ZEND_STR_VALUE))) {
980 return !bc_is_zero(intern->num);
981 }
982
983 if (zend_string_equals_literal(name, "scale")) {
984 return intern->scale != 0;
985 }
986 }
987 return zend_string_equals(name, ZSTR_KNOWN(ZEND_STR_VALUE)) || zend_string_equals_literal(name, "scale");
988}
989
990static zend_result bcmath_number_cast_object(zend_object *obj, zval *ret, int type)
991{
992 if (type == _IS_BOOL) {
993 bcmath_number_obj_t *intern = get_bcmath_number_from_obj(obj);
994 ZVAL_BOOL(ret, !bc_is_zero(intern->num));
995 return SUCCESS;
996 }
997
999}
1000
1001static void bcmath_number_register_class(void)
1002{
1003 bcmath_number_ce = register_class_BcMath_Number(zend_ce_stringable);
1004 bcmath_number_ce->create_object = bcmath_number_create;
1005 bcmath_number_ce->default_object_handlers = &bcmath_number_obj_handlers;
1006
1007 memcpy(&bcmath_number_obj_handlers, &std_object_handlers, sizeof(zend_object_handlers));
1008 bcmath_number_obj_handlers.offset = XtOffsetOf(bcmath_number_obj_t, std);
1009 bcmath_number_obj_handlers.free_obj = bcmath_number_free;
1010 bcmath_number_obj_handlers.clone_obj = bcmath_number_clone;
1011 bcmath_number_obj_handlers.do_operation = bcmath_number_do_operation;
1012 bcmath_number_obj_handlers.compare = bcmath_number_compare;
1013 bcmath_number_obj_handlers.write_property = bcmath_number_write_property;
1014 bcmath_number_obj_handlers.unset_property = bcmath_number_unset_property;
1015 bcmath_number_obj_handlers.has_property = bcmath_number_has_property;
1016 bcmath_number_obj_handlers.read_property = bcmath_number_read_property;
1017 bcmath_number_obj_handlers.get_properties_for = bcmath_number_get_properties_for;
1018 bcmath_number_obj_handlers.cast_object = bcmath_number_cast_object;
1019}
1020
1021static zend_always_inline void bcmath_number_add_internal(
1022 bc_num n1, bc_num n2, bc_num *ret,
1023 size_t n1_full_scale, size_t n2_full_scale, size_t *scale, bool auto_scale
1024) {
1025 if (auto_scale) {
1026 *scale = MAX(n1_full_scale, n2_full_scale);
1027 }
1028 *ret = bc_add(n1, n2, *scale);
1029 (*ret)->n_scale = MIN(*scale, (*ret)->n_scale);
1031}
1032
1033static zend_always_inline void bcmath_number_sub_internal(
1034 bc_num n1, bc_num n2, bc_num *ret,
1035 size_t n1_full_scale, size_t n2_full_scale, size_t *scale, bool auto_scale
1036) {
1037 if (auto_scale) {
1038 *scale = MAX(n1_full_scale, n2_full_scale);
1039 }
1040 *ret = bc_sub(n1, n2, *scale);
1041 (*ret)->n_scale = MIN(*scale, (*ret)->n_scale);
1043}
1044
1045static zend_always_inline zend_result bcmath_number_mul_internal(
1046 bc_num n1, bc_num n2, bc_num *ret,
1047 size_t n1_full_scale, size_t n2_full_scale, size_t *scale, bool auto_scale
1048) {
1049 if (auto_scale) {
1050 *scale = n1_full_scale + n2_full_scale;
1051 if (UNEXPECTED(CHECK_RET_SCALE_OVERFLOW(*scale, n1_full_scale))) {
1052 zend_value_error("scale of the result is too large");
1053 return FAILURE;
1054 }
1055 }
1056 *ret = bc_multiply(n1, n2, *scale);
1057 (*ret)->n_scale = MIN(*scale, (*ret)->n_scale);
1059 return SUCCESS;
1060}
1061
1062static zend_always_inline zend_result bcmath_number_div_internal(
1063 bc_num n1, bc_num n2, bc_num *ret,
1064 size_t n1_full_scale, size_t *scale, bool auto_scale
1065) {
1066 if (auto_scale) {
1067 *scale = n1_full_scale + BC_MATH_NUMBER_EXPAND_SCALE;
1068 if (UNEXPECTED(CHECK_RET_SCALE_OVERFLOW(*scale, n1_full_scale))) {
1069 zend_value_error("scale of the result is too large");
1070 return FAILURE;
1071 }
1072 }
1073 if (!bc_divide(n1, n2, ret, *scale)) {
1075 return FAILURE;
1076 }
1078 if (auto_scale) {
1079 size_t diff = *scale - (*ret)->n_scale;
1081 }
1082 return SUCCESS;
1083}
1084
1085static zend_always_inline zend_result bcmath_number_mod_internal(
1086 bc_num n1, bc_num n2, bc_num *ret,
1087 size_t n1_full_scale, size_t n2_full_scale, size_t *scale, bool auto_scale
1088) {
1089 if (auto_scale) {
1090 *scale = MAX(n1_full_scale, n2_full_scale);
1091 }
1092 if (!bc_modulo(n1, n2, ret, *scale)) {
1094 return FAILURE;
1095 }
1097 return SUCCESS;
1098}
1099
1100static zend_result bcmath_number_pow_internal(
1101 bc_num n1, bc_num n2, bc_num *ret,
1102 size_t n1_full_scale, size_t *scale, bool auto_scale, bool is_op
1103) {
1104 /* Check the exponent for scale digits and convert to a long. */
1105 if (UNEXPECTED(n2->n_scale != 0)) {
1106 if (is_op) {
1107 zend_value_error("exponent cannot have a fractional part");
1108 } else {
1109 zend_argument_value_error(1, "exponent cannot have a fractional part");
1110 }
1111 return FAILURE;
1112 }
1113 long exponent = bc_num2long(n2);
1114
1115 bool scale_expand = false;
1116 if (auto_scale) {
1117 if (exponent > 0) {
1118 *scale = n1_full_scale * exponent;
1119 if (UNEXPECTED(*scale > INT_MAX || *scale < n1_full_scale)) {
1120 zend_value_error("scale of the result is too large");
1121 return FAILURE;
1122 }
1123 } else if (exponent < 0) {
1124 *scale = n1_full_scale + BC_MATH_NUMBER_EXPAND_SCALE;
1125 if (UNEXPECTED(CHECK_RET_SCALE_OVERFLOW(*scale, n1_full_scale))) {
1126 zend_value_error("scale of the result is too large");
1127 return FAILURE;
1128 }
1129 scale_expand = true;
1130 } else {
1131 *scale = 0;
1132 }
1133 }
1134
1139 if (UNEXPECTED(exponent == 0 && (n2->n_len > 1 || n2->n_value[0] != 0))) {
1140 if (is_op) {
1141 zend_value_error("exponent is too large");
1142 } else {
1143 zend_argument_value_error(1, "exponent is too large");
1144 }
1145 return FAILURE;
1146 }
1147 if (!bc_raise(n1, exponent, ret, *scale)) {
1148 zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Negative power of zero");
1149 return FAILURE;
1150 }
1152 if (scale_expand) {
1153 size_t diff = *scale - (*ret)->n_scale;
1155 }
1156 return SUCCESS;
1157}
1158
1159static zend_always_inline bcmath_number_obj_t *bcmath_number_new_obj(bc_num ret, size_t scale)
1160{
1161 bcmath_number_obj_t *intern = get_bcmath_number_from_obj(bcmath_number_create(bcmath_number_ce));
1162 intern->num = ret;
1163 intern->scale = scale;
1164 return intern;
1165}
1166
1167static zend_result bcmath_number_parse_num(zval *zv, zend_object **obj, zend_string **str, zend_long *lval)
1168{
1169 if (Z_TYPE_P(zv) == IS_OBJECT && instanceof_function(Z_OBJCE_P(zv), bcmath_number_ce)) {
1170 *obj = Z_OBJ_P(zv);
1171 return SUCCESS;
1172 } else {
1173 switch (Z_TYPE_P(zv)) {
1174 case IS_LONG:
1175 *lval = Z_LVAL_P(zv);
1176 return SUCCESS;
1177
1178 case IS_STRING:
1179 *str = Z_STR_P(zv);
1180 return SUCCESS;
1181
1182 case IS_NULL:
1183 *lval = 0;
1184 return FAILURE;
1185
1186 default:
1187 return zend_parse_arg_long_slow(zv, lval, 1 /* dummy */) ? SUCCESS : FAILURE;
1188 }
1189 }
1190}
1191
1192static zend_result bc_num_from_obj_or_str_or_long(
1193 bc_num *num, size_t *full_scale, const zend_object *obj, const zend_string *str, zend_long lval)
1194{
1195 if (obj) {
1196 bcmath_number_obj_t *intern = get_bcmath_number_from_obj(obj);
1197 *num = intern->num;
1198 if (full_scale) {
1199 *full_scale = intern->scale;
1200 }
1201 return SUCCESS;
1202 } else if (str) {
1203 return php_str2num_ex(num, str, full_scale);
1204 } else {
1205 php_long2num(num, lval);
1206 if (full_scale) {
1207 *full_scale = 0;
1208 }
1209 return SUCCESS;
1210 }
1211}
1212
1213static zend_result bcmath_number_do_operation(uint8_t opcode, zval *ret_val, zval *op1, zval *op2)
1214{
1215 switch (opcode) {
1216 case ZEND_ADD:
1217 case ZEND_SUB:
1218 case ZEND_MUL:
1219 case ZEND_DIV:
1220 case ZEND_MOD:
1221 case ZEND_POW:
1222 break;
1223 default:
1224 return FAILURE;
1225 }
1226
1227 zend_object *obj1 = NULL;
1228 zend_string *str1 = NULL;
1229 zend_long lval1 = 0;
1230
1231 zend_object *obj2 = NULL;
1232 zend_string *str2 = NULL;
1233 zend_long lval2 = 0;
1234
1235 if (UNEXPECTED(bcmath_number_parse_num(op1, &obj1, &str1, &lval1) == FAILURE || bcmath_number_parse_num(op2, &obj2, &str2, &lval2) == FAILURE)) {
1236 return FAILURE;
1237 }
1238
1239 bc_num n1 = NULL;
1240 bc_num n2 = NULL;
1241 size_t n1_full_scale;
1242 size_t n2_full_scale;
1243 if (UNEXPECTED(bc_num_from_obj_or_str_or_long(&n1, &n1_full_scale, obj1, str1, lval1) == FAILURE)) {
1244 zend_value_error("Left string operand cannot be converted to BcMath\\Number");
1245 goto fail;
1246 }
1247 if (UNEXPECTED(bc_num_from_obj_or_str_or_long(&n2, &n2_full_scale, obj2, str2, lval2) == FAILURE)) {
1248 zend_value_error("Right string operand cannot be converted to BcMath\\Number");
1249 goto fail;
1250 }
1251
1252 if (UNEXPECTED(CHECK_SCALE_OVERFLOW(n1_full_scale) || CHECK_SCALE_OVERFLOW(n2_full_scale))) {
1253 zend_value_error("scale must be between 0 and %d", INT_MAX);
1254 goto fail;
1255 }
1256
1257 bc_num ret = NULL;
1258 size_t scale;
1259 switch (opcode) {
1260 case ZEND_ADD:
1261 bcmath_number_add_internal(n1, n2, &ret, n1_full_scale, n2_full_scale, &scale, true);
1262 break;
1263 case ZEND_SUB:
1264 bcmath_number_sub_internal(n1, n2, &ret, n1_full_scale, n2_full_scale, &scale, true);
1265 break;
1266 case ZEND_MUL:
1267 if (UNEXPECTED(bcmath_number_mul_internal(n1, n2, &ret, n1_full_scale, n2_full_scale, &scale, true) == FAILURE)) {
1268 goto fail;
1269 }
1270 break;
1271 case ZEND_DIV:
1272 if (UNEXPECTED(bcmath_number_div_internal(n1, n2, &ret, n1_full_scale, &scale, true) == FAILURE)) {
1273 goto fail;
1274 }
1275 break;
1276 case ZEND_MOD:
1277 if (UNEXPECTED(bcmath_number_mod_internal(n1, n2, &ret, n1_full_scale, n2_full_scale, &scale, true) == FAILURE)) {
1278 goto fail;
1279 }
1280 break;
1281 case ZEND_POW:
1282 if (UNEXPECTED(bcmath_number_pow_internal(n1, n2, &ret, n1_full_scale, &scale, true, true) == FAILURE)) {
1283 goto fail;
1284 }
1285 break;
1287 }
1288
1289 if (Z_TYPE_P(op1) != IS_OBJECT) {
1290 bc_free_num(&n1);
1291 }
1292 if (Z_TYPE_P(op2) != IS_OBJECT) {
1293 bc_free_num(&n2);
1294 }
1295
1296 bcmath_number_obj_t *intern = bcmath_number_new_obj(ret, scale);
1297
1298 /* For increment and decrement, etc */
1299 if (ret_val == op1) {
1300 zval_ptr_dtor(ret_val);
1301 }
1302 ZVAL_OBJ(ret_val, &intern->std);
1303
1304 return SUCCESS;
1305
1306fail:
1307 if (Z_TYPE_P(op1) != IS_OBJECT) {
1308 bc_free_num(&n1);
1309 }
1310 if (Z_TYPE_P(op2) != IS_OBJECT) {
1311 bc_free_num(&n2);
1312 }
1313 return FAILURE;
1314}
1315
1316static int bcmath_number_compare(zval *op1, zval *op2)
1317{
1318 zend_object *obj1 = NULL;
1319 zend_string *str1 = NULL;
1320 zend_long lval1 = 0;
1321
1322 zend_object *obj2 = NULL;
1323 zend_string *str2 = NULL;
1324 zend_long lval2 = 0;
1325
1326 bc_num n1 = NULL;
1327 bc_num n2 = NULL;
1328
1329 int ret = ZEND_UNCOMPARABLE;
1330
1331 if (UNEXPECTED(bcmath_number_parse_num(op1, &obj1, &str1, &lval1) == FAILURE)) {
1332 goto failure;
1333 }
1334
1335 if (UNEXPECTED(bcmath_number_parse_num(op2, &obj2, &str2, &lval2) == FAILURE)) {
1336 goto failure;
1337 }
1338
1339 size_t n1_full_scale;
1340 size_t n2_full_scale;
1341 if (UNEXPECTED(bc_num_from_obj_or_str_or_long(&n1, &n1_full_scale, obj1, str1, lval1) == FAILURE ||
1342 bc_num_from_obj_or_str_or_long(&n2, &n2_full_scale, obj2, str2, lval2) == FAILURE)) {
1343 goto failure;
1344 }
1345
1346 if (UNEXPECTED(CHECK_SCALE_OVERFLOW(n1_full_scale) || CHECK_SCALE_OVERFLOW(n2_full_scale))) {
1347 zend_value_error("scale must be between 0 and %d", INT_MAX);
1348 goto failure;
1349 }
1350
1351 ret = bc_compare(n1, n2, MAX(n1->n_scale, n2->n_scale));
1352
1353failure:
1354 if (Z_TYPE_P(op1) != IS_OBJECT) {
1355 bc_free_num(&n1);
1356 }
1357 if (Z_TYPE_P(op2) != IS_OBJECT) {
1358 bc_free_num(&n2);
1359 }
1360
1361 return ret;
1362}
1363
1364#define BCMATH_PARAM_NUMBER_OR_STR_OR_LONG(dest_obj, ce, dest_str, dest_long) \
1365 Z_PARAM_PROLOGUE(0, 0); \
1366 if (UNEXPECTED(!(zend_parse_arg_obj(_arg, &(dest_obj), ce, 0) || \
1367 zend_parse_arg_str_or_long(_arg, &(dest_str), &(dest_long), &_dummy, 0, _i)))) { \
1368 zend_argument_type_error(_i, "must be of type int, string, or %s, %s given", \
1369 ZSTR_VAL(bcmath_number_ce->name), zend_zval_value_name(_arg)); \
1370 _error_code = ZPP_ERROR_FAILURE; \
1371 break; \
1372 }
1373
1374static zend_always_inline zend_result bc_num_from_obj_or_str_or_long_with_err(
1375 bc_num *num, size_t *scale, zend_object *obj, zend_string *str, zend_long lval, uint32_t arg_num)
1376{
1377 size_t full_scale = 0;
1378 if (UNEXPECTED(bc_num_from_obj_or_str_or_long(num, &full_scale, obj, str, lval) == FAILURE)) {
1379 zend_argument_value_error(arg_num, "is not well-formed");
1380 return FAILURE;
1381 }
1382 if (UNEXPECTED(CHECK_SCALE_OVERFLOW(full_scale))) {
1383 zend_argument_value_error(arg_num, "must be between 0 and %d", INT_MAX);
1384 return FAILURE;
1385 }
1386 if (scale != NULL) {
1387 *scale = full_scale;
1388 }
1389 return SUCCESS;
1390}
1391
1392PHP_METHOD(BcMath_Number, __construct)
1393{
1394 zend_string *str = NULL;
1395 zend_long lval = 0;
1396
1398 Z_PARAM_STR_OR_LONG(str, lval);
1400
1401 bcmath_number_obj_t *intern = get_bcmath_number_from_zval(ZEND_THIS);
1402 if (UNEXPECTED(intern->num != NULL)) {
1403 zend_readonly_property_modification_error_ex(ZSTR_VAL(bcmath_number_ce->name), "value");
1404 RETURN_THROWS();
1405 }
1406
1407 bc_num num = NULL;
1408 size_t scale = 0;
1409 if (bc_num_from_obj_or_str_or_long_with_err(&num, &scale, NULL, str, lval, 1) == FAILURE) {
1410 bc_free_num(&num);
1411 RETURN_THROWS();
1412 }
1413
1414 intern->num = num;
1415 intern->scale = scale;
1416}
1417
1418static void bcmath_number_calc_method(INTERNAL_FUNCTION_PARAMETERS, uint8_t opcode)
1419{
1420 zend_object *num_obj = NULL;
1421 zend_string *num_str = NULL;
1422 zend_long num_lval = 0;
1423 zend_long scale_lval = 0;
1424 bool scale_is_null = true;
1425
1427 BCMATH_PARAM_NUMBER_OR_STR_OR_LONG(num_obj, bcmath_number_ce, num_str, num_lval);
1429 Z_PARAM_LONG_OR_NULL(scale_lval, scale_is_null);
1431
1432 bc_num num = NULL;
1433 size_t num_full_scale = 0;
1434 if (bc_num_from_obj_or_str_or_long_with_err(&num, &num_full_scale, num_obj, num_str, num_lval, 1) == FAILURE) {
1435 goto fail;
1436 }
1437 if (bcmath_check_scale(scale_lval, 2) == FAILURE) {
1438 goto fail;
1439 }
1440
1441 bc_num ret = NULL;
1442 size_t scale = scale_lval;
1443 bcmath_number_obj_t *intern = get_bcmath_number_from_zval(ZEND_THIS);
1444
1445 switch (opcode) {
1446 case ZEND_ADD:
1447 bcmath_number_add_internal(intern->num, num, &ret, intern->scale, num_full_scale, &scale, scale_is_null);
1448 break;
1449 case ZEND_SUB:
1450 bcmath_number_sub_internal(intern->num, num, &ret, intern->scale, num_full_scale, &scale, scale_is_null);
1451 break;
1452 case ZEND_MUL:
1453 if (UNEXPECTED(bcmath_number_mul_internal(intern->num, num, &ret, intern->scale, num_full_scale, &scale, scale_is_null) == FAILURE)) {
1454 goto fail;
1455 }
1456 break;
1457 case ZEND_DIV:
1458 if (UNEXPECTED(bcmath_number_div_internal(intern->num, num, &ret, intern->scale, &scale, scale_is_null) == FAILURE)) {
1459 goto fail;
1460 }
1461 break;
1462 case ZEND_MOD:
1463 if (UNEXPECTED(bcmath_number_mod_internal(intern->num, num, &ret, intern->scale, num_full_scale, &scale, scale_is_null) == FAILURE)) {
1464 goto fail;
1465 }
1466 break;
1467 case ZEND_POW:
1468 if (UNEXPECTED(bcmath_number_pow_internal(intern->num, num, &ret, intern->scale, &scale, scale_is_null, false) == FAILURE)) {
1469 goto fail;
1470 }
1471 break;
1473 }
1474
1475 if (num_obj == NULL) {
1476 bc_free_num(&num);
1477 }
1478
1479 bcmath_number_obj_t *new_intern = bcmath_number_new_obj(ret, scale);
1480 RETURN_OBJ(&new_intern->std);
1481
1482fail:
1483 if (num_obj == NULL) {
1484 bc_free_num(&num);
1485 }
1486 RETURN_THROWS();
1487}
1488
1489PHP_METHOD(BcMath_Number, add)
1490{
1491 bcmath_number_calc_method(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ADD);
1492}
1493
1494PHP_METHOD(BcMath_Number, sub)
1495{
1496 bcmath_number_calc_method(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_SUB);
1497}
1498
1499PHP_METHOD(BcMath_Number, mul)
1500{
1501 bcmath_number_calc_method(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_MUL);
1502}
1503
1504PHP_METHOD(BcMath_Number, div)
1505{
1506 bcmath_number_calc_method(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_DIV);
1507}
1508
1509PHP_METHOD(BcMath_Number, mod)
1510{
1511 bcmath_number_calc_method(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_MOD);
1512}
1513
1514PHP_METHOD(BcMath_Number, pow)
1515{
1516 bcmath_number_calc_method(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_POW);
1517}
1518
1519PHP_METHOD(BcMath_Number, divmod)
1520{
1521 zend_object *num_obj = NULL;
1522 zend_string *num_str = NULL;
1523 zend_long num_lval = 0;
1524 zend_long scale_lval = 0;
1525 bool scale_is_null = true;
1526
1528 BCMATH_PARAM_NUMBER_OR_STR_OR_LONG(num_obj, bcmath_number_ce, num_str, num_lval);
1530 Z_PARAM_LONG_OR_NULL(scale_lval, scale_is_null);
1532
1533 bc_num num = NULL;
1534 size_t num_full_scale;
1535 if (bc_num_from_obj_or_str_or_long_with_err(&num, &num_full_scale, num_obj, num_str, num_lval, 1) == FAILURE) {
1536 goto fail;
1537 }
1538 if (bcmath_check_scale(scale_lval, 2) == FAILURE) {
1539 goto fail;
1540 }
1541
1542 bc_num quot = NULL;
1543 bc_num rem = NULL;
1544 size_t scale = scale_lval;
1545 bcmath_number_obj_t *intern = get_bcmath_number_from_zval(ZEND_THIS);
1546
1547 if (scale_is_null) {
1548 scale = MAX(intern->scale, num_full_scale);
1549 }
1550
1551 if (!bc_divmod(intern->num, num, &quot, &rem, scale)) {
1553 goto fail;
1554 }
1557
1558 if (num_obj == NULL) {
1559 bc_free_num(&num);
1560 }
1561
1562 bcmath_number_obj_t *quot_intern = bcmath_number_new_obj(quot, 0);
1563 bcmath_number_obj_t *rem_intern = bcmath_number_new_obj(rem, scale);
1564
1565 zval z_quot, z_rem;
1566 ZVAL_OBJ(&z_quot, &quot_intern->std);
1567 ZVAL_OBJ(&z_rem, &rem_intern->std);
1568
1569 RETURN_ARR(zend_new_pair(&z_quot, &z_rem));
1570
1571fail:
1572 if (num_obj == NULL) {
1573 bc_free_num(&num);
1574 }
1575 RETURN_THROWS();
1576}
1577
1578PHP_METHOD(BcMath_Number, powmod)
1579{
1580 zend_object *exponent_obj = NULL;
1581 zend_string *exponent_str = NULL;
1582 zend_long exponent_lval = 0;
1583
1584 zend_object *modulus_obj = NULL;
1585 zend_string *modulus_str = NULL;
1586 zend_long modulus_lval = 0;
1587
1588 zend_long scale_lval = 0;
1589 bool scale_is_null = true;
1590
1592 BCMATH_PARAM_NUMBER_OR_STR_OR_LONG(exponent_obj, bcmath_number_ce, exponent_str, exponent_lval);
1593 BCMATH_PARAM_NUMBER_OR_STR_OR_LONG(modulus_obj, bcmath_number_ce, modulus_str, modulus_lval);
1595 Z_PARAM_LONG_OR_NULL(scale_lval, scale_is_null);
1597
1598 bc_num exponent_num = NULL;
1599 bc_num modulus_num = NULL;
1600 if (bc_num_from_obj_or_str_or_long_with_err(&exponent_num, NULL, exponent_obj, exponent_str, exponent_lval, 1) == FAILURE) {
1601 goto cleanup;
1602 }
1603 if (bc_num_from_obj_or_str_or_long_with_err(&modulus_num, NULL, modulus_obj, modulus_str, modulus_lval, 2) == FAILURE) {
1604 goto cleanup;
1605 }
1606 if (bcmath_check_scale(scale_lval, 3) == FAILURE) {
1607 goto cleanup;
1608 }
1609
1610 bcmath_number_obj_t *intern = get_bcmath_number_from_zval(ZEND_THIS);
1611 bc_num ret = NULL;
1612 size_t scale = scale_lval;
1613 raise_mod_status status = bc_raisemod(intern->num, exponent_num, modulus_num, &ret, scale);
1614 switch (status) {
1616 zend_value_error("Base number cannot have a fractional part");
1617 goto cleanup;
1619 zend_argument_value_error(1, "cannot have a fractional part");
1620 goto cleanup;
1621 case EXPO_IS_NEGATIVE:
1622 zend_argument_value_error(1, "must be greater than or equal to 0");
1623 goto cleanup;
1624 case MOD_HAS_FRACTIONAL:
1625 zend_argument_value_error(2, "cannot have a fractional part");
1626 goto cleanup;
1627 case MOD_IS_ZERO:
1629 goto cleanup;
1630 case OK:
1631 break;
1633 }
1634
1636
1637 if (exponent_obj == NULL) {
1638 bc_free_num(&exponent_num);
1639 }
1640 if (modulus_obj == NULL) {
1641 bc_free_num(&modulus_num);
1642 }
1643
1644 bcmath_number_obj_t *new_intern = bcmath_number_new_obj(ret, scale);
1645 RETURN_OBJ(&new_intern->std);
1646
1647cleanup:
1648 if (exponent_obj == NULL) {
1649 bc_free_num(&exponent_num);
1650 }
1651 if (modulus_obj == NULL) {
1652 bc_free_num(&modulus_num);
1653 }
1654 RETURN_THROWS();
1655}
1656
1657PHP_METHOD(BcMath_Number, sqrt)
1658{
1659 zend_long scale_lval = 0;
1660 bool scale_is_null = true;
1661
1664 Z_PARAM_LONG_OR_NULL(scale_lval, scale_is_null);
1666
1667 if (bcmath_check_scale(scale_lval, 1) == FAILURE) {
1668 RETURN_THROWS();
1669 }
1670
1671 bcmath_number_obj_t *intern = get_bcmath_number_from_zval(ZEND_THIS);
1672
1673 size_t scale;
1674 if (scale_is_null) {
1675 scale = intern->scale + BC_MATH_NUMBER_EXPAND_SCALE;
1676 if (UNEXPECTED(CHECK_RET_SCALE_OVERFLOW(scale, intern->scale))) {
1677 zend_value_error("scale of the result is too large");
1678 RETURN_THROWS();
1679 }
1680 } else {
1681 scale = scale_lval;
1682 }
1683
1684 bc_num ret = bc_copy_num(intern->num);
1685 if (!bc_sqrt (&ret, scale)) {
1686 zend_value_error("Base number must be greater than or equal to 0");
1687 bc_free_num(&ret);
1688 RETURN_THROWS();
1689 }
1690
1691 ret->n_scale = MIN(scale, ret->n_scale);
1693 if (scale_is_null) {
1694 size_t diff = scale - ret->n_scale;
1696 }
1697
1698 bcmath_number_obj_t *new_intern = bcmath_number_new_obj(ret, scale);
1699 RETURN_OBJ(&new_intern->std);
1700}
1701
1702PHP_METHOD(BcMath_Number, compare)
1703{
1704 zend_object *num_obj = NULL;
1705 zend_string *num_str = NULL;
1706 zend_long num_lval = 0;
1707 zend_long scale_lval = 0;
1708 bool scale_is_null = true;
1709
1711 BCMATH_PARAM_NUMBER_OR_STR_OR_LONG(num_obj, bcmath_number_ce, num_str, num_lval);
1713 Z_PARAM_LONG_OR_NULL(scale_lval, scale_is_null);
1715
1716 bc_num num = NULL;
1717 size_t num_full_scale = 0;
1718 if (bc_num_from_obj_or_str_or_long_with_err(&num, &num_full_scale, num_obj, num_str, num_lval, 1) == FAILURE) {
1719 goto fail;
1720 }
1721 if (bcmath_check_scale(scale_lval, 2) == FAILURE) {
1722 goto fail;
1723 }
1724
1725 size_t scale;
1726 bcmath_number_obj_t *intern = get_bcmath_number_from_zval(ZEND_THIS);
1727 if (scale_is_null) {
1728 scale = MAX(intern->num->n_scale, num->n_scale);
1729 } else {
1730 scale = scale_lval;
1731 }
1732 zend_long ret = bc_compare(intern->num, num, scale);
1733
1734 if (num_obj == NULL) {
1735 bc_free_num(&num);
1736 }
1738
1739fail:
1740 if (num_obj == NULL) {
1741 bc_free_num(&num);
1742 }
1743 RETURN_THROWS();
1744}
1745
1746static void bcmath_number_floor_or_ceil(INTERNAL_FUNCTION_PARAMETERS, bool is_floor)
1747{
1749
1750 bcmath_number_obj_t *intern = get_bcmath_number_from_zval(ZEND_THIS);
1751
1752 bc_num ret = bc_floor_or_ceil(intern->num, is_floor);
1753
1754 bcmath_number_obj_t *new_intern = bcmath_number_new_obj(ret, 0);
1755 RETURN_OBJ(&new_intern->std);
1756}
1757
1758PHP_METHOD(BcMath_Number, floor)
1759{
1760 bcmath_number_floor_or_ceil(INTERNAL_FUNCTION_PARAM_PASSTHRU, true);
1761}
1762
1763PHP_METHOD(BcMath_Number, ceil)
1764{
1765 bcmath_number_floor_or_ceil(INTERNAL_FUNCTION_PARAM_PASSTHRU, false);
1766}
1767
1768PHP_METHOD(BcMath_Number, round)
1769{
1770 zend_long precision = 0;
1771 zend_long rounding_mode = PHP_ROUND_HALF_UP;
1772 zend_object *mode_object = NULL;
1773
1776 Z_PARAM_LONG(precision);
1779
1780 if (mode_object != NULL) {
1781 rounding_mode = php_math_round_mode_from_enum(mode_object);
1782 }
1783
1784 switch (rounding_mode) {
1785 case PHP_ROUND_HALF_UP:
1788 case PHP_ROUND_HALF_ODD:
1789 case PHP_ROUND_CEILING:
1790 case PHP_ROUND_FLOOR:
1793 break;
1794 default:
1795 zend_argument_value_error(2, "is an unsupported rounding mode");
1796 RETURN_THROWS();
1797 }
1798
1799 bcmath_number_obj_t *intern = get_bcmath_number_from_zval(ZEND_THIS);
1800
1801 bc_num ret = NULL;
1802 bc_round(intern->num, precision, rounding_mode, &ret);
1803
1804 bcmath_number_obj_t *new_intern = bcmath_number_new_obj(ret, ret->n_scale);
1805 RETURN_OBJ(&new_intern->std);
1806}
1807
1808PHP_METHOD(BcMath_Number, __toString)
1809{
1811 bcmath_number_obj_t *intern = get_bcmath_number_from_zval(ZEND_THIS);
1812 RETURN_STR_COPY(bcmath_number_value_to_str(intern));
1813}
1814
1815PHP_METHOD(BcMath_Number, __serialize)
1816{
1818
1819 bcmath_number_obj_t *intern = get_bcmath_number_from_zval(ZEND_THIS);
1820
1823
1824 zval zv;
1825 ZVAL_STR_COPY(&zv, bcmath_number_value_to_str(intern));
1826 zend_hash_update(props, ZSTR_KNOWN(ZEND_STR_VALUE), &zv);
1827}
1828
1829PHP_METHOD(BcMath_Number, __unserialize)
1830{
1831 HashTable *props;
1832
1834 Z_PARAM_ARRAY_HT(props)
1836
1837 zval *zv = zend_hash_find(props, ZSTR_KNOWN(ZEND_STR_VALUE));
1838 if (!zv || Z_TYPE_P(zv) != IS_STRING || Z_STRLEN_P(zv) == 0) {
1839 goto fail;
1840 }
1841
1842 bcmath_number_obj_t *intern = get_bcmath_number_from_zval(ZEND_THIS);
1843 if (UNEXPECTED(intern->num != NULL)) {
1844 zend_readonly_property_modification_error_ex(ZSTR_VAL(bcmath_number_ce->name), "value");
1845 RETURN_THROWS();
1846 }
1847
1848 bc_num num = NULL;
1849 size_t scale = 0;
1850 if (php_str2num_ex(&num, Z_STR_P(zv), &scale) == FAILURE || CHECK_SCALE_OVERFLOW(scale)) {
1851 bc_free_num(&num);
1852 goto fail;
1853 }
1854
1855 intern->num = num;
1856 intern->scale = scale;
1857
1858 return;
1859
1860fail:
1861 zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(bcmath_number_ce->name));
1862 RETURN_THROWS();
1863}
1864
1865#endif
bc_num bc_add(bc_num n1, bc_num n2, size_t scale_min)
Definition add.c:42
rounding_mode_ce
floor(int|float $num)
sqrt(float $num)
pow(mixed $num, mixed $exponent)
ceil(int|float $num)
bool bc_str2num(bc_num *num, const char *str, const char *end, size_t scale, size_t *full_scale, bool auto_scale)
Definition str2num.c:109
bool bc_modulo(bc_num num1, bc_num num2, bc_num *resul, size_t scale)
Definition divmod.c:86
void bc_rm_trailing_zeros(bc_num num)
Definition rmzero.c:48
void bc_init_num(bc_num *num)
Definition init.c:108
bool bc_sqrt(bc_num *num, size_t scale)
Definition sqrt.c:39
long bc_num2long(bc_num num)
Definition num2long.c:40
bc_num bc_multiply(bc_num n1, bc_num n2, size_t scale)
Definition recmul.c:243
bc_num bc_long2num(zend_long lval)
Definition long2num.c:23
raise_mod_status
Definition bcmath.h:167
@ MOD_HAS_FRACTIONAL
Definition bcmath.h:172
@ OK
Definition bcmath.h:168
@ BASE_HAS_FRACTIONAL
Definition bcmath.h:169
@ EXPO_HAS_FRACTIONAL
Definition bcmath.h:170
@ EXPO_IS_NEGATIVE
Definition bcmath.h:171
@ MOD_IS_ZERO
Definition bcmath.h:173
bool bc_divmod(bc_num num1, bc_num num2, bc_num *quo, bc_num *rem, size_t scale)
Definition divmod.c:44
bool bc_is_zero(bc_num num)
Definition zero.c:58
bool bc_divide(bc_num n1, bc_num n2, bc_num *quot, size_t scale)
Definition div.c:331
struct bc_struct * bc_num
Definition bcmath.h:39
bc_num bc_floor_or_ceil(bc_num num, bool is_floor)
void bc_force_free_number(bc_num *num)
Definition init.c:100
#define bc_free_num(num)
Definition bcmath.h:187
bc_num bc_sub(bc_num n1, bc_num n2, size_t scale_min)
Definition sub.c:42
void bc_round(bc_num num, zend_long places, zend_long mode, bc_num *result)
Definition round.c:21
void bc_init_numbers(void)
Definition init.c:91
raise_mod_status bc_raisemod(bc_num base, bc_num exponent, bc_num mod, bc_num *result, size_t scale)
Definition raisemod.c:37
bool bc_raise(bc_num base, long exponent, bc_num *result, size_t scale)
Definition raise.c:46
bcmath_compare_result bc_compare(bc_num n1, bc_num n2, size_t scale)
Definition compare.c:154
zend_string * bc_num2str_ex(bc_num num, size_t scale)
Definition num2str.c:37
bccomp(string $num1, string $num2, ?int $scale=null)
bcfloor(string $num)
bcpowmod(string $num, string $exponent, string $modulus, ?int $scale=null)
bcsub(string $num1, string $num2, ?int $scale=null)
bcadd(string $num1, string $num2, ?int $scale=null)
bcdivmod(string $num1, string $num2, ?int $scale=null)
bcpow(string $num, string $exponent, ?int $scale=null)
bcceil(string $num)
bcround(string $num, int $precision=0, RoundingMode $mode=RoundingMode::HalfAwayFromZero)
bcsqrt(string $num, ?int $scale=null)
bcmod(string $num1, string $num2, ?int $scale=null)
bcdiv(string $num1, string $num2, ?int $scale=null)
bcmul(string $num1, string $num2, ?int $scale=null)
bcscale(?int $scale=null)
DNS_STATUS status
Definition dns_win32.c:49
zend_ffi_type * type
Definition ffi.c:3812
zval * zv
Definition ffi.c:3975
memcpy(ptr1, ptr2, size)
char * mode
#define NULL
Definition gdcache.h:45
#define round(tables, k1, k2)
Definition hash_gost.c:26
#define SUCCESS
Definition hash_sha3.c:261
foreach($dp as $el) foreach( $dp as $el) if( $pass2< 2) echo ""
PHPAPI int php_math_round_mode_from_enum(zend_object *mode)
Definition math.c:307
lu_byte right
Definition minilua.c:4267
lu_byte left
Definition minilua.c:4266
php_info_print_table_start()
Definition info.c:1064
php_info_print_table_row(2, "PDO Driver for Firebird", "enabled")
php_info_print_table_end()
Definition info.c:1074
#define PHP_GINIT
Definition php.h:397
#define PHP_FUNCTION
Definition php.h:364
#define PHP_MSHUTDOWN_FUNCTION
Definition php.h:401
#define PHP_MINFO
Definition php.h:396
#define PHP_MINIT_FUNCTION
Definition php.h:400
#define PHP_MSHUTDOWN
Definition php.h:393
#define PHP_MINFO_FUNCTION
Definition php.h:404
#define PHP_GINIT_FUNCTION
Definition php.h:405
#define INT_MAX
Definition php.h:237
#define PHP_GSHUTDOWN_FUNCTION
Definition php.h:406
#define PHP_MINIT
Definition php.h:392
#define PHP_METHOD
Definition php.h:365
#define PHP_MODULE_GLOBALS
Definition php.h:408
#define PHP_GSHUTDOWN
Definition php.h:398
zend_module_entry bcmath_module_entry
int bc_precision
Definition php_bcmath.h:36
#define BCG(v)
Definition php_bcmath.h:46
struct _bcmath_number_obj_t bcmath_number_obj_t
#define BC_MATH_NUMBER_EXPAND_SCALE
Definition php_bcmath.h:49
#define PHP_BCMATH_VERSION
Definition php_bcmath.h:28
#define add(i, ts)
#define PHP_INI_STAGE_RUNTIME
Definition php_ini.h:75
#define PHP_INI_ALL
Definition php_ini.h:45
#define PHP_INI_USER
Definition php_ini.h:41
#define PHP_INI_BEGIN
Definition php_ini.h:52
#define STD_PHP_INI_ENTRY
Definition php_ini.h:64
#define PHP_INI_END
Definition php_ini.h:53
#define PHP_ROUND_TOWARD_ZERO
#define PHP_ROUND_HALF_UP
#define PHP_ROUND_HALF_DOWN
#define PHP_ROUND_FLOOR
#define PHP_ROUND_HALF_EVEN
#define PHP_ROUND_AWAY_FROM_ZERO
#define PHP_ROUND_HALF_ODD
#define PHP_ROUND_CEILING
bool fail
Definition session.c:1065
zval rv
Definition session.c:1024
p
Definition session.c:1105
zend_string * value
Definition php_bcmath.h:52
zend_object *(* create_object)(zend_class_entry *class_type)
Definition zend.h:195
zend_string * name
Definition zend.h:149
const zend_object_handlers * default_object_handlers
Definition zend.h:186
zend_object_write_property_t write_property
zend_object_compare_t compare
zend_object_unset_property_t unset_property
zend_object_free_obj_t free_obj
zend_object_do_operation_t do_operation
zend_object_read_property_t read_property
zend_object_cast_t cast_object
zend_object_has_property_t has_property
zend_object_get_properties_for_t get_properties_for
zend_object_clone_obj_t clone_obj
zend_class_entry * ce
Definition zend_types.h:560
size_t n_len
Definition bcmath.h:42
size_t n_scale
Definition bcmath.h:43
char * n_value
Definition bcmath.h:44
ZEND_API ZEND_COLD void zend_throw_error(zend_class_entry *exception_ce, const char *format,...)
Definition zend.c:1772
ZEND_API ZEND_COLD void zend_value_error(const char *format,...)
Definition zend.c:1849
#define ZEND_TSRMLS_CACHE_UPDATE()
Definition zend.h:69
#define INTERNAL_FUNCTION_PARAMETERS
Definition zend.h:49
#define ZEND_TSRMLS_CACHE_DEFINE()
Definition zend.h:68
#define INTERNAL_FUNCTION_PARAM_PASSTHRU
Definition zend.h:50
ZEND_API bool ZEND_FASTCALL zend_parse_arg_long_slow(const zval *arg, zend_long *dest, uint32_t arg_num)
Definition zend_API.c:627
ZEND_API void object_properties_init(zend_object *object, zend_class_entry *class_type)
Definition zend_API.c:1688
ZEND_API ZEND_COLD void zend_argument_value_error(uint32_t arg_num, const char *format,...)
Definition zend_API.c:433
#define RETURN_OBJ(r)
Definition zend_API.h:1052
#define ZEND_PARSE_PARAMETERS_END()
Definition zend_API.h:1641
#define ZEND_PARSE_PARAMETERS_NONE()
Definition zend_API.h:1623
#define ZEND_DECLARE_MODULE_GLOBALS(module_name)
Definition zend_API.h:268
#define RETVAL_NEW_STR(s)
Definition zend_API.h:1015
#define RETURN_ARR(r)
Definition zend_API.h:1050
#define Z_PARAM_OPTIONAL
Definition zend_API.h:1667
#define ZEND_GET_MODULE(name)
Definition zend_API.h:241
#define RETVAL_ARR(r)
Definition zend_API.h:1024
#define Z_PARAM_STR(dest)
Definition zend_API.h:2086
#define ZEND_PARSE_PARAMETERS_START(min_num_args, max_num_args)
Definition zend_API.h:1620
#define Z_PARAM_LONG(dest)
Definition zend_API.h:1896
#define RETURN_LONG(l)
Definition zend_API.h:1037
#define RETURN_THROWS()
Definition zend_API.h:1060
#define Z_PARAM_ARRAY_HT(dest)
Definition zend_API.h:1852
#define Z_PARAM_OBJ_OF_CLASS(dest, _ce)
Definition zend_API.h:1997
#define ZEND_THIS
Definition zend_API.h:523
#define Z_PARAM_LONG_OR_NULL(dest, is_null)
Definition zend_API.h:1899
#define Z_PARAM_STR_OR_LONG(dest_str, dest_long)
Definition zend_API.h:2165
#define RETVAL_LONG(l)
Definition zend_API.h:1011
#define RETURN_STR_COPY(s)
Definition zend_API.h:1042
#define array_init(arg)
Definition zend_API.h:537
struct _zval_struct zval
ZEND_API zend_class_entry * zend_ce_division_by_zero_error
ZEND_API ZEND_COLD zend_object * zend_throw_exception_ex(zend_class_entry *exception_ce, zend_long code, const char *format,...)
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_readonly_property_modification_error_ex(const char *class_name, const char *prop_name)
#define EG(v)
ZEND_API zval *ZEND_FASTCALL zend_hash_str_update(HashTable *ht, const char *str, size_t len, zval *pData)
Definition zend_hash.c:1031
ZEND_API HashTable *ZEND_FASTCALL zend_new_pair(zval *val1, zval *val2)
Definition zend_hash.c:296
ZEND_API HashTable *ZEND_FASTCALL zend_array_dup(HashTable *source)
Definition zend_hash.c:2438
ZEND_API zval *ZEND_FASTCALL zend_hash_update(HashTable *ht, zend_string *key, zval *pData)
Definition zend_hash.c:997
ZEND_API zval *ZEND_FASTCALL zend_hash_find(const HashTable *ht, zend_string *key)
Definition zend_hash.c:2668
ZEND_API zend_long zend_ini_parse_quantity_warn(zend_string *value, zend_string *setting)
Definition zend_ini.c:869
ZEND_API zend_result zend_alter_ini_entry(zend_string *name, zend_string *new_value, int modify_type, int stage)
Definition zend_ini.c:325
#define UNREGISTER_INI_ENTRIES()
Definition zend_ini.h:204
#define REGISTER_INI_ENTRIES()
Definition zend_ini.h:203
#define DISPLAY_INI_ENTRIES()
Definition zend_ini.h:205
#define ZEND_INI_MH(name)
Definition zend_ini.h:30
#define ZEND_INI_GET_ADDR()
Definition zend_ini.h:259
ZEND_API zend_class_entry * zend_ce_stringable
int32_t zend_long
Definition zend_long.h:42
struct _zend_string zend_string
#define STANDARD_MODULE_HEADER
struct _zend_module_entry zend_module_entry
#define STANDARD_MODULE_PROPERTIES_EX
ZEND_API zend_result zend_std_cast_object_tostring(zend_object *readobj, zval *writeobj, int type)
ZEND_API HashTable * zend_std_get_properties(zend_object *zobj)
ZEND_API const zend_object_handlers std_object_handlers
ZEND_API zval * zend_std_write_property(zend_object *zobj, zend_string *name, zval *value, void **cache_slot)
ZEND_API void zend_std_unset_property(zend_object *zobj, zend_string *name, void **cache_slot)
ZEND_API zval * zend_std_read_property(zend_object *zobj, zend_string *name, int type, void **cache_slot, zval *rv)
enum _zend_prop_purpose zend_prop_purpose
#define ZEND_PROPERTY_NOT_EMPTY
ZEND_API void ZEND_FASTCALL zend_object_std_init(zend_object *object, zend_class_entry *ce)
ZEND_API void zend_object_std_dtor(zend_object *object)
ZEND_API zend_string *ZEND_FASTCALL zend_long_to_str(zend_long num)
#define ZEND_UNCOMPARABLE
#define MIN(a, b)
#define zend_always_inline
#define XtOffsetOf(s_type, field)
#define ZEND_STRL(str)
#define EMPTY_SWITCH_DEFAULT_CASE()
#define UNEXPECTED(condition)
#define MAX(a, b)
struct _zend_class_entry zend_class_entry
struct _zend_object zend_object
#define ZSTR_VAL(zstr)
Definition zend_string.h:68
#define ZSTR_INIT_LITERAL(s, persistent)
#define ZSTR_KNOWN(idx)
#define zend_string_equals_literal(str, literal)
#define ZSTR_LEN(zstr)
Definition zend_string.h:69
#define Z_TYPE_P(zval_p)
Definition zend_types.h:660
#define ZVAL_STR(z, s)
#define Z_ARRVAL_P(zval_p)
Definition zend_types.h:987
#define ZVAL_LONG(z, l)
#define IS_STRING
Definition zend_types.h:606
#define ZVAL_STR_COPY(z, s)
struct _zend_array HashTable
Definition zend_types.h:386
#define Z_OBJ_P(zval_p)
Definition zend_types.h:990
#define Z_STR_P(zval_p)
Definition zend_types.h:972
#define Z_STRLEN_P(zval_p)
Definition zend_types.h:978
#define IS_NULL
Definition zend_types.h:601
#define Z_OBJCE_P(zval_p)
#define ZVAL_OBJ(z, o)
@ FAILURE
Definition zend_types.h:61
#define IS_OBJECT
Definition zend_types.h:608
#define IS_LONG
Definition zend_types.h:604
#define _IS_BOOL
Definition zend_types.h:629
ZEND_RESULT_CODE zend_result
Definition zend_types.h:64
struct _zend_object_handlers zend_object_handlers
Definition zend_types.h:88
#define Z_LVAL_P(zval_p)
Definition zend_types.h:966
#define ZVAL_BOOL(z, b)
ZEND_API void zval_ptr_dtor(zval *zval_ptr)
zval * return_value
uint32_t arg_num
zend_string * name
bool result
op2
op1
zval * ret
value
#define ZEND_POW
#define ZEND_SUB
#define ZEND_DIV
#define ZEND_MUL
#define ZEND_MOD
#define ZEND_ADD