So let's say I have an option page that will set $threshold as '1', '2', '3', '4', or '5'
I've got a form that submits/redirects differently based on that threshold (right now the threshold is set to three only, not changeable, so one, two, and three go to PAGE ONE and do FUNCTION ONE, while four and five got to PAGE TWO and do FUNCTION TWO.
I want people to be able to set their own threshold.
currently I have:
if($foo == 'five' || $foo == 'four' || $foo == 'three'){
//DO ALL THIS CRAZY STUFF
} else {
//DO ALL THIS OTHER STUFF
}
what I WANT is basically a threshold wrapped around that:
if($threshold == '5'){
if($foo == 'five'){
//DO ALL THIS CRAZY STUFF
} else {
//DO ALL THIS OTHER STUFF
}
} else if ($threshold =='4'){
if($foo =='five' || $foo == 'four')
if($foo == 'five'){
//DO ALL THIS CRAZY STUFF
} else {
//DO ALL THIS OTHER STUFF
}
}
etc. for 3, 2, and 1 as well.
Is there an easy way to do that? Like should I set the if/or statements as variables? like:
if($threshold == '5'){ $var = "$foo =='five'" }
else if($threshold == '4'){ $var = "$foo =='five' || $foo == 'four'" }
then do
if($var){
//DO ALL THIS CRAZY STUFF
} else {
//DO ALL THIS OTHER STUFF
}
??
I'm not quite sure the 'best approach' to this :/
I'm not really sure if, for different $threshold numbers and $foo combinations, you have different functions for each of them, or if you just want to know if $foo is located within the specified $threshold. I guess the latter is your goal:
// the map
$thresholds = array(
5 => array('five'),
4 => array('five','four'),
// etc
);
// dummy values
$threshold = 5;
$foo = "four";
// check values
if(array_key_exists($threshold,$thresholds)) {
if(in_array($foo, $thresholds[$threshold])) {
//DO ALL THIS CRAZY STUFF
}
else {
//DO ALL THIS OTHER STUFF
}
}
If you have to make complex decisions, based on multiple vars, a good strategie is to build a map.
A map is a multi dimension array and has a function name or a closure as a value. What you do is lookup what function to call based on the keys of the array.
Related
I have two (and sometimes) three variables which determine if I should run a specific code. The problem is that any of them can be true or false and sometimes this leads to messy codes.
For three variables, there are 8 possible scenarios that I have to check. Like this:
if($var_a && $var_b && $var_c) {
// Do this (A)
} else if(!$var_a && $var_b && $var_c) {
// Do this (B)
} else if($var_a && !$var_b && $var_c) {
// Do this (C)
} else if(!$var_a && !$var_b && $var_C) {
// Do this (D)
}
... and so on.
Is there any way to use nesting and make this code less messy? It gets confusing at times to keep track of so many possibilities.
It might be easier to understand what I am saying with an example of two variables.
if($var_a && $var_b) {
// Do this (A)
} else if($var_a && !$var_b) {
// Do this (B)
} else if(!$var_a && $var_b) {
// Do this (C)
}
Is there any way to combine these conditions together so that I don't have to use so many && and if else conditions? This will make things less confusing for me when I have to deal with three (may be more) variables.
I guess you should try something like lookup map with bitwise map, in your case, it can be something like this:
$bitOne = $var_a ? 1 : 0;
$bitTwo = $var_b ? 2 : 0;
$bitThree = $var_c ? 4 : 0;
$resultKey = $bitOne | $bitTwo | $bitThree;
$map = [
7 => function() { return 'All are true'; },
3 => function() { return 'var_a and var_b are true'; },
6 => function() { return 'var_b and var_c are true'; },
// and so on
];
$result = $map[$resultKey];
If you extract the common variable (or an arbitrary choice in this case), you can produce a more layered approach, although the combinations will still mount up and it looks more code, it should be clearer...
if($var_a) {
if(!$var_b) {
// $var_a && !$var_b
}
else {
// $var_a && $var_b
}
}
else {
if($var_b) {
// !$var_a && $var_b
}
}
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 made the script to do what is expected, so it work ok but there must be a more elegant way to achieve the same result. I know that using switch will make it look nicer but not sure if the result will be the same as the 'default:' behavior:
This is the section of the script i want to refactor:
foreach ($free_slots as $val) { // here i am looping through some time slots
$slot_out = $free_slots[$x][1];
$slot_in = $free_slots[$x][0];
$slot_hours = $slot_out - $slot_in;
// tasks
if ($slot_out != '00:00:00') {
// Here i call a function that do a mysql query and
// return the user active tasks
$result = tasks($deadline,$user);
$row_task = mysql_fetch_array($result);
// HERE IS THE UGLY PART <<<<<----------------
// the array will return a list of tasks where this current
// users involved, in some cases it may show active tasks
// for other users as the same task may be divided between
// users, like i start the task and you continue it, so for
// the records, user 1 and 2 are involved in the same task.
// The elseif conditions are to extract the info related
// to the current $user so if no condition apply i need
// to change function to return only unnasigned tasks.
// so the i need the first section of the elseif with the
// same conditions of the second section, that is where i
// actually take actions, just to be able to change of
// change of function in case no condition apply and insert
// tasks that are unassigned.
if ($row_task['condition1'] == 1 && etc...) {
} else if ($row_task['condition2'] == 1 && etc...) {
} else if ($row_task['condition3'] == 1 && etc...) {
} else if ($row_task['condition4'] == 1 && etc...) {
} else {
// in case no condition found i change function
// and overwrite the variables
$result = tasks($deadline,'');
$row_task = mysql_fetch_array($result);
}
if ($row_task['condition1'] == 1 && etc...) {
// insert into database
} else if ($row_task['condition2'] == 1 && etc...) {
// insert into database
} else if ($row_task['condition3'] == 1 && etc...) {
// insert into database
} else if ($row_task['condition4'] == 1 && etc...) {
} else {
echo 'nothing to insert</br>';
}
}
}
Basically i run the else if block twice just to be able to change of function in case nothing is found in the first loop and be able to allocate records unassigned.
I haven't changed the functionality of your code, but this is definitely a lot cleaner.
The main problem was that your logic for your if/else statements was confused. When you're writing:
if($a == 1){ } else if($b == 1){ } else if($c == 1){ }else{ //do something }
You're saying If a is 1 do nothing, if b is 1 do nothing, if c is 1 do nothing, but if all of those did nothing, do something when you can just say if a is not 1 and b is not 1 and c is not 1, do something.
I wasn't too sure on your second if statements, but generally it's not good to have an if else with no body within it. However, if the "insert into database" comment does the same thing, you can merge the 3 if statements that do the same code.
I hope i've cleared a few things up for you.
Here's what I ended up with:
foreach ($free_slots as $val) { // here i am looping through some time slots
$slot_out = $free_slots[$x][1];
$slot_in = $free_slots[$x][0];
$slot_hours = $slot_out - $slot_in;
// tasks
if ($slot_out != '00:00:00') {
$result = tasks($deadline, $user);
$row_task = mysql_fetch_array($result);
if (!($row_task['condition1'] == 1 || $row_task['condition2'] == 1 || $row_task['condition3'] == 1 || $row_task['condition4'] == 1)) {
$result = tasks($deadline,'');
$row_task = mysql_fetch_array($result);
}
if ($row_task['condition1'] == 1 && etc...) {
// insert into database
} else if ($row_task['condition2'] == 1) {
// insert into database
} else if ($row_task['condition3'] == 1) {
// insert into database
} else if ($row_task['condition4'] == 1) {
} else {
echo 'nothing to insert</br>';
}
}
}
I am using the following code to pass a variable. if variable = a, do nothing.
I then want to check if variable = a, do nothing, if b, do nothing, else do something
<?
if($_GET['pageid'] == 'a'){
} else {
include('header_image.php');
}
?>
Above is the code I have working correctly for one vartiable.
How do I add an if / else?
if($_GET['pageid'] != 'a' && $_GET['pageid'] != 'b'){
//do smth
}
This is a comment - i want the formatting...
To do what you want:
if ($_GET['pageid'] == 'a') {
// do nothing for now
}
elseif ($_GET['pageid'] == 'b') {
// do some more nothing...
}
else { // we do something...
include('header_image.php');
}
You could combine the 'do nothing' tests as:
if ( $_GET['pageid'] == 'a'
|| $_GET['pageid'] == 'b') {
// do nothing for now
}
else { // we do something...
include('header_image.php');
}
I agree it reads better than the 'not equal and' tests. However, that is what 'programmers' use so it is worthwhile getting used to it.
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++;
}