I thought I've known the String Operator . well enough until I was asked a question about it today. The question looks quite simple:
echo 100...100;
At the first glance I thought it would make a syntax error. But when I ran the code and saw the result I was totally confused. The result is
1000.1
So I wonder how could this happen?
Thanks.
Read it like this:
(100.) . (.100)
Thus it concats 100 and 0.1.
Assuming you meant
echo 100...100;
The reason for this is the beauty of PHP. :)
This statement is understood as
100. . .100
which is equivalent to
100.0 . 0.1
<=>
'100' . '0.1'
<=>
'1000.1'
You can read it as echo 100 . 0.1.
Actually, that only works without the quotes:
echo "100...100"; 100...100 << with quotes the . is just a char
echo 100 . 100; 100100 << two concatenated strings "100"
echo 100.100; 100.1 << 100.100 is just a number
echo 100...100; 1000.1 << what you asked
echo 100. . .100; 1000.1 << what PHP actually interprets
Related
This question already has answers here:
Compare floats in php
(17 answers)
Closed 4 years ago.
This piece of code:
$total=$o->cart->getTotalSum();
$subTotal=$o->cart->getSubTotal();
if(floatval($r['sum_total']) != floatval($total) ||
floatval($r['sum_sub']) != floatval($subTotal)) {
echo 'Differs on #' . $r['id'];
echo 'Total: ' . $total . ' / ' . $r['sum_total'];
echo 'Sub: ' . $subTotal . ' / ' . $r['sum_sub'];
}
Gives me this output:
Differs on #697
Total: 19.6 / 19.6
Sub: 19.6 / 19.6
Why? How is that even possible?
I make sure that all values compared are of type float, so no strings could have slipped in.
I must be missing something.
My apologies for not providing really reproducible code, but i wouldn't know how in this case.
If you do it like this they should be the same. But note that a characteristic of floating-point values is that calculations which
seem to result in the same value do not need to actually be identical.
So if $a is a literal .17 and $b arrives there through a calculation
it can well be that they are different, albeit both display the same
value.
Usually you never compare floating-point values for equality like
this, you need to use a smallest acceptable difference:
if (abs(($a-$b)/$b) < 0.00001) { echo "same"; } Something like that.
I think someone else had the exact same problem.
https://stackoverflow.com/a/3148991/2725502
I was experimenting with weak/dynamic typing properties of PHP in preparation for a test and was completely baffled by the output of this string concatenation. Can someone explain how this is even possible?
<?php echo 1 . "/n" . '1' + 1 ?><br />
output:
2
Analysis:
echo 1 . "/n" . '1' + 1;
is equivalent to
//joined first 3 items as string
echo "1/n1"+1;
is equivalent to
//php faces '+' operator, it parses '1/n1' as number
//it stops parsing at '/n' because a number doesn't
//contain this character
echo "1"+1;
is equivalent to
echo 1+1;
Is this behaviour correct in PHP?
<?php echo '-' . 1 + 1 . ' crazy cats'; ?>
// Outputs:
0 crazy cats
I understand that minus is being concatenated to the first '1' and '-1' casted to integer, and not '2' to string.
Please explain why.
What is the best way to solve it?
This one?
<?php echo '-' . (string)1 + 1 . ' crazy cats'; ?>
First of all, it is correct, and if it would be different it would also be correct, that's how PHP developers defined operand precedence.
In this scenario, no operand has precedence, so u read it left to right
'-' . 1 ==> '-1'
'-1' + 1 ==> 0 (arithmetic operations on strings, will try to cast them to numbers first and then do the arithmetics).
0 . ' crazy cats' ==> "0 crazy cats" (strings operations on numbers, will cast them to strings).
If you want -2 crazy cats, you can set the manipulate precedence with parenthesis:
echo '-' . (1 + 1) . ' crazy cats';
echo also follows the construct of echo 'foo', 'bar' which separates the items into distinct statements to echo. You don't have to worry about concatenation order in that case.
So you could do <?php echo '-', (1 + 1), ' crazy cats'; ?> and your cats wouldn't care about negatives!
If you prefer, this avoids precedence:
printf('-%d crazy cats',1+1);
Your verbiage is off. The '-' is not being casted but concated.
PHP will still treat (string) 1 and -1 as an integer.
. and +/- have the same precedence in PHP, so the string can be read from left to right.
The above is similar to saying:
echo '-1' + '1 crazy cats';
Here is a simple php program which gives a strange output. Can anyone explain why it is coming like this and how to get the expected output?
<?php
$a=2;$b=3;
echo "<br> ADD:".$a+$b;
echo "<br> SUB:".$a-$b;
echo "<br> MUL:".$a*$b;
echo "<br> DIV:".$a/$b;
?>
Output:
3-3
MUL:6
DIV:0.66666666666667
Expected Output:
ADD:5
SUB:-1
MUL:6
DIV:0.66666666666667
It is because the string concatenation operator . has the same precedence as the add/sub operators, and all of them are left-associative. This means that evaluation proceeds left-to-right, so "<br> ADD:".$a is evaluated first and the result is added to 3. This particular string converts to zero and 0 + 3 = 3. Similar for the subtraction.
Solution: put the arithmetic in parentheses.
echo "<br> ADD:".($a+$b);
echo "<br> SUB:".($a-$b);
On the other hand, mul/div have higher precedence than concatenation so they produce the expected result.
I was simply wishing to test for overflow on an integer, such as in C (well, if it were just over integer max anyway). When I looked to see if PHP was actually doing what I told it to, it seems it fails for some reason. Here are my tests of the problem:
define('INT_MAX', 0x7FFFFFFF);
print "In decimal: " . hexdec(INT_MAX) . "<br/>";
print "In decimal: " . hexdec(0x7FFFFFFE) . "<br/>"; //Under int_max
print "In hex: " . dechex(hexdec(INT_MAX)) . "<br/>";
print "Float: " . ((bool)is_float(INT_MAX)?'true':'false') . "<br/>";
Results being:
In decimal: 142929835591
In decimal: 142929835590
In hex: 47483647
Float: false
As I saw on the manual, it will cast to float if overthrown, but it seems to not and is clearly way higher. Am I being insane and missing something here, or is there some odd problem I should really need to know about when working with hexidecimal in PHP?
Your program makes no sense, because you are taking 0x7FFFFFFF which is 2147483647, and then treating it like 0x2147483647, which is 142929835591 in decimal.
Anyway, PHP already has a constant that you can use:
var_dump(PHP_INT_MAX + 1); // converted to float
define('INT_MAX', 0x7FFFFFFF);
This defines INT_MAX to be integer 2147483647. It is unnecessary to interpret it as a hexadecimal number. If you really want to use INT_MAX as a literal hexadecimal value, then you need to declare it as '7FFFFFFF' (inside a string); then the hexdec function will interpret the hexadecimal notation and convert it to a decimal value.
print(dechex(INT_MAX) . "\n");
This prints "7fffffff".