Let's take a look at the following code:
if ($a == 1) {
echo "this is stage 1";
}
else if ($a == 2) {
echo "this is stage 2";
}
else if ($a == 3) {
$a = 1;
// at this point I want something that restarts the if-else construct so
// that the output will be "this is stage 1"
}
I'm working on an if else construct at the moment and let's say that I have three stages and the if-else construct checks which stage I'm in.
Now it happens that some activities in stage 3 lead to a jump back to stage 1. Now I've already passed the code for stage one, which is why I want to somehow restart the if-else construct. Is there a way to do that? And even more important: Is there a better way to do what I want? Because my idea doesn't seem to be good practice.
You're right, it's bad practice.
You're asking for goto.
Example:
<?php
goto a;
echo 'Foo';
a:
echo 'Bar';
The above would never output 'Foo'
It's difficult to suggest the better method without seeing exactly what you're trying to do, but consider a switch.
switch ($a) {
case 3:
// Execute 3 stuff
// No break so it'll continue to 1
case 1:
// Execute 1 stuff
break // Don't go any further
case 2:
// 2 stuff
break;
}
That's probably not what you want either.
You may just want to abstract the code into functions and call them multiple times if necessary.
You can put an endless loop around your if and break out if you're done
while (1) {
if ($a == 1) {
echo "this is stage 1";
break;
}
else if ($a == 2) {
echo "this is stage 2";
break;
}
else if ($a == 3) {
$a = 1;
}
else {
break;
}
}
Maybe you want to look at Wikipedia - Finite-state machine and this question PHP state machine framework
The short answer is yes, there is a way, but the better answer is yes to your second question as well.
Put, at very least, the code that can get called from multiple locations in a function. For example,
function stageOneCode() {
//do stuff;
}
etc.. I would recommend a function for each stage, but it's hard to make recommendations without actually seeing what's being executed in the stages.
In any event, at the end of your stage three function, simply call your stage one function.
A recursive function is helpful for this (but maybe overkill if it will always revert back to 1)
function echo_stage($stage) {
if ($a == 1) {
return "this is stage 1";
}
else if ($a == 2) {
return "this is stage 2";
}
return echo_stage(1);
}
echo echo_stage(5);
Or:
switch ($number)
{
case 2 :
echo "this is stage 2";
break;
case 1:
default:
echo "this is stage 1"
}
use switch(). you can have a "default" case as well as specific cases.
A loop is what you are searching for:
// initialize $a
$a = 1;
// the while loop will return endless
while (true);
// if you want to break for any reason use the
// break statement:
// if ($whatever) {
// break;
// }
if ($a == 1) {
echo "this is stage 1";
}
else if ($a == 2) {
echo "this is stage 2";
}
else if ($a == 3) {
$a = 1;
// continue will go back to the head
// of the loop (step 1) early:
continue;
}
// don't forget to increment $a in every loop
$a++;
}
Related
I am in the making of some code that needs to check if a users login details are correct, and I therefore need a lot of if-statements inside each other. If any of the conditions in the if-statements are not true, they should alle return the same value. Is there an easy way of doing this, instead of writing the same multiple times? I have made an example below to visualize my problem. As you can see here I write " else { return false; }" multiple time, and this is what I am wondering if you are able to do more efficiently. Maybe so I only have to write "or else return false" once.
//some code
if (/*some condition*/) {
//some code
if (/*some new condition*/) {
//some code
if (/*some new condition*/) {
//some code
} else {
return false;
}
} else {
return false;
}
} else {
return false;
}
I am having a hard time finding a good way to explain my problem, so if you have a more elegant way of explaining it, do not hesitate to edit my post. I am also not quite sure that the title is as good as it could be, so if you have any ideas to an alternativ please say so :)
Lets say you have something like that (I added No):
if ( condition1 ) {
//some code 1
if ( condition2 ) {
//some code 2
if ( condition3 ) {
//some code 3
} else {
return false;
}
} else {
return false;
}
} else {
return false;
}
Since each time a condition is false, you exit the function returning false, you can directly test if the condition is false using a negation (if the negated condition is true):
if ( !condition1 ) {
return false;
}
//some code 1
if ( !condition2 ) {
return false;
}
//some code 2
if ( !condition3 ) {
return false;
}
//some code 3
This doesn't reduce the number of if statements, but you avoid many nesting levels and the else statements.
You can also try the switch statement. For many situations it will produce cleaner code.
<?php
if ($i == 0) {
echo "i equals 0";
} elseif ($i == 1) {
echo "i equals 1";
} elseif ($i == 2) {
echo "i equals 2";
}
switch ($i) {
case 0:
echo "i equals 0";
break;
case 1:
echo "i equals 1";
break;
case 2:
echo "i equals 2";
break;
}
?>
The switch statement is also compatible with using strings:
<?php
switch ($i) {
case "apple":
echo "i is apple";
break;
case "bar":
echo "i is bar";
break;
case "cake":
echo "i is cake";
break;
}
?>
Good luck! :)
in PHP (and even other languages but in the present case this is more for PHP), i often end up sometimes having to code long conditions such as the example below:
i have a code with many conditions and i want to display a different result based on certain conditions.
if something is RED and the other thing is RED, then print X,
if something is RED but the other thing is BLACK, then print Y
if something RED and the other thing is RED but a third thing is blue, then print X
& so on
is there a way to properly handle this by using some kind of data structure/configuration array/matrix/whatever ? that is, storing these "conditions" and "results" properly in some kind of configuration array or other ?
instead of having to code nested conditions that can be tricky to support afterwards
like this very small example but in a much bigger scale
if (preg_match(/something/, $string) {
$result = 'GREEN';
} elseif (preg_match(/something/, $string) {
$result = 'RED';
} else {
if (something else) {
$result = 'GREEN';
} else {
if (something OR something) {
$result = 'AMBER';
} else {
$result = 'GREEN';
}
}
}
or is it the only way of handling this ?
maybe with a single
if (something and something or something) {
} elseif (something and something and something) {
} elseif (something and something or something and something) {
} etc
thank you for your help
i'm coding an app that should display a different "status" for a certain data depending on many different data (other attributes of this data), and i'd like to avoid having unreadable code
You can use nested arrays:
$conditions = [
'/something1/' => [
'/something2/' => "X"
],
'thing3' => [
'/thing3/' => 'Y',
'/thing4/' => 'Z'
]
];
$matched = false;
foreach ($conditions as $key1 => $val1) {
if (preg_match($key1, $string)) {
if (is_array($val1)) {
foreach ($val1 as $key2 => $val2) {
if (preg_match($key2, $string)) {
$result = $val2;
$matched = true;
break;
}
}
} else {
$result = $val1;
$matched = true;
}
}
if ($matched) {
break;
}
}
if (!$matched) {
$result = 'default';
}
To allow arbitrary levels of nesting you could turn this into a recursive function.
For the purposes of the answer below I'm assuming you're coding OO PHP.
One variable
When I have one variable that determines the outcome, if the variable is boolean or close to being boolean (meaning it can only either be one or two different values), is to use an if() statement like you have. If the variable can be a variety of (known) values, like your colours example, I use a switch() function.
Two or more variables
If I have two variables that determine the outcome, for instance colour and size, I first use a switch(), then for each switch, I use a method that contains another switch().
It may be more verbose, but it is so much easier to keep track of in the long run. Below is a simplified example of the logic.
switch ($colour) {
case 'red':
red_handler($size);
break;
case 'green':
green_handler($size);
break;
case 'blue':
blue_handler($size);
break;
}
/** We already know the first variable value is red */
function red_handler($size)
{
switch ($size) {
case 'small':
echo "my fruit is a cherry";
break;
case 'medium':
echo "my fruit is an apple";
break;
case 'large':
echo "my fruit is a watermelon";
break;
}
}
In a similar vein to #dearsina i'd tend to separate it out into functions for this kind of thing, for example if you know there are lots of cases where it could return the same value, e.g.:
if(isGreen($string)) return 'GREEN';
else if (isRed($string)) return 'RED';
function isGreen($string) {
if(cond1)return true;
if(cond2 && cond3)return true;
if(cond4 || cond 5)return true;
return false;
}
function isRed($string) {
if(cond6)return true;
if(cond1 && cond7)return true;
if(cond2 || cond 8)return true;
return false;
}
we do sometimes use the style you've suggested...
if (something and something or something) {
} else if (something and something and something) {
but you can quickly end up back in the same problems of readability and maintenance issues
I have a large switch statement in my code, and I want it to do something like this:
// assign $foo
switch ($foo) {
case 1:
case 2:
// do X, then break if 1, do Y and break if 2
case 3:
case 4:
case 5:
// do A & B, break if 3, do C if 4 or 5, do D if 5 and then break
}
Such "groups" are prevalent throughout the switch statement and currently I just repeat the logic, keeping each case separate.
Am I wrong in assuming that this could be restructured into something that's objectively "better"?
Edit: I excluded my original code snippet from the question, since it had deeply flawed logic and didn't conform to the basic concepts of using a switch, replacing it with pseudocode that resembles the desired result.
As commented, that switch doesn't actually work as you think.
You're simply looking for:
if (in_array($foo, [1, 2])) {
...
if ($foo == 2) {
...
}
}
Alternatively:
switch ($foo) {
case 1:
case 2:
...
if ($foo == 2) {
...
}
break;
}
TLDR;
For simple "is it this", use a switch, if you need logical checks, use an if
The answer;
What you are asking is quite subjective, while using a switch for something simple is good, i.e;
<?php
$case = getCaseFrom("X"); // Let's say this = "a"
switch ($case)
{
case "a" : {
$thing = "a";
break;
}
case "b" : {
$thing = "b";
break;
}
case "c" : {
$thing = "c";
break;
}
default : {
$thing = "d";
}
}
?>
The same could be achieved by using;
<?php
$case = getCaseFrom("x");
$thing = $case;
// And even shorter;
$thing = getCaseFrom("x");
?>
Whereas, if you needed some logic to this...
<?php
$operator = getOperatorFrom("X"); // In this case, add
$num1 = 10;
$num2 = 2;
switch ($operator)
{
case "add" : {
$res = num1 + num2;
break;
}
case "subtract" : {
$res = num1 - num2;
break;
}
case "multiply" : {
$res = num1 * num2;
break;
}
case "divide" : {
$res = num1 / num2;
break;
}
}
?>
The alternative;
And of course, all of the above switches case be done using if else clauses, but a switch (IMO) is a neater, and more readable approach depending on what your certain criteria are (see the drawbacks).
The easiest way to look at it is;
If you need to check if something matches a value, use an if, if it is an enumerated set of values (let's say 1 to 4), a switch is subjectively better
The drawbacks;
A switch also doesn't let you have multiple "and" checks in the same statement, for example;
<?php
$case = getCaseFrom("X"); // In this case, a (does not have "b")
switch ($case)
{
case "a" :
case "b" : {
// This checks for a or b, not both, despite this not containing "b"
// this will still be accessed
break;
}
case "c" : {
// This will not be used as the break stops
// it from falling through to this clause
break;
}
}
if (stristr("a", $case) && stristr("b", $case))
{
// This checks to see if case contains a AND b
// therefore, this will not be used, as this
// does not have both a and b in $case
}
else if (stristr("a", $case) || stristr("b", $case))
{
// This checks to see if case contains a OR b
// therefore, this will be used, as this
// is checking that $case has "a" or "b" in it
// This is the same as the switch in this instance as it uses "or"
}
The noteworthy;
To be aware of the following also would be useful;
Inside a switches case, you cannot use login, for example;
case getThing("a") :
would cause an error
NB: Of course, when using the case statements, you don't need the curly braces added, they are mainly for code folding and ease of reading
The function for the primes is clear, so I omitted it.
$a=10;
$z=30;
for($prime = $a; $prime<$z; $prime++)
{ if
(Prim($prime) == TRUE)
{ echo $prime."<br/>";}}
Now I want to select the next term of the sequence as well, in order to perform an operation between the variable $prime and $next_prime, as long as the loop goes on - like for example:
$prime_gap=bcsub($next_prime, $prime);
Whatever solutions I find and I try, it's never the proper one. It's surely very simple but I am already desperate.
I would suggest you start by creating a next_prime() function. Like this, for example:
function next_prime($n) {
do {
$n++;
} while (!Prim($n));
return $n;
}
Then you can refactor your code quite easily:
$a=10;
$z=30;
for ($p1=next_prime($a),$p2=next_prime($p1); $p2<$z; $p1=$p2,$p2=next_prime($p2)) {
if (some_function($p1, $p2)) {
echo "I like $p1 and $p2\n";
}
}
The if I add in the for loop is not so nice, but if you want something simple and easy to understand, you can still use it (I switch the name from $prime & $next_prime to $prime & $previous_prime, I think it makes more sense)
$a=10;
$z=30;
$previous_prime = 0;
for($prime = $a; $prime<$z; $prime++)
{
if (Prim($prime) == TRUE)
{
echo $prime."<br/>";
if ($previous_prime == 0) {
$previous_prime = $prime
} else
{
$prime_gap = $prime - $previous_prime;
$previous_prime = $prime;
}
}
}
no idea how to ask this question... the problem is that I need to stop the loop from runing if if ($current[$id][$i]['item'] == '') is true, so whatever the script needs to do or in this case echo, don't get repeated 15 times.
If using exit; the whole page will stop to render, so, any ideas ?
Thanks in advance.
If the question is not clear enough don't hesitate to ask using the comments, I will more than happy to clarify any doubts.
$i=1;
while($i<=15) {
if ($current[$id][$i]['item'] == '') {
echo 'Done!.';
//do something
}
$a++;
}
use break
$i=1;
while($i<=15) {
if ($current[$id][$i]['item'] == '') {
echo 'Done!.';
break;
}
$i++; //<- that should probably be $i instead of $a?
}
How about using the break control structure?
You need to break. Also, your current loop is endless and will therefore time-out. Presumably you meant to increment $i, not $a.
$i=1;
while($i<=15) {
if ($current[$id][$i]['item'] == '') {
echo 'Done!.';
break; //<-- terminate loop
}
$a++; //<-- shouldn't this be $i++?
}
There is only 2 ways to break a loop... using exit; and break;....
break; is what you want it will exit the loop and continue execution, exit will end the script.
$i=1;
while($i<=15) {
if ($current[$id][$i]['item'] == '') {
echo 'Done!.';
break; // or you can make value of $i = 20;
}
$a++;
}