If Loop inside of While Loop causes infinite loop - php

I'm trying to loop through the first 5 items of an array that contain a specific value.
The code below causes an infinite loop.
$i = 0;
while ($i < 5):
if ($counselor[$i]->state == $state || !$state):
// do stuff
$i++;
endif;
endwhile;
Essentially I want to end the loop after the if statement has run 5 times.

While others have explained why your solution currently does not work, and some ways around it, the best alternative is to loop the entire array until you find 5 matches - by using a foreach-loop instead.
By using an foreach-loop, you will never run into issues if the array has less than 5 matching elements (if it has less than 5 matching elements, it will never break).
$i = 0;
// Loop the array
foreach ($counselor as $k=>$v) {
// Check if there is a match
if ($v->state == $state || !$state) {
// Do whatever if a match here
$i++;
}
// If we have found 5 matches, break out of the loop!
if ($i == 5) {
break;
}
}
You can now check how big $i is, and if less than 5, you found less than 5 matches. If it's exactly 5, you found your matches, and ended the loop.

If the if statement is not met, then you will only stay checking the $counselor[0]->state.
You need a separate counter for when the if statement is met.
$i = 0;
$containsCount = 0;
while ($containsCount < 5 || !isset($counselor[$i])):
if ($counselor[$i]->state == $state || !$state):
// do stuff
++$containsCount;
endif;
++$i;
endwhile;
I've also added a bounds check by checking if the $counselor[$i] is null. (could also check $i < $arrayLength)

If your if statement is false the first time ($i = 0) it will never match...since $i always will be 0. The same goes for $i = 1, 2, 3 or 4. If any of those are false, the loop will be stuck. $i will never increase. You need another solution.

You increment $i only when the if statement returns true. If you take your $i++; out of the if statement the loop will always run exactly 5 times.
$i = 0;
while($i < 5):
if($counselor[$i]->state == $state || !$state):
// do stuff
endif;
$i++;
endwhile;

You have to exit $i++ of your if condition :
$i = 0;
while($i < 5):
if($counselor[$i]->state == $state || !$state):
// do stuff
endif;
$i++;
endwhile;

if the if() condition is not met 5 times, it will be infinite as the while() condition will never be met.
Instead of while statement, use a loop that matches the length of the array and it will end then when it reaches the end of the array.

Maybe you can try altering your if statement a bit like this :
$i = 0;
while($i < 5):
if($counselor[$i++]->state == $state || !$state):
// do stuff
endif;
endwhile;

Related

Could isset be used in a condition of a for loop?

I am trying to get rooms that are not written already to a residential apartment short: RA. So as long array_shift is dragging the rooms out of the array, the loop should count further and it have to check allRARooms if there are still some rooms left for me.
So is that ok to check for isset in a for condition?
for($i = 1; count($ra) <= $quantity && isset($this->allRARooms); $i++)
Yes you can set for loop terminating condition to whatever expression you like.
You can even skip it ! for example:
for ($i=0;;$i++) {
if ($i>10) break;
echo "$i\n";
}
Or maybe you want an everlasting loop with for? here it is :
for (;;) echo ++$x . "\n";
In essence you can skip whatever part in for loop you need
Condition optimization
Your condition count($ra) <= $quantity && isset($this->allRARooms) can be factored a bit.
In 99% cases it's enough of count($ra) <= $quantity && $this->allRARooms, because '',null,[] - all evaluates to false.
Further you should put allRARooms var check at first place, like:
$this->allRARooms && count($ra) <= $quantity. In that way you will employ a short-circuit evaluation trick for boosting condition check speed, because if var allRARooms is not set - count($ra) will not be evaluated - thus saving CPU ticks
Yes it is.
A for loop can be described as such : for (initialisation; alive condition; last loop statement)
it can be translated using a while loop that way :
initialisation
while (alive condition)
{
// some code
last loop statement
}
You put what you want as long as it respects the differents statements
for($i = 1; count($ra) <= $quantity && isset($this->allRARooms); $i++) { }
is equivalent to
$i = 1;
while (count($ra) <= $quantity && isset($this->allRARooms))
{
// some code
$i++;
}
You can add many initialisation and last instruction statements and the alive condition can be independant of them.
$aConditionIndependantOfInit = true;
for ($i = 0, $j = 42; $aConditionIndependantOfInit; $i++, $j--)
{
echo "foo\n";
if ($i >= $j)
$aConditionIndependantOfInit = false;
}
This output 21 foo

PHP even numbers generating

I'm somewhat new to PHP, been reading a few books and I've never seen a loop where it gets you all the even numbers(for example from 1 to 10), so I decided to try it myself:
for($i=0;$i<10 && $i % 2===0;$i++)
echo $i;
Tried with only double == as well.
And this,
$i=0;
do echo $i; while($i++<10 && $i % 2 ==0);
Can't seem to figure out how to use 2 conditions in the same statement.
Would appreciate the help!
Thanks.
Try to use this code
for( $i=0; $i<=10; $i++ )
{
if( $i%2 == 0 ){
echo $i;
}
}
The loop is breaking entirely when the second condition fails the first time. On the first iteration: 0 is less than 10, and it is even, so the loop iterates. On the second iteration: 1 is less than 10, but is odd, so the loop breaks.
Your code is the equivalent of this:
for($i=0; $i<10; $i++) {
if ($i % 2 !==0 ) {
break;
}
echo $i;
}
0
You can eliminate the second condition of your for loop to prevent the breakage and rely exclusive on a third expression to increment $i by two each iteration.
for($i=0; $i<10; $i = $i + 2) {
echo $i;
}
02468
The second statement in a for-loop is/are the condition(s) which gets checked every loop. so if it fails your loop stops. what you need will look somewhat like this:
for ($i = 0; $i < 10; $i++)
if ($i % 2 == 0)
echo $i;
So the loop will run over every number but only print out the even ones.
You don't need to loop.
Range can create a range with third parameter step 2.
$arr = range(0,20,2);
Echo implode(" ", $arr);
https://3v4l.org/S3JWV
you can use also regular loop and get the evens by formula:
for($i=0; $i<10 ;$i++) {
$j = $i * 2;
// do somthing with $j witch loop over 10 first evens...
}

Strange for loop syntax

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.

How can I loop through an array, starting at an offset and looping round again?

Newb question: I'm using a foreach loop to get items from an array.
I need to start looping at an offset number- (I'm using a $i variable to do this, no problem).
But when my foreach reaches the end of the array I want it to start going through the array again until it reaches the offset number.
I need to do this so I can have a user open any image in an artist's portfolio and have this image used as the first image presented in a grid of thumbnail icons , with all the other images subsequently populating the rest of the grid.
Any ideas?
Please bear in mind I'm new to PHP! :)
See below for an example of my current code...
$i=0;
$limit=50;// install this in the if conditional with the offset in it (below) to limit the number of thumbnails added to the page.
$offset=$any_arbitrary_link_dependant_integer;
foreach($portfolio_image_array as $k=>$image_obj){//$k = an integer counter, $image_obj = one of the many stored imageObject arrays.
$i++;
if ($i > $offset && $i < $limit) {// ignore all portfolio_array items below the offset number.
if ($img_obj->boolean_test_thing===true) {// OK as a way to test equivalency?
// do something
} else if ($img_obj->boolean_test_thing===false) { // Now add all the non-see_more small thumbnails:
// do something else
} else {
// error handler will go here.
}
} // end of offset conditional
}// end of add boolean_test_thing thumbnails foreach loop.
};// end of add thumbnails loop.
$i = 0;
$limit = 50;
$offset = $any_arbitrary_link_dependant_integer;
$count = count($portfolio_image_array);
foreach($portfolio_image_array as $k=>$image_obj){//$k = an integer counter, $image_obj = one of the many stored imageObject arrays.
$i++;
if ($i > $offset && $i < $limit && $i < ($count - $offset)) {// ignore all portfolio_array items below the offset number.
if ($img_obj->boolean_test_thing===true) {// OK as a way to test equivalency?
// do something
} else if ($img_obj->boolean_test_thing===false) { // Now add all the non-see_more small thumbnails:
// do something else
} else {
// error handler will go here.
}
} // end of offset conditional
}// end of add boolean_test_thing thumbnails foreach loop.
};
Only thing I added was a $count variable.
Edit: If your array starts at 0 I would suggest you put the $i++; at the end of your foreach loop.
A simple method is to use two separate numeric for loops, the first going from offset to end, and the second going from beginning to offset.
<?php
// Create an example array - ignore this line
$example = array(1,2,3,4,5,6);
$offset = 3;
// Standard loop stuff
$count = count($example);
for($i = $offset; $i < $count; $i++)
{
echo $example[$i]."<br />";
}
for($i = 0; $i < $offset; $i++)
{
echo $example[$i]."<br />";
}
?>
This is also almost certainly cheaper than doing multiple checks on every single element in the array, and it expresses exactly what you are trying to do to other programmers who look at this code - including yourself in 2 weeks time.
Edit: depending on the nature of the array, in order to use numeric keys you may first need to do $example = array_values($portfolio_image_array);.
Using Answer Question to force StackOverflow to let me post a decent length of text!
OK #Mark Walet et al, not sure how to post correctly on this forum yet but here goes. I got the issue sorted as follows:
$i=0;
$offset=$image_to_display_number;
$array_length = count($portfolio_image_array);
// FIRST HALF LOOP:
foreach($portfolio_image_array as $k=>$img_obj){// go through array from offset (chosen image) to end.
if ($i >= $offset && $i <= $array_length) {
echo write_thumbnails_fun($type_of_thumbnail, $image_path, $k, $i, $portfolio_image_array, $title, $image_original);
$t_total++;// update thumbnail total count.
}
$i++;
}// end of foreach loop 1.
$looped=true;// Just FYI.
$i=0;// Reset.
// SECOND HALF LOOP:
foreach($portfolio_image_array as $k=>$img_obj){// go through array from beginning to offset.
if ($i < $offset) {
echo write_thumbnails_fun($type_of_thumbnail, $image_path, $k, $i, $portfolio_image_array, $title, $image_original);
}
$i++;
}// end of foreach loop 2.
Thankyou so much for all the help!
:)
as #arkascha suggested use modulo operator
<?php
$example = array(1,2,3,4,5,6);
$count = count($example);
$offset = 3;
for($i = 0; $i < $count; $i++) {
$idx = ($offset + $i) % count
echo $example[$idx]."<br />";
}
?>

PHP Explode function. If function

Could someone help suggest in below php explode function, we are displaying script after 5th listing. How is it possible to display script exactly after 5th listing and 10th listing on a page which has more than 10 listings
We tried using
if ($i == 5 & $i== 10)
but it does not work
Below is original code - which displays script after 5th listing
<?php
$listings = explode("<hr/>", $list);
$numberOfListings = count($listings);
for($i = 0; $i < $numberOfListings; ++$i)
{
if ($i == 5)
{ ?>
<script> </script>
<?php }
echo $listings[$i] . "<hr/>";
}
?>
Edit
How is it like - if have to display a separate script on $i==9, could you advise.
Because $i starts at 0 (0 to 9 is 10, whilst 0 to 10 is 11). Try if ($i == 4 || $i== 9), with an or operator.
Also I would not use the && (the and operator), because it is unlikely $i will ever equal both 4 and 9. I'd suggest you read into Truth Tables (and maybe Propositional Calculus) because from seeing what you had tried originally, it would be helpful to understand how a truth table works.
(source: wlc.edu)
You can use the contine, continue is used within looping structures to skip the rest of the current loop iteration and continue execution at the condition evaluation and then the beginning of the next iteration.
$arr = range(0,9);
foreach($arr as $number) {
if($number < 5) {
continue;
}
print $number;
}
Ref: http://php.net/manual/en/control-structures.continue.php
Try using modulus operator
$listings = explode("<hr/>", $list);
$numberOfListings = count($listings);
for($i = 1; $i < $numberOfListings; ++$i)
{
if ($i%5 == 0)
{
echo "in";
?>
<script> </script>
<?php
}
echo $listings[$i-1] . "<hr/>";
}
Here we are looping from 1 and there for $i <= $numberOfListings
and while listing we will use $listings[$i-1]
DEMO CODE AT http://codepad.viper-7.com/lrTOgP

Categories