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';
Related
I was studying about ternary operation nesting and made some tests with this routine:
<?php
$test1 = [15,30,'ok'];
$test2 = [8,90,'fail'];
$test3 = [4,32,'ok'];
$test1[2] == 'ok' ?
print('First passed. The second round marks '.
$test2[1]/$test2[0] < 10 ? 'an irrelevant value' : $test2[1]/$test2[0].
' and the third was skipped.') :
print('First failed. The second round was skipped and the third marks '.
$test3[1]/$test3[0] < 10 ? 'an irrelevant value' : $test3[1]/$test3[0]);
Although I know why it's not printing the string in the way I'd expect (it ignores everything before conditional test) because it lacks parenthesis around the ternary operator, it's showing some curious behavior despite of that. It's inverting the operator's evaluation priority.
Example
This test, written as it is, should return 11.25 since 11.25 > 10, but instead it returns an irrelevant value!
If I change the < operator for >, it should then print an irrelevant value, since it's true, but it evaluates to false and print 11.25 anyway.
Can anyone explain to me why it happens? Like I've said, I know the above statement is syntactically wrong, but I'm willing to understand why it alters the way PHP works the logic.
http://php.net/manual/en/language.operators.precedence.php lists the PHP operators with their precedence. According to this table,
'First passed. The second round marks ' . $test2[1] / $test2[0] < 10
? 'an irrelevant value'
: $test2[1] / $test2[0] . ' and the third was skipped.'
parses as
(('First passed. The second round marks ' . ($test2[1] / $test2[0])) < 10)
? 'an irrelevant value'
: (($test2[1] / $test2[0]) . ' and the third was skipped.')
/ binds tighter than .
. binds tighter than <
< binds tighter than ?:
In other words, you're comparing the string 'First passed. The second round marks 11.25' to the number 10.
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;
I got some PHP code here:
<?php
echo 'hello ' . 1 + 2 . '34';
?>
which outputs 234,
But when I add a number 11 before "hello":
<?php
echo '11hello ' . 1 + 2 . '34';
?>
It outputs 1334 rather than 245 (which I expected it to). Why is that?
That's strange...
But
<?php
echo '11hello ' . (1 + 2) . '34';
?>
or
<?php
echo '11hello ', 1 + 2, '34';
?>
fixes the issue.
UPDATE v1:
I finally managed to get the proper answer:
'hello' = 0 (contains no leading digits, so PHP assumes it is zero).
So 'hello' . 1 + 2 simplifies to 'hello1' + 2 is 2. Because there aren't any leading digits in 'hello1' it is zero too.
'11hello ' = 11 (contains leading digits, so PHP assumes it is eleven).
So '11hello ' . 1 + 2 simplifies to '11hello 1' + 2 as 11 + 2 is 13.
UPDATE v2:
From Strings:
The value is given by the initial portion of the string. If the string
starts with valid numeric data, this will be the value used.
Otherwise, the value will be 0 (zero). Valid numeric data is an
optional sign, followed by one or more digits (optionally containing a
decimal point), followed by an optional exponent. The exponent is an
'e' or 'E' followed by one or more digits.
The dot operator has the same precedence as + and -, which can yield unexpected results.
That technically answers your question... if you want numbers to be treated as numbers during concatenation, just wrap them in parentheses.
<?php
echo '11hello ' . (1 + 2) . '34';
?>
You have to use () in a mathematical operation:
echo 'hello ' . (1 + 2) . '34'; // output hello334
echo '11hello ' . (1 + 2) . '34'; // output 11hello334
You should check the PHP type conversion table to get a better idea of what's happening behind the scenes.
If you hate putting operators in between, assign them to a variable:
$var = 1 + 2;
echo 'hello ' . $var . '34';
Consider the following line of code:
<?php
$x = 10;
$y = 7;
echo '10 - 7 = '.$x-$y;
?>
The output of that is 3, which is the expected result of the calculation $x-$y. However, the expected output is:
10 - 7 = 3
My question therefore is, what happened to the string that I'm concatenating with the calculation? I know that in order to produce the result I expected, I need to enclose the arithmetic operation in parenthesis:
<?php
$x = 10;
$y = 7;
echo '10 - 7 = '.($x-$y);
?>
outputs
10 - 7 = 3
But since PHP does not complain about the original code, I'm left wondering what the logic behind the produced output in that case is? Where did the string go? If anyone can explain it or point me to a location in the PHP manual where it is explained, I'd be grateful.
Your string '10 - 7 = ' is being concatenated with $x. Then that is being interpreted as an int which results in 10 and then 7 is subtracted, resulting in 3.
For more explanation, try this:
echo (int) ('10 - 7 = ' . 10); // Prints "10"
More information on string to number conversion can be found at http://www.php.net/manual/en/language.types.string.php#language.types.string.conversion
If the string starts with valid numeric data, this will be the value used
In this code:
echo '10 - 7 = '.$x-$y;
The concatenation takes precedence, so what you're left with is this:
echo '10 - 7 = 10'-$y;
Because this is trying to perform integer subtraction with a string, the string is converted to an integer first, so you're left with something like this:
echo (int)'10 - 7 = 10'-$y;
The integer value of that string is 10, so the resulting arithmetic looks like this:
echo 10-$y;
Because $y is 7, and 10 - 7 = 3, the result being echoed is 3.
. and - have the same precedence, so PHP is reinterpreting '10 - 7 = 10' as a number, giving 10, and subtracting 7 gives 3.
PHP runs operations in the order defined here ; https://www.php.net/manual/en/language.operators.precedence.php
Take a look at this example ;
$session_period = 30;
new \DateTime('now -' . $session_period+1 . ' minutes');
Beware! This will NOT give you the time 31 minutes ago.
In this case PHP just interprets starting from the leftmost part of an expression so this simple-looking expression returns the wrong result;
Because ;
'now -' . $session_period => 'now -30'
then PHP will cast the string to 0 and add 1 to that => 1
and 1 . ' minutes' => '1 minutes'
That's why the expression above will give you the result of
new \DateTime('1 minutes')
To avoid this kind of confusion, use () like this ;
new \DateTime('now -' . ($session_period+1) . ' minutes');
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