ZF-2804: bcmath extension and numbers processing behavior may need spechial approach to provide correct results for some locales


The core of the problem is locale dependent numbers processing behavior, especially strings <-> numbers conversion.

float -> string conversion uses zend_spprintf() function, which actually uses xbuf_format_converter() function. xbuf_format_converter() uses decimal point provided by current locale. string -> float conversion uses zend_strtod() function which has hardcoded decimal point character ('.')

So float -> string -> float conversion may be not reversible operation for locales which don't use '.' as decimal point (e.g. fr_FR locale uses ',');

setlocale(LC_ALL,'fr_FR'); var_dump((float)26.25); // output: float(26,25)

setlocale(LC_ALL,'fr_FR'); var_dump((string)(float)26.25); // output: string(5) "26,25"

setlocale(LC_ALL,'fr_FR'); var_dump((float)(string)(float)26.25); // output: float(26)

I am not sure it's a bug, since that exactly corresponds to the behavior described in the PHP manual (…)

That affects our implementation of Zend_Locale_Math_PhpMath methods.

Another problem is bcmath extension behavior. bcmath functions take strings as arguments. Conversion to the strings is performed automatically. But! bcmath functions operate with '.' as decimal point. If it gets another symbol it treats number as zero:

setlocale(LC_ALL,'fr_FR'); var_dump(bcadd(1, '2.25', 2)); // output: string(4) "3.25"

setlocale(LC_ALL,'fr_FR'); var_dump(bcadd(1, '2,25', 2)); // output: string(4) "1.00"

setlocale(LC_ALL,'fr_FR'); var_dump(bcadd(1, 2.25, 2)); // output: string(4) "1.00"

So we have to provide input for math functions as non-localized strings with numbers.


With the change from ZF-2813 and the last changeset 8584 the problem should be prevented. Now all inputs are converted to string and only string is returned.

All I18N classes which make use of this internal class have been reviewed and 2 small possible problems have been reworked.

The testbed always tests with the actual used locale. Some defined tests are done with 'fr' which has a complete different number representation. Using the testhelper you can simply change the used locale to any locale you wish.

This issue should have been fixed for the 1.5 release.