I try to listen for the value of a variable and execute some code if it has a specific value.
e.g. I execute the function element() inside a switch statement and I have to execute break if the value of $element is false.
At the moment I do it like this:
switch(strtolower($testcase)) {
case 'test':
$element = $sel->element("class name", "btn-primary", true);
if ($element == false) { break; }
$element->click("");
...
public function element($using, $value, $takeScreenshot=false, $customMessage="")
{
try {
$element = $this->driver->element($using, $value);
} catch(PHPWebDriver_UnhandledWebDriverError $exception) {
$msg = "<b>PHPWebDriver_UnhandledWebDriverError: $using</b> is "
. "not a valid value for the parameter <b>\$using</b>!";
if ($customMessage !== "") {
$msg = "<b>$customMessage</b><br>$msg";
}
$this->setMessage(1, $msg, $exception, $takeScreenshot, $value);
return false;
} catch(PHPWebDriver_NoSuchElementWebDriverError $exception) {
$msg = "<b>PHPWebDriver_NoSuchElementWebDriverError:</b> No "
. "Element with <b>'$using'</b> and value <b>'$value'</b> found !";
if ($customMessage !== "") {
$msg = "<b>$customMessage</b><br>$msg";
}
$this->setMessage(1, $msg, $exception, $takeScreenshot, $value);
return false;
}
return $element;
}
But I would like to simplify it so that the line if ($element == false) { break; } is not needed anymore. e.g.
switch(strtolower($testcase)) {
case 'test':
$element = $this->element("class name", "btn-primary", true);
$element->click("");
...
I tried to return break; but this failed. Is there another way? e.g. can I add an EventListener which executes break automatically in the switch case if the value of $element is false?
When building functions, it's usually best to design them to be de-coupled, not coupled. This means, element() shouldn't care about what is calling it.
Therefore, attempting to break a switch from within element() would be a bad programming design.
If element() should always stop execution when it hits a certain spot, regardless of what called it, you should consider throwing an exception. However, this won't simplify the code in your switch statement as you'd have to use try, catch blocks.
With that said, since PHP allows assignments in conditionals, you could simplify the code you have written as:
if ($element = $sel->element("class name", "btn-primary", true)) {
$element->click("");
}
Related
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 am trying to validate an input using a form, through the use of an if statement.
if (isset($_POST['weekly-rate']))
{
$weekly_rate = $_POST['weekly-rate'];
if(!isset($_POST['weekly-rate']))
{
$error_messages[]= 'Weekly rate was not set';
}
else
{
$weekly_rateOK = true;
}
}
else
{
$error_messages[] = 'Weekly rate was not set...';
}
When I run this it gives doesn't give me the output I want, which is Weekly rent was not set. Am I incorrect in thinking that
if(!isset($_POST['weekly-rate']))
{
$error_messages[]= 'Weekly rate was not set';`
Means, if an input is not set, run the error message, weekly rate was not set.
However all I receive is nothing
Your understanding of isset() is correct. However, the form always posts the field back to your backend code which triggers isset() to be true all the time. You may look at using empty() instead.
A simplified version would look like this
$weekly_rateOK = !empty($_POST['weekly-rate']);
if (!$weekly_rateOK) {
$error_messages[] = 'Weekly rate was not set...';
}
You may need to add an integer check if needed.
If you are using a text input/select with a name, then the input/select is always posted and is set, but with an empty string. If it is a checkbox or radio buttons, then they will be set only if the checkbox is checked or a radio button is selected.
I have written a sample validation function, inspired by Laravel. You can check it here, and extend it by adding additional cases:
function validate ($rule_bag, $input) {
$flag = true;
$error_bag = [];
foreach ($rule_bag as $item => $rules){
$rules = is_array($rules) ? $rules : array_filter(explode(',', $rules));
foreach($rules as $rule){
$rule = trim($rule);
switch(mb_strtolower(trim($rule))){
case 'required': {
// checking isset then empty to be compatible with php <= 5.4
if (!isset($input[$item]) || empty($input[$item]))
{
$flag = false;
!isset($error_bag[$item])?$error_bag[$item]=[]:null;
$error_bag[$item][] = $rule;
}
break;
}
default: {
if (isset($input[$item])){
try {
if (!preg_match($rule, $input[$item])){
$flag = false;
!isset($error_bag[$item])?$error_bag[$item]=[]:null;
!isset($error_bag[$item]['regex'])?$error_bag[$item]['regex']=[]:null;
$error_bag[$item]['regex'][] = $rule;
}
}
catch(Exception $e){
echo $e->getMessage();
}
}
}
}
}
}
return $flag ? $flag : $error_bag;
}
The code block below actually executes when the whole script is run. What is not clear to me is that method write only test for the case of if data is not written to file. then the Exception should be thrown. It does say that if $data exist and writeable then write to it.
public function write($data) {
if (#!fwrite($this->_fp, $data . "\n")) {
throw new Exception('Could not write to the file.');
}
}
What am used to is this :
if( condition is true ) {
echo 'Run Code';
} else {
echo 'Throw Exception';
}
or something like this
public function query($sql) {
$result = mysql_query($sql, $this->connection);
if(!$result){
die("Database Query Failed : ". mysql_error());
}
return $result;
}
How is this possible ?
as mentioned in here if(expr) evaluates the expr to its Boolean value.. which means that in your example when calling the write function, the fwrite function always gets executed and then if checkes if it returns a falsy or truthy value..
and from the doc fwrite() returns the number of bytes written, or FALSE on error. hence #!fwrite($this->_fp, $data . "\n") evaluates to true on error, and the exception is thrown
I'm not good at explaining such kind of things, but let's try :)
I think you misunderstood how a condition works.
Let's use a simple example
if($x == 1) {
echo 'Run Code';
} else {
echo 'Throw Exception';
}
The if and what you put inside are independant. A condition is just a statement that returns a boolean, and a if just tests a boolean (whatever returned it). So you could transform this example like this :
$is_x_equal_to_one = ($x == 1); // $is_x_equal_to_one now contains true or false
if($is_x_equal_to_one) {
echo 'Run Code';
} else {
echo 'Throw Exception';
}
The ! operator negates an expression. If it's true, it will return false, and if it's false, it will return true.
So you could revert your condition like this :
$is_x_equal_to_one = ($x == 1);
if(!$is_x_equal_to_one) {
echo 'Throw Exception';
} else {
echo 'Run Code';
}
Now what if you don't need to run any code and you just want to say that "something is broken" if $x is not equal to 1 ? The else statement is always optional :
$is_x_equal_to_one = ($x == 1);
if(!$is_x_equal_to_one) {
echo 'Throw Exception';
}
fwrite not only writes to a file, it also returns false if it didn't worked. If it works, it returns a positive integer. And positive integers are evaluated as true with PHP.
That means you can use it like that :
$is_write_successful = fwrite($this->_fp, $data . "\n");
if(!$is_write_successful) {
echo 'Throw Exception';
}
And finally, you can shorten this code by removing a useless temporary variable :
if(!fwrite($this->_fp, $data . "\n")) {
echo 'Throw Exception';
}
You can rewrite the if as this:
$returnValue = #fwrite($this->_fp, $data . "\n");
if (!$returnValue) {
So it will always execute the fwrite function.
The php manual states under 'Changelog for break':
5.4.0 Removed the ability to pass in variables (e.g., $num = 2; break $num;) as the numerical argument.
I have a function that copies a table with a tree structure to another table.
After copying each record, the function tests a relation to see if that record has more child records in the next "level" of the tree.
If child records are found, this same function is executed for each child record using a foreach() loop. If they also have child records, the process is repeated, etc. etc.
So the number of "branches" and "levels" in the table will determine how many foreach() loops will be executed. Since the user creates the records, I have no control over the number of "branches" and "levels" in the table.
If break cannot receive a variable any more (I cannot run "branch" and "level" counters any more) - how do you break out of ALL loops if an error occurs?
Scaled down example:
public function copyTreeModels($row, $id)
{
try
{
/* copy current record. */
$status == 'ok';
/* loop to this same function if $status == 'ok' and hasChildren */
if($status == 'ok')
{
If ($row['hasChildren'] == 'yes') // check relation
{
foreach($row['children'] as $child)
{
$this->copyTreeModels($child, $id);
}
}
}
else
{
// break;
throw new CDbException($message);
}
}
catch(CDbException $e)
{
$message .= $e->getMessage();
}
return($message);
}
Don't put try in the recursive function. You need a wrapper function around the whole thing that establishes the condition handler:
public function copyTreeModels($row, $id) {
try {
$this->copytreeModelsRecurse($row, $id);
}
catch(CDbException $e)
{
$message .= $e->getMessage();
}
return($message);
}
copyTreeModelsRecurse would then be your copyTreeModels function, but without the try/catch blocks.
The only thing I can think of is to set a variable which determines whether or not to break all.
An example (untested) is
$break_all = false;
foreach($values as $val) {
foreach($val as $val1) {
foreach($val1 as $val2) {
if($val2 == "xyz") {
$break_all = true;
}
if($break_all) break;
}
if($break_all) break;
}
if($break_all) break;
}
I'll agree with the fact it's not a pretty solution however.
Edit:
An alternative suggestion if the amount of nested loops to break; from is a variable amount is setting a counter and decrementing the break counter for each break, and only breaking if it is greater than 0:
$break_count = 0;
foreach($values as $val) {
foreach($val as $val1) {
foreach($val1 as $val2) {
if($val2 == "xyz") {
$break_count = 3;
}
if($break_count > 0) { $break_count--; break; }
}
if($break_count > 0) { $break_count--; break; }
}
if($break_count > 0) { $break_count--; break; }
}
This is a long shot question, but is there a way in php to exit an "if" statement and continue on to the "else" statement if an error occurs inside the if block?
example
if ($condition == "good")
{
//do method one
//error occurs during method one, need to exit and continue to else
}
else
{
//do method two
}
Of course it is possible to do a nested if inside the first if, but that seems hacky.
TIA
try {
//do method one
//error occurs during method one, need to exit and continue to else
if ($condition != "good") {
throw new Exception('foo');
}
} catch (Exception $e) {
//do method two
}
I would just use a function so you don't duplicate code:
if ($condition == "good") {
//do method one
//error occurs during method one
if($error == true) {
elsefunction();
}
} else {
elsefunction();
}
function elsefunction() {
//else code here
}
Should that be possible?
Anyway you might consider changing it to.
$error = "";
if ($condition == "good") {
if (/*errorhappens*/) { $error = "somerror"; }
}
if (($condition != "good") || ($error != "") ) {
//dostuff
}
You could modify methodOne() such that it returns true on success and false on error:
if($condition == "good" && methodOne()){
// Both $condition == "good" and methodOne() returned true
}else{
// Either $condition != "good" or methodOne() returned false
}
Assuming that methodOne returns false on error :
if !($condition == "good" && methodOne())
{
//do method two
}
you really need this? i think no... but you can hack..
do{
$repeat = false;
if ($condition == "good")
{
//do method one
$condition = "bad";
$repeat = true;
}
else
{
//do method two
}
}while( $ok ) ;
I advise on methods to separate...
I find using switches instead of if...else are handy for doing this: Omitting a break statement makes the switch fall through to the next case:
switch ($condition) {
case 'good':
try {
// method to handle good case.
break;
}
catch (Exception $e) {
// method to handle exception
// No break, so switch continues to default case.
}
default:
// 'else' method
// got here if condition wasn't good, or good method failed.
}
if ($condition == "good") {
try{
method_1();
}
catch(Exception $e){
method_2();
}
}
else {
method_2();
}
function method_2(){
//some statement
}