I have a while loop with 2 conditions separated by 'or':
while (($i <= 8) || ($x <= 5)){
$i++;
$x++;
}
I want the loop to end when the lowest number is reached - in the above case 5. However, the above stops when the first, higher condition is met and it loops 8 times.
This still occurs when I swap the values, eg:
while (($i <= 5) || ($x <= 8))
The loop will still ignore <= 5 and loop through 8 times.
Would anyone know how I can fix this to have the loop cycle stop at the lower number?
It's doing what you have written. Use && instead of || and it will stop as soon as one of the conditions is no longer true.
The loop will execute as long as the expression inside while(expression) is true. In this case, your expression is $i <= 8 || $ x<=5 wich translates into:
$i is less or equal than 8 OR $i is less or queal than 5.
From php documentation:
$a || $b is TRUE if either $a or $b is TRUE.
If you want the smallest number, then you want both conditions to be true to continue the loop, so you use AND, which documentation is:
$a && $b is TRUE if both $a and $b are TRUE
So your code should be:
while (($i <= 8) && ($x <= 5)){
$i++;
$x++;
}
You can also use the keywords andand or, but be careful, because they have different operator precedence, in particular, they have less precedence:
http://php.net/manual/en/language.operators.precedence.php
Use and instead of or
while (($i <= 8) && ($x <= 5)){
}
If you use or it needs only one of its condition to be true for foing inside the loop. And will ensure that both of the condition should be true. So it will exit the loop when any one of the condition becomes false
You should use 'and' operation.
while($x<5 && $y<8) {//Your code here}
I suggest reading about this logic operators, these operators are basic in development.
Related
I am learning PHP. I decided to adapt a solution to the famous FizzBuzz problem from Javascript to PHP, just to see how JS and PHP compare.
For those who forgot what the FizzBuzz problem is :
Write a short program that prints each number from 1 to 100 on a new
line. For each multiple of 3, print "Fizz" instead of the number.
For each multiple of 5, print "Buzz" instead of the number. For
numbers which are multiples of both 3 and 5, print "FizzBuzz" instead
of the number.
I am using a lot of short-circuit evaluations in the following examples.
Here's the clever solution (not written by me) that I adapted to PHP:
Works great!
Then, for the sake of challenge, I decided to try and rewrite it in one single line.
Here's how I started:
Seems like a good start. My condition in the while loop: if $i is not set set, then I set it to zero, but if it is already set, I skip the first part and check if it's inferior to 100.
As you can see on this picture, my loop works.
Since my goal is to write it in one line, I need to increment $i inside my conditional statement, just as with my previous multi-line solution. But when I write $i++ < 100 as before, something weird happens. My loop only runs once and stops.
Very weird indeed.
Even weirder, if I use both increments (one in the condition and one in the loop), the loop then works fine, and applies both increments.
I'm puzzled. Is it because there is a safeguard for infinite loops somewhere? With all those short-circuit evaluations, even my IDE PHP Storm says 'variable $i is probably undefined'. But it gets defined, and my loop works fine under certain conditions. What did I miss ?
EDIT:
Here's the code:
Multi-line working FizzBuzz:
$i = 0;
while ($i++ < 100) {
$msg = '';
($i % 3) || ($msg = $msg . 'Fizz');
($i % 5) || ($msg = $msg . 'Buzz');
echo $msg . "\n";
}
Weird loop iteration (you can delete the increment either in the loop or in the condition, or leave both to see the different effects):
while ( (!isset($i) && ($i=0 || true) ) || ($i++ < 100) ) {
echo $i . "\n";
$i = $i +1;
}
if $i is not set set, then I set it to zero
This is not quite right. Here's what's going on.
Your statement ($i=0 || true) sets $i to TRUE.
PHP's type juggling with print "1" for "$i". Consider $v = TRUE; echo "$v"; to see this in effect.
On the next iteration, your second condition is evaluated as TRUE < 100 which evaluates to FALSE, thereby exiting the loop.
So, in order to fix your problem, simply drop the || true and be on your merry way.
$i=0 || true results in $i being true.
true++ doesn’t actually do anything.
true < 100 is false.
echo true outputs 1.
An explicit true + 1 creates 2.
OMG, Yes! I thought I needed the || true part because ( !isset($i) && ( $i = 0 ) ) will either do both sides of the &&, or neither. I never thought that ( $i = 0 ) would evaluate to "true". But it looks like it does :)
OBSOLETE COMMENT: I found the origin of the quirk. Not sure why it happens though.
If I rewrite $i++ as ($i = $i + 1), it works fine.
while ( (!isset($i) && ($i=0 || true) ) || (($i = $i + 1) < 100) ) {
echo $i . "\n";
}
Within a for loop, i need to add some HTML that outputs only when the loop is on a [(multiple of 3) minus 1].
For example, what i could do is:
for($i=0; $i<count($imagearray); $i++)
{
if($i=="0" || $i=="2" || $i=="5" || $i=="8" || $i=="11")
{
echo 'string';
}
}
but this isnt very elegant and extremely useless for big for loops, is there a proper way to do this?
if ( $i==0 || ($i+1)%3 == 0 )
{
//do stuff
}
What this will do, is go to the next index, divide it by 3, and see if there is a remainder. If there is none, then that means that the current index is one less than a number that is divisible by 3
Use the modulus operator.
if (! (($i+1) % 3) ) {
If $i+1 divides into 3 with no remainder, the result will be zero. Then you just need a boolean not.
If you want to match 0 as well (since you use it in your example, but it doesn't match your description) then you will have to special case it with an ||.
You want to use the modulo for that:
(1 % 3) == 1
(2 % 3) == 2
(3 % 3) == 0
(4 % 3) == 1
Good luck
Modulo is the same thing as saying, give me the remainder of a division. So 1 / 3 equals 0 remainder 1, and so on.
if(($i+1)%3 == 0){
//do something
}
The % operator is known as the modulus operator and returns the remainder of a division.
the most elegent method is thus
if ($i % 3 === 2) {
//do stuff
}
as it doesn't add things to the $i value, but all answers are essentially correct!
I am running a for loop 10 times in order to populate data in a data table. In doing this, I wanted to use number_format in order to format the numbers. However, when I apply the number_format the For loop for some reason runs one additional time.
It works just fine when I exclude the number_format. Can anyone explain why this happens?
<?php
foreach($data['data'] as $result) {
For ($n = 0; $n <= 10; $n++){
echo "<td>";
echo number_format($result[$n], 0, ".", ",");
echo "</td>";
}
}
?>
TL;DR: Your loop will always run an additional time. Assuming that there are no errors in your number_format function call, all you have to do to get this to run 10 times is change your code to for($n = 0; $n < 10; n++). Note the use of < and not <=.
For loops are really just syntactical sugar for while loops. The statement for(initial_statement; bound_condition; loop_statement) { code; } is equivalent to
initial_statement;
while(bound_condition) {
code;
loop_statement;
}
Which, functionally, is equivalent to
initial_statement;
while(true) {
code;
loop_statement;
if(!bound_condition) break;
}
This means that if you want a loop to run, say, 2 times, and you write for($i = 0; $i <= 2; $i++) your code will loop as follows:
$i = 0
i++; (i now equals 1)
i <= 2 (condition is true, so continue)
$i = 1
i++; (i now equals 2)
i <= 2 (condition is true, so continue)
$i = 2
i++; (i now equals 3)
i <= 2 (condition is FALSE, so break)
Using the <= operator when your control variable starts at 0 causes an extra iteration to occur, since there are three integer values of i such that 0 <= i <= 2 (0, 1, and 2). To ensure that there are only two iterations, use the < operator, and now the loop will only be executed for values in the domain 0 <= i < 2 (0 and 1).
If you are still bent on using the <= operator and are fine with a non-zero-based iteration count, then you can simply change the initial value of i to 1 to offset the error.
By the way your code is written, I assume that you wish for your inner loop to run 10 times, not 11. This would explain why you are getting an extra iteration, and the issue is quite unrelated to the use of number_format. If you are only getting 10 iterations when you don't use that function, you might want to make sure that the statement 1 == 1 evaluates to true in your PHP interpreter.
Additionally, as a code styling issue, I would recommend using consistent case in your statements; you write foreach (lowercase) but also use For (uppercase). The convention is to use lowercase for both.
I have no clue why you would be only getting 10 iterations without number_format. You might be counting incorrectly? Try changing it to < and see if that resolves your issue.
I've been programming in php for about 2 years now.
I just stumbled into this for loop:
// Check the URI namespace for a context
$wsDir = basename(dirname(__FILE__));
$uriArr = explode("/", $_SERVER['REQUEST_URI']);
for (
$i = 0, $uriSize = sizeof($uriArr);
$i < $uriSize && $uriArr[$i] != $wsDir && $i++;
);
$i++;
self::$executionContext = isset($uriArr[$i]) && !empty($uriArr[$i]) && substr($uriArr[$i], 0, 1) != '?'
? strtoupper($uriArr[$i]) : 'SOAP';
and I have no idea how this is supposed to work.
Can someone explain this to me ?
It is just a normal three-part for loop without its main statement and an empty third part.
From the manual:
for (expr1; expr2; expr3)
statement
The first expression (expr1) is evaluated (executed) once unconditionally at the beginning of the loop.
In the beginning of each iteration, expr2 is evaluated. If it evaluates to TRUE, the loop continues and the nested statement(s) are executed. If it evaluates to FALSE, the execution of the loop ends.
At the end of each iteration, expr3 is evaluated (executed).
So:
for (
# initializes two variables
$i = 0, $uriSize = sizeof($uriArr);
# conditional, expr2
$i < $uriSize && $uriArr[$i] != $wsDir && $i++;
# no expr3
);
If the expr2 evaluates to true the loop continues. Of course there is no statement or block to execute, so it just jumps to the next iterarion, meaning expr2 will be executed repeatedly until it evaluates to false at some point.
As pointed out by R. Chappell in the comments, this is probably to find a position in a string. You could rewrite this with a similar logic but in a more "descriptive" way:
$uriSize = sizeof($uriArr)
for ($i = 0; $i < $uriSize; $i++) {
if ($uriArr[$i] == $wsDir) break;
}
# now $i will be the index of the first $wsDir occurrence in the $uriArr array
Coming late, but none seems to have cached this : this for loop is equivalent to :
$i = 1;
Why ? Because in the condition part of the for loop, you have 3 conditions that are bound with AND:
$i < $uriSize
&&
$uriArr[$i] != $wsDir
&&
$i++;
In the first iteration, $i++ evaluates to 0 which is equivalent to false, and is incremented only after. So the loop stops after only one iteration, and $i is 1, and you have a bug. Unless it's a typo in your code...
This is another example (not an answer as such) of using a for without a third statement. It's a little clearer than the original question.
for ($i=0; $i >= $i++ && $i <= 10; /* third statement */ );
echo $i;
This will basically count to 10 and echo it out, and it's only made possible with the increment operator in PHP.
First we set $i to zero;
Second we check and increment $i to ensure it's equal to or greater than itself whilst less than or equal to 10.
Third we do nothing... no point really...
However, normal people would write the same thing as:
for ($i = 0; $i <= 10; $i++);
echo $i;
You'll have to imagine a better use case though and yes you can just do $i = 10; but it doesn't go as far as to explaining the question.
I have the following code in production that appears to be causing an infinite loop.
$z=1;
while (!$apns = $this->getApns($streamContext) && $z < 11)
{
myerror_log("unable to conncect to apple. sleep for 2 seconds and try again");
$z++;
sleep(2);
}
How are the precedence rules getting applied that cause this behavior?
http://php.net/manual/en/language.operators.precedence.php
I see this note in the docs:
Although = has a lower precedence than most other operators, PHP will
still allow expressions similar to the following: if (!$a = foo()), in
which case the return value of foo() is put into $a.
Which makes me think the the = should be evaluated first. then the ! then the &&, which would not cause an infinite loop.
Your code is evaluating like this:
while (!($apns = ($this->getApns($streamContext) && ($z < 11))))
which is why you see the infinite loop (as soon as $z >= 11, $apns is false, so the condition is always true). The reason for this precedence is that the special rules only apply to ! on the left of the assignment being valid (having lower precedence than =). It has no effect on the boolean operator on the right, which behaves as it would in any sane language.
Your style is bad. Try this, which is much more readable and only differs in the final value of $z (and if that's important you can tweak the break statement.
for( $z = 1; $z < 11; ++ $z ) {
// note extra brackets to make it clear that we intend to do assignment not comparison
if( ($apns = $this->getApns($streamContext)) ) {
break;
}
myerror_log("unable to conncect to apple. sleep for 2 seconds and try again");
sleep(2);
}
Your code is clear example of why it's good habit to always put all the conditions in brackets (and the same applies to code block. Even oneliners should be surrounded by { and }). So instead of error-prone:
while (!$apns = $this->getApns($streamContext) && $z < 11)
do
while (!($apns = $this->getApns($streamContext)) && ($z < 11))
and you will be safe.