Hello,
While testing a bit of code under a different locale (de_DE) we found
that var_export()
uses a , for representing floating point decimal
separators. As var_export()
is supposed to generate "valid PHP code"
there is now a bug in this function.
While looking into this, I found that internally it uses the following
call:
php_printf("%.*G", (int) EG(precision), Z_DVAL_PP(struc));
However, the G modifier, unlike F, is locale-aware and will happily
create "5,12" as a "valid PHP float". This of course does not parse. I
expected the uppercase G to be locale-insensitve and the lowercase g to
be locale-sensitive. However, looking at the code it only switched
between E and e. The g/G modifier as is implemented now does not seem to
have any locale-insensitive option. The difference between "f" and "g"
is that g/G is smarter regarding appending 0's. Trailing zeroes are not
wanted when rendering a float as "valid PHP code" (as it looks different
than when it was written in the application).
I see a few options to address this:
-
Change "G" to be locale-insensitve.
We can't really do that as it's also use in _convert_to_string.
-
Add a new modifier "H" or "L" that is like G, but
locale-insensitive. -
Change "g" to be locale-insensitve, as this one does not seem to be
used anywhere in the code base.
I think we should pick option 2, find another modifier letter as it
won't impact anything else.
Notes:
- _build_trace_args (from Zend/zend_exceptions.c) seems also to be
affected, as it uses the G modifier to build argument lists as string
for exception traces. So now it uses the , to separate arguments AND
as float decimal sep in case of a de_DE locale.
regards,
Derick
--
Derick Rethans
http://derickrethans.nl | http://ez.no | http://xdebug.org
- Add a new modifier "H" or "L" that is like G, but
locale-insensitive.
I implemented this as the "H" modifier.
Notes:
- _build_trace_args (from Zend/zend_exceptions.c) seems also to be
affected, as it uses the G modifier to build argument lists as string
for exception traces. So now it uses the , to separate arguments AND
as float decimal sep in case of a de_DE locale.
This one can not be fixed, as it uses zend_sprintf() which just wraps
around sprintf()
incase sprintf is not "broken". sprintf()
doesn't have
a format modifier for this purpose, so what we can do here is 1. always
use our sprintf()
implementation; 2. use php_printf() or 3. ignore it.
Derick