for() loop fails to stop looping ? - php

I'm trying to print an array until it's empty.
Here is my code:
for ($i=0; $array[0][$i]!=NULL; ++$i){
echo $array[0][$i];
}
However it looks like it performs the echo one extra time, I don't know why ?
Here's my output for an array that contains data up to array[0][2].
I am sure that array[0][3] is empty, I tried it with if(array[0][3]==NULL)
Test 0
Test 1
Test 2
( ! ) Notice: Undefined offset: 3 in C:\... on line 9
Any idea ?

You should use the arrays length when you loop... Or try this instead:
foreach($array[0] as $val) {
echo $val;
}

It makes perfect sense, really. PHP can not magically know that the next id (in your example, index number '3') is not set, it has to access the variable to determine that. That's also why you get the notice.
In short, it does not execute the body of the for loop, but it has to execute the test to determine whether or not to continue.
Anyway, use a foreach loop, or calculate the number of items in the array first and increment $i till they match.

Possible alternatives to you code that should actually work.
foreach($array[0] as $val)
if($val===null)
break;
else
echo $val;
or
$arrlen=count($array[0]);
for($i=0;$i<$arrlen;$i++)
if($array[0][$i]===null)
break;
else
echo $array[0][$i];
or even
$i=0;
while($array[0][$i]!==null) { //not recommended, can cause infinite loop
echo $array[0][$i];
$i++;
}

The reason why it's throwing an error is because an array index that does not exist is not equal to NULL. You can modify your code to this:
for ($i=0; isset($array[0][$i]); ++$i){
echo $array[0][$i];
}
Or try this instead:
$ctr = count($array[0]);
for ($i = 0; $i < $ctr; $i++) {
echo $array[0][$i];
}
The loop should finish after reaching the end of the array.

Related

What does this for-loop mean?

I've stumbled upon a syntax in a code example I have never seen in for-loops before in PHP.
What does this do? WHY should I use this?
for(;$i<$max;){
$i++;
//code..
}
I could figure out that it was not the same as
for($i=0;$i<$max;$i++) {
//code...
}
I don't understand the difference between the two examples above.
If for being more specific about my thoughts.
If we have this code (taken from a solution from adventofcode):https://www.reddit.com/r/adventofcode/comments/kdf85p/2020_day_15_solutions/
<?php
$cap = 2020;
$bits = [5,1,9,18,13,8,0];
$i=0;
$time = [];
foreach($bits as $bit) {
$i++;
$time[$bit] = $i;
$say = 0;
}
for(;$i<$cap-1;){
$i++;
if(isset($time[$say])) {
$last = $time[$say];
}
else {
$last = $i;
}
$time[$say] = $i;
$say = $i - $last;
}
echo $say;
?>
and compare that to:
<?php
$cap = 2020;
$bits = [5,1,9,18,13,8,0];
$i=0;
$time = [];
foreach($bits as $bit) {
$i++;
$time[$bit] = $i;
$say = 0;
}
for($i=0;$i<$cap-1;$i++){
if(isset($time[$say])) {
$last = $time[$say];
}
else {
$last = $i;
}
$time[$say] = $i;
$say = $i - $last;
}
echo $say;
?>
I get different results in $say.(376 in first example and 38 in last example).
Why do I get different values?
Well based on the PHP docs:
https://www.php.net/manual/en/control-structures.for.php
for loops are the most complex loops in PHP. They behave like their C
counterparts. The syntax of a for loop is:
for (expr1; expr2; expr3)
statement
While:
Each of the expressions can be empty or contain multiple expressions
separated by commas.
So it's just a way to "save code" when your first expression of the for-loop is "obvious", So instead of mentioning the default obvious expression - you just "skip" it.
According to your example:
for(;$i<$cap-1;)
we skipped the first expression (expr1) as $i has been already defined as 0 ($i = 0;) earlier in the code block so it's "skippable". Doesn't affect the code.
But, The third expression:
At the end of each iteration, expr3 is evaluated (executed).
Since we don't mention it in the loop, we are responsible to handle the "increasement" (in this case) of $i in the loop itself.
However - the main difference in the code is that if you mention the third expression - it's evaluated at the end of each iteration but in the code block (your example) - we increase the $i variable at the beginning of the code.
The main difference between the two blocks (assuming $i is initialised to 0 before the for(;$i<$max;){ loop) is that the first loop increments $i before running the loop code, where the second loop increments $i after running the loop code. As a trivial example:
function code($i) {
echo "$i\n";
}
$max = 3;
$i = 0;
for(;$i<$max;){
$i++;
code($i);
}
for($i=0;$i<$max;$i++) {
code($i);
}
The output of the first loop is:
1
2
3
while the output of the second loop is:
0
1
2
Note (as pointed out by #IMSoP), the condition clause is executed at the beginning of the loop, and can have side-effects, so you could also emulate the first loop with this code:
for($i=0;$i++<$max;) {
code($i);
}
C-style for loops are a rather peculiar piece of syntax. They actually consist of three expressions, any of which can do anything you like, or even be empty:
An expression to execute for its side effects once before the loop begins
An expression to evaluate at the beginning of each iteration, to see if the loop should terminate
An expression to execute for its side effects at the end of each iteration
The most common way to use them is:
Initialise a counter of some sort
Check if the counter has reached some value
Increment or decrement the counter
But those aren't built into the language at all, and leaving one of the expressions out doesn't apply any default behaviour, it just does nothing - except that leaving the second expression empty always evaluates to true.
So, for instance:
for(;true;) is an infinite loop: it does nothing, checks true, and does nothing again
for(;;) is the same infinite loop, because the empty expression in the middle is considered true
for($i=0;;) is just the same infinite loop, but with $i initialised to 0 before running it
for(;true;foo()) is the same loop, but with the function foo() run at the end of every iteration
In your case, the loop is for(;$i<$max;) which breaks down to:
Before starting the loop, do nothing
At the beginning of each iteration, terminate if the expression $i<$max happens to be false
At the end of each iteration, do nothing
It doesn't do anything to control what values $i and $max have before or during the loop.
In fact, it's just the same as while($i<$max) and would probably be much clearer if written that way.
The example shown seems to have ended up that way because the author wanted to move the $i++ to the beginning of each iteration, rather than the end (although why they also left out the $i=0 I'm not sure). But the for syntax supports that too! You can actually include multiple expressions with a comma between in any of the three positions; if they're in the second position, the last one is what determines if the loop exits.
So you can do this:
for($i=0; $i++,$i<=$max; )
Now, $i will be incremented at the beginning of the loop; since it will be incremented before the test, you have to also adjust the condition from < to <= to make sure it runs for one more iteration.
For that particular case, there's another way as well: incrementing a variable returns a value. If you write ++$i it returns the value after incrementing, and if you write $i++ it returns the value before incrementing. So both of these would also work:
for($i=0; ++$i <= 10; ) echo $i, PHP_EOL;
for($i=0; $i++ < 10; ) echo $i, PHP_EOL;
In your first example, $i is registered somewhere before. so $i can be 0 or other zero, because if you use code like
for(;$i<$max;){
$i++;
//code..
}
you got error Undefined variable $i in and later $i is registered.
/* example 1 */
for ($i = 1; $i <= 10; $i++) {
echo $i;
}
/* example 2 */
for ($i = 1; ; $i++) {
if ($i > 10) {
break;
}
echo $i;
}
/* example 3 */
$i = 1;
for (; ; ) {
if ($i > 10) {
break;
}
echo $i;
$i++;
}
https://www.php.net/manual/en/control-structures.for.php
what is your point?

$_POST array sometimes skips numbers and IF statement ends

I can not figure out how to print all $_POST array items (ending in successive numbers) if one or more numbers do not exist. Not sure how to explain this... For example..
$i = 1;
while( isset($options['item_code'.$i]) )
{
echo $options['item_code'.$i];
$i++;
}
This code works fine as long as the numbers continue to exist in order...
item_code, item_code1, item_code2, item_code3, etc...
But once a number is removed, the if statement stops and the rest of the values are not printed. For example...
item_code, item_code1, item_code3, etc...
Will stop at "item_code1" because item_code2 does not exist.
I've tried solutions given to similar questions here on stackoverflow but they either do not work, do the same thing, or create a continuous loop.
I would appreciate any help that someone can give me here.
you are doing it in wrong way. Please update your code like this. replace $i<=4 with number of element you want to trace
$key = end(array_keys($options));
$dataa = explode('item_code',$key);
$count = $dataa[1];
$i = 1;
while( $i <= $count )
{
if(isset($options['item_code'.$i])){
echo $options['item_code'.$i];
}
$i++;
}
I guess it can be done with an array_filter and strpos functions:
<?php
$codes = array_filter($options, function ($key) {
return strpos($key, 'item_code') === 0;
}, ARRAY_FILTER_USE_KEY);
foreach ($codes as $code) {
echo $code . PHP_EOL;
}
Instead of while use foreach like
foreach($options as $option){
echo $value;
}

Issue with getting data when traversing through an array PHP with a variable

I asked a similar question earlier but I couldn't get a clear answer to my issue. I have a function "isParent" that gets 2 pieces of data. Each 1 of the 2 gets a string separating each value with a , or it just gets a plain int and then checks if the first value given is a parent of the second.
I pull the 2 bits of data in and explode them but when I go through my nested for loop and try to test
$toss = $arr1[$i];
print_r($toss);
It comes up blank. I have no idea what the issue is: Here is the full code of the function...
function isParent($parent, $child)
{
$parentArr = explode(',', $parent);
$childArr = explode(',',$child);
//Explode by Comma here. If array length of EITHER parentArr or childArr > 1 Then throw to an Else
if(count($parentArr) <= 1 && count($childArr) <= 1) //If explode of either is > 1 then ELSE
{
$loop = get_highest_slot(15);
for($i = $loop; $i > 0; $i--)
{
$temp = get_membership_from_slot($i,'id_parent','id_child');
if($temp['id_parent'] == $parent && $temp['id_child'] == $child)
{
return 1;
}
}
}
else //set up a for loop in here so that you traverse each parentArr value and for each iteration check all child values
{
$i = count($parentArr);
$c = count($childArr);
for(;$i >=0;$i--) //Loop through every parent
{
for(;$c >=0;$c--)
{
echo '<br>$i = ';
print_r($i);
echo '<br><br>Parent Arr at $i:';
$toss = $parentArr[$i];
echo $toss;
echo '<br>';
print_r($childArr);
echo '<br><br>';
if(isParent($parentArr[$i],$childArr[$c])) //THIS CAUSES AN INFINITE YES! Learn how to pull an array from slot
{
return 1;
}
}
}
}
return 0;
}
You are missing some code for the slot procedures. Apart from that, you probably need to use a different variable for the inner for loop. because $c will be 0 after the first iteration of $i.
Thanks for the help! The issue was in the recursive call back to the top of the function. It was tossed empty slots and when comparing 2 empty slots it returned a false positive. A quick !empty() check fixed it.

What's the wrong on my for statement; getting undefined offset?

I keep getting undefined offset.. what would be the problem with this?
for($m=0; $m<=count($data); $m++){ // (this is where it points)
if(date("m-Y",strtotime($data['data'][$i]['date_d'])) == $curdate)
$sum.$cmonth +=1;
else
$sum.$cmonth = 0;
}
That is because , adding a <= will make your loop iterate till the non-existent index of the array. , Rewrite like this.
for($i=0; $i<count($data); $i++){ // (this is where it points)
if(date("m-Y",strtotime($data['data'][$i]['date_d'])) == $curdate)
$sum.$cmonth +=1;
else
$sum.$cmonth = 0;
}
I recommend a foreach instead.
foreach($data as $k=>$v)
{
}
I see your array to be multidimensional and you are running the loop on second index so do like
for($m=0; $m<count($data['data']); $m++){
This will consider the length of the array(if there is any) named data inside the $data variable.
And change your $i to $m(if you are trying to traverse that array usinf the loop) like
if(date("m-Y",strtotime($data['data'][$m]['date_d'])) == $curdate)

Looping through an explode() in php weird output

I'm getting a very weird results when trying to loop through a comma delimited list in PHP.
It sometimes only outputs a few of them and there seems no logical reason to why it doesn't loop through all of them, and I can't for the life of me figure out what's actually causing it.
My code is:
//pids = &pids=1,2,3,6,7,9
$pids = $_GET['pids'];
$photoIdArray = explode(",", $pids);
for($i = 0; $i <= count($photoIdArray); $i++) {
foreach($photoIdArray as $j){
if($i == $j){
echo "{$j}";
}
}
}
// result = 1236
This is just for testing so there is im not checking the inputs to prevent exploits and what not at the moment.
Any help would be appreciated.
Thanks!
Combining 2 loop for and foreach is overkill for something like this
Try using only foreach
$pids = "1,2,3,6,7,9";
$photoIdArray = explode(",", $pids);
foreach($photoIdArray as $value)
{
echo $value;
}
Output
123679
It is because you are looping through your values and check if $i is the same as the value. You should check
if ($photoIdArray[$i] == $j) {
instead of
if ($i == $j) {
This is the reason it didn't work, but you should still use Baba's method.
I agree with Dusan, Baba & Co., but to answer the actual question:
Nothing weird happens here. i loops from 0 to 6 (though the array has only indices 0..5), and you compare i with the VALUES of the array, which range from 1 to 9. Of course, only the values 1 to 6 are matched, because i never exceeds 6.
EDIT: Asad and Sietse were faster.

Categories