====== PHP RFC: Fix up BCMath Number Class / Change GMP bool cast behavior ====== * Version: 1 * Date: 2024-06-30 * Author: Saki Takamachi (saki@php.net) * Status: Implemented * First Published at: https://wiki.php.net/rfc/fix_up_bcmath_number_class ===== Introduction ===== Regarding [[rfc:support_object_type_in_bcmath|RFC: Support object type in BCMath]], I received several comments and suggestions, so I created this RFC to respond to them. Also, in those discussions, there were suggestions regarding the behavior of casting GMP classes to bool, and for procedural efficiency, I will combine these into one RFC. (Each vote will be taken separately.) ===== Proposal ===== This RFC makes several corrections and changes to the BcMath\Number class and proposes to override the first RFC. It also proposes that when a GMP object is cast to bool, change it so that 0 is false and everything else is true, like an int. Details of the proposal regarding BCMath are as follows: - Casting a Number object to bool makes it false if it is 0 and true otherwise. - Of the six comparison methods comp(), eq(), gt(), gte(), lt(), lte(), remove all except comp(). Then rename the comp() method to compare(). - Remove format() method. - Remove rounding in calculations. - Make it serializable. - Fixed typo in stub. === bool cast === Change both GMP and BCMath to behave like int. ==== BCMath ==== === More information about comparison methods === In fact, only the comp() method is needed to fulfill the functionality of the other five methods. Adding methods later is easy, but removing them always involves a BC Break. Providing 6 methods from the start is obviously overkill, so we will only provide comp(). By the way, the reason comp() is needed, and why comparison operators are underpowered, is to specify the scale to use for the comparison. Currently, there is no other expression for comparison in PHP called "comp". The expression "cmp" is mainly used for functions, and the expression "compare" is used for class methods. e.g. https://www.php.net/manual/ja/splpriorityqueue.compare.php https://www.php.net/manual/ja/collator.compare.php Therefore, follow these conventions and rename comp() to compare(). public function compare(Number|string|int $num, ?int $scale = null): int {} === Remove format method === The optimal format varies greatly from country to country, and the signature proposed in the original RFC is insufficient. There are also opinions that such functionality should be implemented in Intl rather than BCMath. If released in a half-finished state, BC Break will become a problem later, so this feature will be removed. If this functionality is really needed for this class, we can always consider adding it again. === Remove rounding in calculations === The current specification does not allow calculations with operators to be used by users who do not want rounding. I also found it very inconvenient to have to specify an optional argument every time I perform a calculation using this method if I don't want rounding. e.g. $ret = $num->div($num2, null, PHP_ROUND_TOWARD_ZERO); If the default behavior is "no rounding", i.e., truncation behavior like the existing BCMath functions, if you want to perform rounding, you can simply use the round() method. $ret = $num->div($num2)->round(2); Based on the idea that we shouldn't provide an API that looks "rich" from the get-go, I suggest removing all of these roundings. In other words, the rounding mode during calculations will be fixed at truncation, and the user will not be able to change it. This applies to both operator and method calculations. If the user wants to do rounding, the round() method should be used. === Make it serializable === Being serializable is very important when using something like Redis, as this is expected to be used as a value object. This probably doesn't require an RFC on its own, but I mention it to keep things clear. === Fixed typo in stub === This probably doesn't require an RFC per se, but I'll make it explicit to keep things clear. public function pow(Number|string|int $exponent, int $minScale, ?int $scale = null, int $roundingMode = PHP_ROUND_HALF_UP): Number {} I forgot to delete int $minScale in this signature. Correctly, it should look like this: public function pow(Number|string|int $exponent, ?int $scale = null, int $roundingMode = PHP_ROUND_HALF_UP): Number {} ===== Backward Incompatible Changes ===== BCMath: None. GMP: Code like if ($gmp) {} will behave differently. However, due to the nature of GMP, such code is likely to be quite rare. ===== Proposed PHP Version(s) ===== next PHP 8.x (8.4) ===== RFC Impact ===== ==== To SAPIs ==== None. ==== To Existing Extensions ==== BCMath: only BCMath GMP: only GMP ==== To Opcache ==== None. ==== New Constants ==== None. ==== php.ini Defaults ==== None. ===== Open Issues ===== None. ===== Unaffected PHP Functionality ===== BCMath: nothing other than BCMath is affected. GMP: nothing other than GMP is affected. ===== Future Scope ===== BCMath: Methods removed in this RFC may be considered for implementation again in the future. However, there are no specific plans at this time. ===== Proposed Voting Choices ===== As per the voting RFC a yes/no vote with a 2/3 majority is needed for this proposal to be accepted. This RFC combines two RFCs into one for procedural efficiency, and the BCMath and GMP proposals will be voted on separately. This means that the two RFCs are completely independent and do not influence each other's voting results. These are not second-round votes, so each requires a two-thirds majority vote to pass. Voting ends on 2024-07-30 00:00:00 UTC. * Yes * No ---- * Yes * No ===== Patches and Tests ===== None. ===== Implementation ===== https://github.com/php/php-src/pull/13741 https://github.com/php/php-src/pull/15151 ===== References ===== https://wiki.php.net/rfc/support_object_type_in_bcmath https://externals.io/message/123323 ===== Rejected Features ===== Some methods will be removed, but since this class has not been released yet, essentially no functionality will be removed.