PHP - Using a variable condition in a do-while loop? - php

I'm wanting to set the condition of a do-while loop with a variable. Here's my code...
$ans_type = mt_rand(1, 2);
if ($ans_type == 1){
$condition = '$work_b != $c';
$symbol = '=';
$final_note = '1';
} else {
$condition = '$work_b == $c';
$symbol = '≠';
$final_note = '2';
}
do{
$a = mt_rand(-25, 25);
$b = mt_rand(-25, 25);
$c = mt_rand(-25, 25);
$d = mt_rand(-25, 25);
if($op_1 == '–'){
$work_b = $b * -1;
} else {
$work_b = $b;
}
if($op_2 == '–'){
$work_d = $d * -1;
} else {
$work_d = $d;
}
} while ($a == 0 || $b == 0 || $c == 0 || $d == 0 || $condition);
Note the $condition variable that I want to put in the while() part of the loop. This produces an infinite loop though.
So, is there a way to use variables as conditions in loops?

You can use variables as conditions, however the reason your code produces an infinite loop is because you are not changing $condition within your while loop. Therefore, if $condition evaluates to true once, it will keep evaluating to true (as it never changes in your code).

What you're trying to do can be better achieved by using normal variables:
if( blah ) {
$conditionstate = false;
} else {
$conditionstate = true;
}
...
} while( ... || ($work_b == $c) == $conditionstate );
If you have more varied conditions, maybe a restructure is in order. If there really is no way to restructure it, I'm hesitant to suggest it, because so many people misuse it to terrible consequences, but eval does what you're looking for and can be safe (if not fast) if used carefully. Needing to use it is usually a sign that your program has a bad structure though.
p.s. These types of random number generation problems are much better solved with code like this:
$a = mt_rand(-25, 24);
if( $a >= 0 ) {
++ $a;
}
// $a is -25 to 25, but never 0
$b = mt_rand(-25, 23);
if( $b >= min( $a, 0 ) ) {
++ $b;
}
if( $b >= max( $a, 0 ) ) {
++ $b;
}
// $b is -25 to 25, but never 0 or a
That can be made more elegant, but you get the idea. No need to loop at all, and guaranteed to halt.

$ans_type = mt_rand(1, 2);
if ($ans_type == 1){
$condition = ($work_b != $c);
$symbol = '=';
$final_note = '1';
} else {
$condition = ($work_b == $c);
$symbol = '≠';
$final_note = '2';
}
You are passing $condition as a string. Just save the $condition variable as a boolean.

Related

PHP - Check if more than one condition is true in a given number of conditions

Is there an elegant way to check if multiple, but not all, conditions are true out of any given number of conditions?
For example, I have three variables: $a, $b, and $c.
I want to check that any two of these are true. So the following would pass:
$a = true;
$b = false;
$c = true;
But this wouldn't:
$a = false;
$b = false;
$c = true;
Also, I may want to check if 4 out of 7 conditions were true, for example.
I realise I can check each combination, but this would get more difficult as the number of conditions increased. Looping through the conditions and keeping a tally is the best option I can think of, but I thought there may be a different way to do this.
Thanks!
Edit: Thanks for all the great answers, they're much appreciated.
Just to throw a spanner in to the works, what if the variables weren't explicit booleans?
E.g.
($a == 2)
($b != "cheese")
($c !== false)
($d instanceof SomeClass)
A "true" boolean in PHP casts to a 1 as an integer, and "false" casts to 0. Hence:
echo $a + $b +$c;
...will output 2 if two out of the three boolean variables $a, $b or $c are true. (Adding the values will implicitly convert them to integers.)
This will also work with functions like array_sum(), so for example:
echo array_sum([true == false, 'cheese' == 'cheese', 5 == 5, 'moon' == 'green cheese']);
...will output 2.
You could put your variables in an array, and use array_filter() and count() to check the number of true values:
$a = true;
$b = false;
$c = true;
if (count(array_filter(array($a, $b, $c))) == 2) {
echo "Success";
};
I'd go for a method like the following:
if (evaluate(a, b, c))
{
do stuff;
}
boolean evaluate(boolean a, boolean b, boolean c)
{
return a ? (b || c) : (b && c);
}
What it says is:
If a is True, then one of b or c must be true too to comply with 2/3
True criterion.
Else, both b and c must be true!
If you want to expand and customise the conditions and the number of variables I'd go for for a solution like the following:
$a = true;
$b = true;
$c = true;
$d = false;
$e = false;
$f = true;
$condition = 4/7;
$bools = array($a, $b, $c, $d, $e, $f);
$eval = count(array_filter($bools)) / sizeof($bools);
print_r($eval / $condition >= 1 ? true : false);
Simply we evaluate the true's and we make sure that the % of True is equals or is better than what we want to achieve. Likewise you could manipulate the final evaluation expression to achieve what you want.
This should also work, and would allow you fairly easily to adjust to the numbers.
$a = array('soap','soap');
$b = array('cake','sponge');
$c = array(true,true);
$d = array(5,5);
$e = false;
$f = array(true,true);
$g = array(false,true);
$pass = 4;
$ar = array($a,$b,$c,$d,$e,$f,$g);
var_dump(trueornot($ar,$pass));
function trueornot($number,$pass = 2){
$store = array();
foreach($number as $test){
if(is_array($test)){
if($test[0] === $test[1]){
$store[] = 1;
}
}else{
if(!empty($test)){
$store[] = 1;
}
}
if(count($store) >= $pass){
return TRUE;
}
}
return false;
}
U can use while loop :
$condition_n = "x number"; // number of required true conditions
$conditions = "x number"; // number of conditions
$loop = "1";
$condition = "0";
while($loop <= $conditions)
{
// check if condition is true
// if condition is true : $condition = $condition + 1;
// $loop = $loop + 1;
}
if($condition >= $condition_n)
{
// conditions is True
}
else
{
// conditions is false
}
I think it is a little easy and short writing when you use operator "&" , "|" like this:
$a = true;
$b = true;
$c = false;
$isTrue = $a&$b | $b&$c | $c&$a;
print_r( $isTrue );
Let check by your self :D

What's a good structure for an edit function in which all parameters are optionals?

Let's get it simple, a table with three parameters (A, B and C). A is the key and is not editable, but B and C can be modified.
What's the best way of defining an editing function? Because what I have so far is...
function edit($b, $c){
if {($b != "") && ($c != "")){
update($b, $c);
}elseif ($b != ""){
update($b);
}elseif ($c != ""){
update($c);
else {
die("Anything to edit")
}
}
In this case it's not kind of a big deal, but what if instead of two parameters there are 10 optional parameters? I'm pretty sure there must be some better way of defining such function.
I would run a loop on the value array (not sure how you are getting the values)
<?php
$a = "A";
$b = "B";
$c = "C";
$d = "D";
$e = "E";
$param = [$b, $c, $e];
foreach($param as $value){
// If $variable isset and not empty
if(isset($value) && !empty($value)){
echo ($value."<br/>");
// update($value);
}
}
?>

Elegant way to shorten if statement

Any ideas how to shorten if statment in an elegant way.
My if statement:
if(getfoo1() == getfoo2() && getfoo2() == 1)
{
}
EDIT:
I'm looking for something like:
if(getfoo1() == getfoo2() ==1)
{
}
But I suppose we can't do this.
$a = getfoo1();
$b = getfoo2(); // less operations, while it not produces duplicate calls
if($a == $b && $b == 1){
// do something
}
$variable = ((getfoo1() == getfoo2() && getfoo2() == 1) ? $value1 : $value2);
More elegant, combined:
$a = getfoo1();
$b = getfoo2();
$variable = (($a == $b && $b == 1) ? $value1 : $value2);
Since we don't know the possible return values from the functions, if you assume they are integers then you can say:
$a = getfoo1();
$b = getfoo2();
if (($a * $b) === 1) { // strict equality for the win
echo 'hi';
}
The result would only be true iff both $a AND $b are 1.
Another way:
$both = array(getfoo1(), getfoo2());
// use array_diff_assoc so it checks multiple occurrences of the same value
$diffCount = count(array_diff_assoc($both, array(1, 1)));
if ($diffCount === 0) {
echo 'hi';
}
Since anyway getfoo2() == 1 must be true, a better approach is to first check whether getfoo2() is equal to 1. If it false no matter about 2nd condition. But If you first check getfoo1() == getfoo2() and and then check getfoo2() == 1 you have to check 2 conditions all the times.
Therefore go for
$a = getfoo1();
$b = getfoo2();
if($b == 1 && $a == $b)
{
// logiv
}
else
{
}
Try this.
$a = getfoo1();
$b = getfoo2();
if( intval($a && $b) === 1) {
echo 'hi';
}

IF condition: Passing first assigned variable as a parameter of a function on second condition

I want to do something like this:
if( $a = 'something' && $b = substr( $a, 2 ) )
{
//do something
}
I mean, on an if condition, evaluate two conditions, and the second one passing the first assigned $a as a parameter to the second condition function substr().
It is just an example, so I don't want answers to this functionality, just generic answers.
The above code throws 'Undefined' $a, since $a is not still assigned.
I could do the next:
if( $a = 'something')
{
if( $b = substr( $a, 2 ) )
//do something
}
}
but this will make my code bigger.
Is there any way to achieve something like the first example?
Edit:
I don't want to compare. Just assign and ensure that $a and $b are not null, false, ...
Your only problem is the wrong precedence of the && and = operators. This works just fine:
if (($a = 'something') && $b = substr($a, 2))
This way, $a is undefined:
if ($a = 'something' && $b = substr($a, 2))
But if you give the = operator priority:
if (($a = 'something') && $b = substr($a, 2))
It will be set.
Moreover, you can simply write:
if( $b = substr( $a = 'something', 2 ) )
This question intrigued me along with #moonwave99 answer, so I did some testing with his last answer.
if( $b = substr( $a = NULL, 2 ) ) { echo "PASS"; } else { echo "FAIL"; }
FAIL
if( $b = substr( $a = FALSE, 2 ) ) { echo "PASS"; } else { echo "FAIL"; }
FAIL
if( $b = substr( $a = 0, 2 ) ) { echo "PASS"; } else { echo "FAIL"; }
FAIL
if( $b = substr( $a = TRUE, 2 ) ) { echo "PASS"; } else { echo "FAIL"; }
FAIL
if( $b = substr( $a = 233, 2 ) ) { echo "PASS"; } else { echo "FAIL"; }
PASS
if( $b = substr( $a = "SOMETHING", 2 ) ) { echo "PASS"; } else { echo "FAIL"; }
PASS
The only way to get it to fail was to pass the Boolean TRUE. But if you are expecting string values, it should fail all Boolean values, zero and NULL and evaluate to true on ints, floats, and string values. (Haven't tested with array, but I suspect it would fail for any non-primitive types). Interesting question.
Use isset() for that.Also keep in mind use == or === for comparison operations since = is assignment operator
if( (isset($a) && $a == 'something') && (isset($b) && $b == substr( $a, 2 )) )
{
//do something
}

Can I string along functions in an if statement and return a single variable?

I'm curious if it's possible to string along a couple possibilities for a function in an if statement, link them to a single variable and return the one that works, if any.
The following doesn't work, but it demonstrates the idea. I'd like the below to return 2 since the function myFn() only returns true when 2 is passed to it.
But instead the following returns true: 1.
if ($b = myFn(1) || $b = myFn(2) || $b = myFn(3)) {
echo 'true: ' . $b;
} else {
echo 'false: ' . $b;
}
function myFn($a) {
if ($a == 2) return $a;
return false;
}
Short of adding a series of elseifs, is there a way to string the functions in a series of ORs while only returning the successful one?
codepad: http://codepad.org/ldiCxY4j
Just wrap each assignment in parenthesis:
(($b = myFn(1)) || ($b = myFn(2)) || ($b = myFn(3)))
See: PHP operator precedence
When using logical operators, PHP coerces the result to boolean. Without the extra parens, it echoes '1' because echoing coerces true to '1'.
You may be better off using a loop:
/**
* Get the first $array value that passes the $test, or else null.
* #return mixed|null
*/
function find ($array, $test) {
foreach ($array as $index => $value) {
if (call_user_func($test, $value, $index, $array))
return $value;
}
}
For such concatenations of assignments PHP has the or operator, which is the same as || but with less precedence than =. This means that
if ($b = myFn(1) or $b = myFn(2) or $b = myFn(3))
is treated like:
if (($b = myFn(1)) or ($b = myFn(2)) or ($b = myFn(3)))
while
if ($b = myFn(1) || $b = myFn(2) || $b = myFn(3))
is treated like:
if ($b = (myFn(1) || $b = (myFn(2) || $b = myFn(3))))

Categories