Why does clean code forbid else expression - php

I have this code in a function:
if ($route !== null) { // a route was found
$route->dispatch();
} else {
// show 404 page
$this->showErrorPage(404);
}
Now PHPmd gives an error:
The method run uses an else expression. Else is never necessary and
you can simplify the code to work without else.
Now I'm wondering if it really would be better code to avoid the else and just add a return statement to the if part?

PHPMD is expecting you to use an early return statement to avoid the else block. Something like the following.
function foo($access)
{
if ($access) {
return true;
}
return false;
}
You can suppress this warning by adding the following to your class doc block.
/**
* #SuppressWarnings(PHPMD.ElseExpression)
*/

You usually can rewrite the expression to use just an if and it does subjectively make the code more readable.
For example, this code will behave in the same way if showErrorPage breaks the execution of the code.
if ($route == null) {
$this->showErrorPage(404);
}
$route->dispatch();
If the content of your if statement does not break the execution, you could add a return
if ($route == null) {
$this->showErrorPage(404);
return;
}
$route->dispatch();
If you where inside a loop, you could skip that iteration using continue
foreach ($things as $thing ) {
if ($thing == null) {
//do stuff and skip loop iteration
continue;
}
//Things written from this point on act as "else"
}

I wouldn't worry about what PHPmd says , atleast in this case.
They probably meant for you to use the conditional operator because (in their opinion) its 'cleaner'.
$route !== null ? $route->dispatch() : $this->showErrorPage(404) ;

Remove the else block by ending the 404 producing branch:
if ($route === null) {
// show 404 page
$this->showErrorPage(404);
return;
}
// a route was found
$route->dispatch();

This answer is coming late, but another method you can get around that is by using else if. Because sometimes you cannot just return if some logic should follow.
Having your example
if ($route !== null) { // a route was found
$route->dispatch();
}
else if ($route === null) {
$this->showErrorPage(404);
}
$route->doSomething();

Related

How to apply the principles of CleanCode to the else expression in my code?

How we remove the unnecessary else condition form below code we have also keep the code which is inside else statement but I don't wants to use else statement.
public function execute(array $responses)
{
foreach ($responses as $response) {
if (!$response) {
$this->callbackSBDL = $this->taskSchema;
$this->generateTask();
} else {
$this->queueHandler->findCompleted($this->taskSchema['tag']);
}
}
}
I don't quite see why you would want to omit your else, but you could do something along these lines, with continue
public function execute(array $responses){
foreach ($responses as $response) {
//if response, do whatever you need to do, then continue to the next item in your list.
if($response){
$this->queueHandler->findCompleted($this->taskSchema['tag']);
continue;
}
//this will only run if response isn't true, because we explicitly check and then skip ahead if response is true
$this->callbackSBDL = $this->taskSchema;
$this->generateTask();
}
}
Personally, from a clean code standpoint, I'm of the opinion that if / else is more verbose and easily apparent to anyone reading the code what the objective and purpose is, whereas ternary operators or things like the above code require the reader to actually read all the steps in the code, and while it's still fairly simple to see the purpose, requires more effort to read and understand than the initial if / else.
You could determine course of action to take depending on all possible values the $response variable, and write an "if" statement to cover each. In your example, it looks like you only need to determine if $response is "falsey", so you could do...
public function execute(array $responses)
{
foreach ($responses as $response) {
if (!$response) {
$this->callbackSBDL = $this->taskSchema;
$this->generateTask();
}
if ($response) {
$this->queueHandler->findCompleted($this->taskSchema['tag']);
}
}
}
Personally, I'd prefer to explicitly state under what circumstances the first "if" statement should be executed, along the lines of.....
public function execute(array $responses)
{
foreach ($responses as $response) {
if (false === $response || null === $response || 0 === $response) {
$this->callbackSBDL = $this->taskSchema;
$this->generateTask();
}
if ($response) {
$this->queueHandler->findCompleted($this->taskSchema['tag']);
}
}
}
Of course, doing things this way means you have to ensure that your "if" statements cover every possible value for $response.

PHP create object inside it's own constructor

EDIT: Link to my first question. Might clear some things up.
PHP Get corresponding data, with default and error handling
I have a function that checks if a GET statement exists. If so, it passes the value to a other function that then selects a class based on the value of the GET statement.
explaining:
The url = Page=Contact
The GetFormVariable approves it, and the class Contact is selected and it will give back a string. This string is used as an object 'Content' that, as it says, creats the content of the page.
public function getFormVariable($value){
switch (strtoupper($_SERVER['REQUEST_METHOD'])) {
case 'GET':
if (isset($_GET[$value]) && $_GET[$value] != NULL) {
return $_GET[$value];
}
else{
return false;
}
break;
case 'POST':
if (isset($POST[$value]) && $POST[$value] != NULL) {
return $POST[$value];
}
else{
return false;
}
break;
default:
return false;
}
}
Now the question.
When there is no GET statement in the url. The GetFormVariable returns false. And this means there is nothing shown.
How do i give this constructor.
public function SetProperty ($prob, $val){
$this->$prob = $val;
}
The information to create the ContentHome.
SetProperty('Content', 'ContentHome');
Sorry for poor explanation, if anything is unclear please tell me so.
I'm suggesting we close this question as unclear what you're asking, but decided to throw some help on the provided code sample anyway...
You can strip this down dramatically, and since there's no context, the function can be static too.
static public function getFormVariable($value)
{
if($_SERVER['REQUEST_METHOD'] == 'GET' &&
isset($_GET[$value]) &&
!empty($_GET[$value]))
return $_GET[$value];
elseif($_SERVER['REQUEST_METHOD'] == 'POST' &&
isset($POST[$value]) &&
!empty($POST[$value]))
return $POST[$value];
return false;
}
Your original isset and != NULL checks were doing the same check. Maybe you want the empty() check as a third check, but look it up to be certain.
The question is unclear.
How you call getFormVariable? How you use SetProperty with the information getFormVariable provides?
As far as I understood, you mean this...
$var = getFormVariable(???);
if (false === $var)
{
SetProperty('Content', 'ContentHome');
} else {
SetProperty('var', $var);
}

Nested if statements, any possible way of cleaning?

I have checked a few other questions but they don't really give me the answer I expect..
My code is a like this..
private function handle()
{
if()
{
if(!condition)
{
if(!condition)
{
if(!condition)
{
if(!condition))
{
if(!condition)
{
if(!condition)
{
if(!condition)
{
if(!condition)
{
if(!condition)
{
code
}
return;
}
return;
}
return;
}
return;
}
return;
}
return;
}
return;
}
return;
}
return;
}
}
In my opinion it is readable but messy, sadly I haven't found really a way of making it look 'pretty'. Any ideas?
EDIT: Each return is different.
EDIT2: Gave an answer of my own, thanks everybody!
Conditions can be merged by a && operator..It works form left to right, which means, as soon as the any one starting from left fails, it stops evaluating the condition..
if($a) {
if($b) {
}
}
can be replaced by
if($a && $b) {
}
Use a variable check, or combine the conditions into fewer IF statements.
Variable check like so:
$execute = TRUE;
// Opposite of what you want, e.g. if you want $a only to be TRUE, do $a !== TRUE
if (condition) {
$execute = FALSE;
}
...
// If all the conditions were met, then everything is OK
if($execute === TRUE) {
// code
}else {
// return
}
Edit:
Variable check can be preferably to combining IF statements if you want more control on what returns, e.g. something specific happens if a certain condition fails, which combining conditions can not always allow for.
Like already posted use
if(condition1&&condition2){}
or if this will not work, you can also use function which stops as soon as a condition is true
function some(){
if(!conditon 1){return 0;}
if(condition 2) {return 1;}
}
this provides more power as second if works only if first doesn't satisfy.
You must choose based on your requirements. Sometimes though nested loops are unavoidable.
I thought it out and have found a nice way of doing it, basically I'll make a method for each basic condition, and I'll call them in an if statement with the bitwise AND operator (&), which don't short-circuit.
/**
* nonsql_condition - It means it doesn't check with the database
*
* sql_condition - It means it does check with the database.
*/
if(!$this->nonsql_condition() & !$this->nonsql_condition() & !$this->nonsql_condition() & !$this->nonsql_condition())
{
if(!$this->sql_condition())
{
return error;
}
if(!$this->sql_condition())
{
return error;
}
code;
}
This allows me to use fewer lines of code in my method, plus also not doing unnecessary queries to my database.

Breaking out of multiple functions (short circuiting) in PHP

I want to return multiple nested functions in PHP. It's possible to break out of multiple loops by adding a number after "break". Eg.
while(1)
while(1)
while(1)
break 3;
Can I do a circuit break while calling a sequence of functions?
Not that I know of, it's also not very healthy of a design, as the parent and grandparent functions in question will never know of the break. You should throw an exception and catch it on the parent, which in turn will throw an exception and catch it on the grandparent etc.
To "break" out of functions, you can use the return.
function somefunction()
{
return;
echo 'This will never get displayed';
}
Another solution would be to add a condition to each while.
while(1 && $isTrue)
while(1 && $isTrue)
while(1 && $isTrue)
$isTrue = false;
break;
Although I don't think this is a very clean approach.
As the manual states break is for loop only.
What I do in such cases is that have an exception return value(or object) and do value check on return value at every function return point to make sure that the situation is propagated or handled appropriately, be careful while doing recursions though, you might completely fold up the tree by mistake....btw if it is a simple exit on error kind of situation you can also use exceptions.
It's possible to return a special result from child functions that indicates a specific condition has been met. WordPress uses WP_Error and is_wp_error() for this sort of operation. Any number of nested functions can check to see if a called function returned an error state, and opt to pass that error up the chain rather than continue with processing.
Example:
function outer() {
$result = inner();
// pass failure back to parent
if( is_wp_error($result) ) {
return $result;
}
// other processing
return $final_result;
}
function inner() {
if( some_condition() ) {
// generate an error
return new WP_Error( 'code', 'message' );
}
return $other_result;
}
$result = outer();
// did we get an error?
if( is_wp_error($result) ) {
echo 'Something went wrong.';
} else {
echo $result;
}
Yes, you can very simply construct a "body-less" while() or if() block. Typically, you will see PSR-12 compliant PHP code using {} to bookend the body of the loop/condition block, but the body is not required. Writing a semicolon at the end of the line will be sufficient and your IDE will not complain about bad syntax.
Returning a truthy value from each function will be an adequate indicator that the following function is authorised for execution.
This will provide the "short circuit" functionality that is desired without creating nested control structures or passing variables into different scopes.
I'll demonstrate with a battery of generic functions:
function echo1T() {
echo "1";
return true;
}
function echo2T() {
echo "2";
return true;
}
function echo3T() {
echo "3";
return true;
}
function echo1F() {
echo "1";
return false;
}
function echo2F() {
echo "2";
return false;
}
function echo3F() {
echo "3";
return false;
}
Code: (Demo with more scenarios)
while (echo1T() && echo2F() && echo3T()); // outputs: 12
if (echo1T() && echo2F() && echo3T()); // outputs: 12
$return = echo1T() && echo2F() && echo3T(); // outputs: 12
var_export($return); // outputs false

Combine three "complex" PHP conditions in one perfect php snippet

I'm stuck in Drupal Panels / PHP Access plugins.
At least, now I found the three conditions to create my final snippet. the purpose of it is to return TRUE; if "condition1 is TRUE" OR "condition2 is TRUE" OR "condition3 is TRUE". I found a lot of similar questions, but the last condition force me to post here to find the right way to do this.
Condition 1:
// At least $view1->result has result.
$view1 = views_get_view('sp_onglet_videos');
$view1->set_display('views-tab-embed_1');
$output1 = $view1->preview();
if ($view1->result) {
return TRUE;
}
Condition 2 (same thing):
// At least $view2->result has result.
$view2 = views_get_view('sp_onglet_audio');
$view2->set_display('views-tab-default');
$output2 = $view2->preview();
if ($view2->result) {
return TRUE;
}
Condition 3 is more complex:
// Checks for content in the field field_txt_videos.
if (isset($contexts['argument_nid_1']->data-> field_txt_videos)) {
$field = $contexts['argument_nid_1']->data-> field_txt_videos;
if (is_null($field)) {
return FALSE;
}
if (is_array($field)) {
foreach ($field as $key => $val) {
if (is_array($val)) {
$field[$key] = array_filter($val);
}
}
$field = array_filter($field);
return count($field);
}
if (is_string($field) && trim($field) == '') {
return FALSE;
}
if ($field) {
return TRUE;
}
return FALSE;
}
I would like to have something clean (and functional) like this:
if ($view1->result && $view2->result && $field) {
return TRUE;
}
But it's to tricky for my php knowledge. Need a little help !
You want to save the result of the 3rd condition (into a variable) and use this result to run your final condition/query. But you can query the 3rd condition if it is a function.
It is better to properly space your code and use plenty of newlines.
However, PHP does have some pretty cool tricks to do assignment inside conditional statements.
if(($view1 = views_get_view('sp_onglet_videos')) AND $view1->set_display('views-tab-embed_1') AND ($output1 = $view1->preview()) AND $view1->result) return TRUE;
However, as you can see this code is a mess - don't do it unless your assignment is really small. Take this simple security check at the top of a PHP file:
<?php defined('BASE_PATH') OR die('Not Allowed');

Categories