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, 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 is0
andtrue
otherwise. - Of the six comparison methods
comp()
,eq()
,gt()
,gte()
,lt()
,lte()
, remove all exceptcomp()
. Then rename thecomp()
method tocompare()
. - 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.
Patches and Tests
None.
Implementation
References
Rejected Features
Some methods will be removed, but since this class has not been released yet, essentially no functionality will be removed.