Why this is not possible to accomplish?
foreach($arr as $k => $v)
{
if($condition) { $obj->myMethod() && continue; }
}
After $obj->myMethod() gets evaluated then the keyword continue is evaluated (executed), resulting in skipping the current iteration.
EDIT: i'm asking this because something like:
if($error) { $log->fatal('Something weird happened.') && continue; }
is single line and self-explanatory.
continue is a statement not an expression.
And never the twain shall meet.
You can't put a statement in an expression. (What would echo false && continue; print?)
Instead, use an if, which can contain statements.
You cannot evaluate continue as a condition. The continue keyword does not work the same way as in other languages. In PHP, depending on context continue and break can be somewhat synonymous, consider this construct:
<?php
switch ($months)
{
// start with vowels
case 'august':
break;
case 'april':
continue; // exactly the same as "break" !!!
default:
return 'OK';
}
throw new StartsWithVowelException('Months with vowels are creepy');
?>
While we are on the topic, the break and continue keywords have a feature in PHP that make them a bit more interesting and powerful than their peers in other languages.
Both can be given a numerical argument when used in a loop that indicates how many loops to continue through or break out of. For example, here is an example that restarts the execution of an outer loop from within an inner one::
<?php
//
// verify that each sub array contains the given value
//
$lowerval = strtolower($value);
foreach ($TwoDArray as $otherArray)
{
foreach ($otherArray as $value)
{
if (strtolower($value) == $lowerval)
{
// we found the value -- this one definitely has it.
continue 2;
}
}
// if we've reached here, then the inner loop doesn't have the
// value. ¡aiiee!
}
?>
Hope this helps you out with these 2 constructs, good-luck.
continue is a statement. In PHP a statement and an expression are two different things, statements cannot be evaluated because they do not by nature return true or false which is a requirement for evaluation in PHP.
In PHP you'd have to do something like:
if(test()) continue;
Related
I have 2 Foreach-Loops. One of them is nested inside the other, e.g.:
foreach(...){
foreach(...){
//if statement
}
}
Within the inner loop I got an if statement and if this statement returns true I want to break the inner loop and continue with the next outter loop. Is there any way to realize this? "break 2; " won't work as I need to continue with the outter loop.
Like with break, you can add a number to continue as well:
foreach(...) {
foreach(...) {
if (...)
continue 2;
}
// this will be skipped
}
From the docs:
continue accepts an optional numeric argument which tells it how many
levels of enclosing loops it should skip to the end of. The default
value is 1, thus skipping to the end of the current loop.
Per PHP documentation, the default is 1, which only breaks out of the immediately encapsulating control struct
break ends execution of the current for, foreach, while, do-while or
switch structure.
break accepts an optional numeric argument which tells it how many
nested enclosing structures are to be broken out of. The default value
is 1, only the immediate enclosing structure is broken out of.
For example, the below code:
<?php
foreach(array(1,2,3,4,5) as $num){
foreach(array('a', 'b') as $char){
if($char === 'b') {
break;
}
echo $char;
}
echo $num;
}
// Result: a1a2a3a4a5
It breaks before it prints 'b', but continues with the loop to 5.
I have a foreach loop inside another foreach loop as this code:
foreach($array1 as $uid => $somevalues) {
$status = true;
foreach($somevalues as $somevalue)
if(!isset($somevalue->$someothervalue))
$status = false;
if($status) {
$content .= "some content added";
$count++;
}
}
How it works
As you see I am looping through all entries in $array1. For each entry I loop through the contained $somevalues array to look for a certain condition (that $someothervalue exists there). Now, if this condition (that something isset) is not true then the $status changes to false.
Only if the $status is still true after all loops of the inner foreach, I wish some action to be made (some content added to a text string $content and a raised counter).
The goal
The arrays I'm working with can be quite large and I have been looking at the break and continue commands to try to skip unnecessary parts to improve the code and have the script running through fewer loops.
As you can see, if a loop from the inner foreach results in $status=false then we can stop it right there (no further loops here are necessary). The break is good for this to skip the rest of the forearch loops.
If this is the case then we can also skip the rest of the current outer loop from the outer foreach, since there will not be run any code now that $status is false. For this purpose the continue command would be useful to let us skip the rest of the current outer loop and go on to the next array row right away.
The question
I have been looking at the command lines break 2 and continue 2 e.g. that let you skip the current AND the outer loop (two steps up) with their respective results (either stopping the loop entirely or skipping the rest of current loop). They work as double break - as a "break break" - and as double continue - as a "continue continue" - respectively.
But here I need something like break continue instead, if you get my point. The first loop should break, the next should continue. I am trying to avoid reaching the if statement in the code if not necessary. The check is already made and it feels like doing an unnecessary double check.
I hope the question is clear. Is there a method for this purpose to double skip from within the inner foreach but with the effect of two different commands break continue?
"Flag" variables are mostly a code smell, and an indication that you actually should be using a function:
function all_valid($somevalues) {
foreach($somevalues as $somevalue)
if(!isset($somevalue->$someothervalue))
return false;
return true;
}
foreach($array1 as $uid => $somevalues) {
if(all_valid($somevalues) {
do stuff
If you're prepared to sacrifice readability for performance, then how about:
foreach($array1 as $uid => $somevalues) {
foreach($somevalues as $somevalue)
if(!isset($somevalue->$someothervalue))
goto next; // I don't believe I wrote this
$content .= "some content added";
$count++;
next:
}
Just use continue 2, it will 'break' out of the first loop and continue the outer loop.
foreach([1, 2, 3] as $i) {
echo $i . PHP_EOL;
foreach([4, 5, 6] as $ii) {
continue 2;
}
echo 'this will never print' . PHP_EOL;
}
Will print:
1
2
3
foreach($array1 as $uid => $somevalues) {
// Task of loop 1
foreach($somevalues as $somevalue){
// Task of loop 2
if(!isset($somevalue->$someothervalue))
{
continue 2;
break;
}
}
}
I am working on legacy code I have inherited and I have come across this code.
This Code works!
Ignore the variable names look at the { the first Condition opens but never closes the else has no open? it still works?
Is it continuing on both or only one condition and if one which one?
Why does it even work?
foreach($bla as $foo) {
if(condition) {
if(condition) {
// Do Something
}else
continue;
}
}
My assumption is that the inner condition will be using the else? but I am only assuming that because of this answer: Nested if-else behaviour without braces I cannot find a definitive answer for PHP
You may rephrase this code (with proper indentation usage):
foreach($bla as $foo) { // FOREACH
if(condition) { // IF#1
if(condition) { // IF#2
// Do Something
} else continue; // END IF#2
} // END IF#1
} // END FOREACH
Now answers on your questions:
Is it continuing on both or only one condition and if one which one?
It is continueing only if nested if() (IF#2) statement condition evaluated to false.
Why does it even work?
It works because if() allows syntax without brackets for simple operations. See example 1 at the manual. So nested if() closed exactly by continue operation with following delimiter ;.
Yes, the else applies to the inner condition. The code compiles because the else block has no opening brace, so the braces are still balanced. Here's the same code properly indented:
foreach($bla as $foo) {
if(condition) {
if(condition) {
// Do Something
}
else
continue;
}
}
Of course this is inconsistent and a very bad way to write this code.
Surely it means that if the first IF condition is true, it will then go to the second IF condition.
So the second IF condition will only be read if the first one is true.
foreach($bla as $foo) {
if(condition) {
if(condition) {
// Do Something
}else continue;
}
}
If the "else" (or if, for that matter) is a one-liner, it doesn't need braces. The "else" in question is continuing the inner "if".
I have a situation where when dealing with an object I generally use a foreach to loop through it like this:
foreach ($main_object as $key=>$small_object) {
...
}
However, I need to put a conditional in there like this:
foreach ($main_object as $key=>$small_object) {
if ($small_object->NAME == "whatever") {
// We found what we need, now see if he right time.
if ($small_object->TIME == $sought_time) {
// We have what we need, but how can we exit this foreach loop?
}
}
What is the elegant way to do this? It seems wasteful to have it keep looping through if it's found a match. Or is there another approach to do this that is better? Possibly using for instead of foreach?
From PHP documentation:
break ends execution of the current for, foreach, while, do-while or switch structure.
So yes, you can use it to get out of the foreach loop.
Use the break statement inside the if condition:
if ($small_object->TIME == $sought_time) {
break;
}
break statement will break out of the loop.
$count = 0;
......
..
..
..
..
......
if (++$count == 5) break;
Let's say I have this code:
if (md5($_POST[$foo['bar']]) == $somemd5) {
doSomethingWith(md5($_POST[$foo['bar']]);
}
I could shorten that down by doing:
$value = md5($_POST[$foo['bar']];
if ($value == $somemd5) {
doSomethingWith($value);
}
But is there any pre-set variable that contains the first or second condition of the current if? Like for instance:
if (md5($_POST[$foo['bar']]) == $somemd5) {
doSomethingWith($if1);
}
May be a unnecessary way of doing it, but I'm just wondering.
No, but since the assignment itself is an expression, you can use the assignment as the conditional expression for the if statement.
if (($value = md5(..)) == $somemd5) { ... }
In general, though, you'll want to avoid embedding assignments into conditional expressions:
The code is denser and therefore harder to read, with more nested parentheses.
Mixing = and == in the same expression is just asking for them to get mixed up.
Since the if is just using the result of an expression, you can't access parts of it.
Just store the results of the functions in a variable, like you wrote in your second snippet.
IMHO your 2nd example (quoting below in case someone edits the question) is just ok. You can obscure the code with some tricks, but for me this is the best. In more complicated cases this advise may not apply.
$value = md5($_POST[foo['bar']];
if ($value) == $somemd5) {
doSomethingWith($value);
}