php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #77347 switch casting behavior by setlocale(LC_NUMERIC, '') is wrong
Submitted: 2018-12-26 14:32 UTC Modified: 2018-12-26 23:11 UTC
From: spam2 at rhsoft dot net Assigned: cmb (profile)
Status: Duplicate Package: Scripting Engine problem
PHP Version: 7.2.13 OS: Linux
Private report: No CVE-ID: None
 [2018-12-26 14:32 UTC] spam2 at rhsoft dot net
Description:
------------
you can disable comments for https://bugs.php.net/bug.php?id=77278 as much as you want - the current behavior of the scriptiung language is plain wrong and this seems have to be fixed even in the past looking at https://bugs.php.net/bug.php?id=17815 and "Workaround for this bug: setlocale(LC_NUMERIC,'C');"

* LC_NUMERIC="de_DE.UTF-8" is the default environment here
* if you call the changing behavior depending on locale
  correct you mustn't silently change it to LC_NUMERIC=C
  to begin with and that code sample would always
  come with , instead .
* but it does not
* it does only after a random setlocale wihtin PHP or some library

[harry@srv-rhsoft:/downloads]$ locale
LANG=de_DE.UTF-8
LC_CTYPE="de_DE.UTF-8"
LC_NUMERIC="de_DE.UTF-8"
LC_TIME="de_DE.UTF-8"
LC_COLLATE="de_DE.UTF-8"
LC_MONETARY="de_DE.UTF-8"
LC_MESSAGES="de_DE.UTF-8"
LC_PAPER="de_DE.UTF-8"
LC_NAME="de_DE.UTF-8"
LC_ADDRESS="de_DE.UTF-8"
LC_TELEPHONE="de_DE.UTF-8"
LC_MEASUREMENT="de_DE.UTF-8"
LC_IDENTIFICATION="de_DE.UTF-8"
LC_ALL=

[harry@srv-rhsoft:/downloads]$ php /downloads/casting.php
LC_CTYPE=de_DE.UTF-8;LC_NUMERIC=C;LC_TIME=C;LC_COLLATE=C;LC_MONETARY=C;LC_MESSAGES=C;LC_PAPER=C;LC_NAME=C;LC_ADDRESS=C;LC_TELEPHONE=C;LC_MEASUREMENT=C;LC_IDENTIFICATION=C
OK: 4

de_DE.UTF-8
FAIL: 3,3333333333333

Test script:
---------------
[harry@srv-rhsoft:/downloads]$ cat /downloads/casting.php
<?php declare(strict_types=1);
echo setlocale(LC_ALL, '0'), "\n";
$pages_summary = (string)(10 / 3);
if($pages_summary > (int)$pages_summary)
{
 $pages_summary = (int)$pages_summary + 1;
}
if((int)$pages_summary !== 4)
{
 echo "FAIL: $pages_summary\n";
}
else
{
 echo "OK: $pages_summary\n";
}

echo "\n";

echo setlocale(LC_NUMERIC, ''), "\n";
$pages_summary = (string)(10 / 3);
if($pages_summary > (int)$pages_summary)
{
 $pages_summary = (int)$pages_summary + 1;
}
if((int)$pages_summary !== 4)
{
 echo "FAIL: $pages_summary\n";
}
else
{
 echo "OK: $pages_summary\n";
}

Expected result:
----------------
no change in casting behavior

Actual result:
--------------
don't change internal behavior randomly

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2018-12-26 14:35 UTC] spam2 at rhsoft dot net
-Summary: switch catsing behavior by setlocale(LC_NUMERIC, '') is wrong +Summary: switch casting behavior by setlocale(LC_NUMERIC, '') is wrong
 [2018-12-26 14:35 UTC] spam2 at rhsoft dot net
fixed typo in summary
 [2018-12-26 15:28 UTC] cmb@php.net
-Status: Open +Status: Duplicate -Assigned To: +Assigned To: cmb
 [2018-12-26 15:28 UTC] cmb@php.net
What are you trying to convey here?  The fact that

  setlocale(LC_NUMERIC, '')

changes the locale setting according to the environment is well
documented[1], and that the decimal separator is locale depending
for float to string casts[2].  Other than that, I can't see how
this bug report isn't a duplicate of bug #77278, where it already
has been explained in detail that:

| PHP converts by locale in one direction (float->string) but not
| in the other direction (string->float). It should be consistent.
| But like @nikic said, this inconsistency is currently the intended
| behavior - not the correct behavior, merely the *intended*
| behavior. It does need to get fixed but it's not a simple thing to
| just do.

To additionally clarify the word “simple” above: of course it is
simple to change the behavior, but that would likely cause a
massive BC break, so we cannot do this for the next minor version,
or even a revision, but would have at least to wait for the next
major PHP version.  And yes, somebody would need to take the time
to walk through the RFC process[3].

[1] <http://php.net/manual/en/function.setlocale.php>
[2] <http://php.net/manual/en/language.types.string.php#language.types.string.casting>
[3] <https://wiki.php.net/rfc/howto>
 [2018-12-26 15:46 UTC] spam2 at rhsoft dot net
well, comments for the other Bugreport are disabled 

can you explain me why for php LC_NUMERIC is set to C while the locale of the session is german other then to prevent that sort of confusion until somebody is touching locale after script start? 

if php would act here consistent I pretty sure would never have written that casting code to begin with because this dumb behavior would have jumped straight in my face all the time and not just by a random library which touched locale 


the float-to-string locale behavior is plain wrong and not that the other direction don't convert back correctly

if one is interest in locale format he is using a format function and not type casting
 [2018-12-26 17:18 UTC] cmb@php.net
> can you explain me why for php LC_NUMERIC is set to C while the
> locale of the session is german other then to prevent that sort of
> confusion until somebody is touching locale after script start? 

PHP's core does not touch any locale settings (so all default to
C), except for LC_TYPE[1].

> if php would act here consistent I pretty sure would never have
> written that casting code to begin with […]

See commit 7e0baa7[2] why initializing LC_ALL might not be the
best idea.

[1] <https://github.com/php/php-src/blob/9882929bfa4422765c1b1fde6a612fa48bfcce2e/main/main.c#L2180>
[2] <http://git.php.net/?p=php-src.git;a=commit;h=7e0baa7a1daa531e39881e59842c88d12e42c901>
 [2018-12-26 17:36 UTC] spam2 at rhsoft dot net
if it don't touch it how can it be C then when the environment is DE
 [2018-12-26 17:53 UTC] spam2 at rhsoft dot net
http://git.php.net/?p=php-src.git;a=commit;h=7e0baa7a1daa531e39881e59842c88d12e42c901 and "Revert Thies' locale patch. It was screwing up language level things" 18 years ago should not have reverted but the "language level things" fixed so that they are *not* get screwed up just because setlocale() exists somewhere left and right in the code
 [2018-12-26 23:11 UTC] cmb@php.net
> if it don't touch it how can it be C then when the environment
> is DE

This is defined by POSIX[1]:

| The POSIX locale is the default global locale at entry to
| main().

(The C locale is equivalent to the POSIX locale.)

POSIX futher elaborates:

| Internationalized programs can initiate language operation
| according to environment variable settings […]

Note the word “can”.

[1] <http://pubs.opengroup.org/onlinepubs/9699919799/functions/setlocale.html>
 
PHP Copyright © 2001-2019 The PHP Group
All rights reserved.
Last updated: Mon Aug 19 14:01:26 2019 UTC