Related
I am refactoring an extensive codebase overtime. In the long run we are going to develop the whole system in classes but in the mean time I am using the opportunity to refine my PHP skills and improve some of the legacy code we use across several hundred websites.
I have read conflicting articles over time about how best to return data from a custom function, generally the debate falls into two categories, those concerned about best technical practice and those concerned about ease of reading and presentation.
I am interesting in opinions (with elaboration) on what you consider best practice when returning from a custom PHP function.
I am undecided as to which of the following as a better standard to follow using this basic theoretical function for example;
Approach a.
Populating a return variable and returning it at the end of the function:
<?php
function theoreticalFunction( $var )
{
$return = '';
if( $something > $somethingelse ){
$return = true;
}else{
$return = false;
}
return $return;
}
?>
Approach b.
Returning at each endpoint:
<?php
function theoreticalFunction( $var )
{
if( $something > $somethingelse ){
return true;
}else{
return false;
}
}
?>
A possible duplicate could have been What is the PHP best practice for using functions that return true or false? however this is not limited to simply true or false despite my basic example above.
I have looked through the PSR guidelines but didn't see anything (but I may have missed it so please feel free to point me to PSR with reference :) ).
Extending the original question:
Is the method used to return different depending on the expected/desired output type?
Does this method change depending on the use of procedural or object oriented programming methods? As this question shows, object orientation brings in its own eccentricities to further extend the possible formatting/presentation options Best practices for returns methods in PHP
Please try to be clear in your explanations, I am interested in WHY you choose your preferred method and what, if anything, made you choose it over another method.
I tend towards early returns - leave the function as soon as you know what is going on. One type of this use if called a 'Guard Clause'
Other things I will often do include dropping final else for a default:
if ($something > $somethingelse) {
return true;
}
return false;
and in fact, conditions of the form if (boolean) return true; else return false, can be shortened even further (if it is clearer to you) to just return ($something > $somethingelse);. Extracting a complex if clause from code like this to a usefully named function can help clear up the meaning of code a lot.
There are people arguing for single exit points in functions (only one return at the end), and others that argue for fail/return early. It's simply a matter of opinion and readability/comprehensibility on a case-by-case basis. There is hardly any objective technical answer.
The reality is that it's simply not something that can be prescribed dogmatically. Some algorithms are better expressed as A and others work better as B.
In your specific case neither is "best"; your code should be written as:
return $something > $somethingelse;
That would hopefully serve as example that there's simply no such thing as a generally applicable rule.
I know this question is old but the it is interesting and according to me
there are many things to say about it.
The first thing to say is that there is no real standard about returning in functions or methods.
It's usually ruled by the rules your team has decided to follow, but if you are the only one on this refactoring you can do what you think better.
In the case of returning a value the important thing I guess is
readability. Sometimes it's better to loose a little bit
of performance for a code that is more readable and maintainable.
I will try to show some examples with pros and cons.
Approach A
<?php
function getTariableType($var = null)
{
if (null === $var) {
return 0;
} elseif (is_string($var)) {
return 1;
} else {
return -1;
}
}
Pros:
Explicitness. Each case explains itself, even without any comments.
Structure. There is a branch for each case, every case is delimited clearly
and it's easy to add a statement for a new case.
Cons:
Readability. All these if..else with brackets make the code hard to read and
we really have to pay attention to every part to understand.
Not required code. The last else statement is not required and the code would be
easier to read if the return -1 was only the last statement of the function,
outside of any else.
Approach B
<?php
function isTheVariableNull($var)
{
return (null === $var);
}
Pros:
Readability. The code is easy to read and understand, at the first look we
know that the function is checking whether the variable is null.
Conciseness. There is only one statement and in this case it's fine and clear.
Cons:
Limit. This notation is limited to really little funtions. Using this notation
or even ternary operator becomes harder to understand in more complicated
functions.
Approach C.1
<?php
function doingSomethingIfNotNullAndPositive($var)
{
if (null !== $var) {
if (0 < $var) {
//Doing something
} else {
return 0;
}
} else {
return -1;
}
}
Pros:
Explicitness. Each case is explicit we can reconstruct the logic of the
function when reading it.
Cons:
Readability. When adding many if..else statements the code is really less
readable. The code is then indented many times looks dirty. Imagine the code
with six nested if.
Difficulty to add code. Because the logic seems complex (even if it is not),
it's difficult to add code or logic into the function.
Plenty of logic. If you have many if..else nested it is perhaps because you
should create a second function. NetBeans IDE for example suggests you to create
an other function that handles the logic of all your nested blocks. A function
should be atomic, it should do only one thing. If it does too much work, has
too much logic, it's hard to maintain and understand. Creating an other function
may be a good option.
Approach C.2
This approch aims to present an alternative to the C.1 notation.
<?php
function doingSomethingIfNotNullAndPositive($var)
{
if (null === $var) {
return -1;
} elseif (0 >= $var) {
return 0;
}
//Doing something
}
Pros:
Readability. This notation is very readable. It's
easy to understand what result we will get according to a given value.
Explicitness. As C.1, this approach is explicit in every branch of the
condition.
Cons:
Difficulty to add logic. If the function becomes a bit more complicated,
adding logic would be difficult because we may need to move all the branches of the
condition.
Approach D
<?php
function kindOfStrlen($var)
{
$return = -1;
if (is_string($var)) {
$return = strlen($var);
}
return $return;
}
Pros:
Default value. In this structure we can see that the default value is handled
from the beginning. We have logic in our function, but if we enter in no
branch we have a value anyway.
Ease to add logic. If we need to add a branch if it's easy and it does not
change the structure of the function.
Const:
Not required variable. In this case the $return variable is not required, we
would write the same function without using it. The solution would be to
return -1 at the end, and return strlen($var) in the if, and it would not
be less readable.
Conclusion
I have not listed all the possible notation here, only some of them. What we can
think about them is there is no perfect one, but in some cases an approach seems
better that an other. For example an is_null function would be fine with the
approach B.
Using an approach or an other is really up to you, the important thing is to
choose a logic and to keep it during all your project.
Using the approach b is more fine with me because in approach a you have written very few lines of code, but if there are many lines of code and many return statements, then are chances that i will somewhere use the wrong return type, where $return was assigned a some other place and i did not notice that.
I prever variant b. Not only is it more readable ( you know exactly that you do not need to consider any of the remaining code after a return statement), but it is also more failsafe.
If you either have a bug in the remaining code, or you encounter a set of conditions you did not take into account when designing the system, it would be possible that your result is changed. This cannot happen when you exit the function with return [$someVariable];
<?php
function theoreticalFunction( $var )
{
if( $something > $somethingelse ){
return true;
}
return false;
}
?>
This approach can also be used as on RETURN Statement, the program cursor is returned back and the next statement will not be executed.
I'm sorry the title of this question is odd. I couldn't find a good way to word it!
The idea is simple, sometimes you see PHP tests this way:
if (!a_function("something")) { }
Here you can think of it as "if not true". I sometimes see the exact same thing but with extra parenz:
if (!(a_function("something"))) { }
Why does it require the extra parenz after the bang? Don't they both essentially mean if (!true)?
For extra bonus, what are the reasons for the two styles (does this have a name?) and maybe give examples of how they would give alternate results if not used correctly.
update:
Here is an example in a PHP script I'm using, the author is testing environment variables and seems to use the styles interchangeably:
if (!(extension_loaded("iconv"))) { ... }
if (!(extension_loaded("xml"))) { ... }
if (!function_exists("json_encode")) { ... }
if (!ini_get("short_open_tag")) { ... }
I know you can't answer for the programmer here, but why would they be alternating the use of extra parenz when these small functions are right next to each other?
I happen to know that, for example, the return value of ini_get is just the number 1, and the return value of the extension_loaded functions may also just be the number 1, so it seems like there would be no difference. I'm not 100% sure there isn't some other trick to this than simple preference or order of operation.
update 2:
I understand parenz can be used for either clarity, or order of operations, but I'm not convinced it is only personal preference beyond that.
In my example above, everything depends on what is returned by the functions that are being tested.
It's my understanding that by wrapping a statement in parenz, PHP will force it into a bool. But when it's not in parenz, could there be a return value that breaks the code without using the parenz around it to force a bool?
If people say, in my example code above, that there is nothing but personal preference going on, then I'll just have to accept that, but I have my doubts.
the parenthesizes are used in case if there are more than 1 logical operator with different precedence, to indicate that "!" operator must be applied after all other operators have been processed. For example:
if(!($var1 < $var2))
First will be checked if $var1 is less than $var2, and after that will be checked if the result is false.
If use that:
if(!$var1 < $var2)
then firstly will be checked if $var1 is false and the result will be compared to $var2, that simply do not make sense.
It's not required. It's a matter of personal preference. Sometimes you like to have extra parens to be EXTRA certain of how the expression will be evaluated.
if(a or b and c)
is confusing.
if ((a or b) and c)
is much more clear.
if(a or (b and c))
is much more clear.
They both work, but some people might have different opinions on which one is more readable.
Parenthesis are not required in the given case, but they can be if, for example, you also assign a variable at the same time :
if (($myVar = myFunc()) !== false) {
// Doing something with $myVar, ONLY if $var is not false
}
While, in the following case, it will change the logic
if ($myVar = myFunc() !== false) {
// Here $myVar = true or false instead of the wanted value
}
if( !(should_return_trueA() && should_return_trueB())) {
// at least one have returned false
}
esentially is the same as:
if( !should_return_trueA() || !should_return_trueB() ) {
// at least one have returned false
}
It's, in my case, a practice to avoid mistaken/ommited exclamation marks. Useful, when building more complex conditions and looking for all-false or all-true result.
when I use some nested if / else statements, sometimes I get confused if my code logic corresponds to my original idea. I use some simple procedural code, so how can I train my understanding?
Try to split your code up into functions. If you have deeply nested if/else statements then you can probably create well-named functions for both the "if" tests and the resulting logic. For example, change:
if ($something == "a" && $somethingElse == "b") {
// code
}
else if ($whatever > 4) {
// more code
}
else {
// yet more code
}
to
if (condition1True()) {
handleCondition1();
}
else if (condition2True()) {
handleCondition2();
}
else {
handleDefaultCondition();
}
Making your code read more like English means you can more easily understand how it works. You can also split your functionality so that each function only needs to do something simple then compose those functions into higher-level behaviour.
EDIT: Regarding comments, I tend to go for well-named functions and variables rather than copious commenting. If you can read the code without comments then that's ideal, but obviously you will still need comments sometimes. Definitely worth writing Javadoc-style comments for each function detailing the meanings of the arguments and return value, but inline comments in the code are sometimes more hindrance than help.
Comments! Write your original ideas in comments above each if/else block, and then make sure the conditionals for each block match the pseudo code you outlined in the comment. If they do, go back after you're done an re-read the comments - if the logic in them still seems valid, then there's a good chance your code will be good to go. I find it much easier to read comments outlining what a conditional does than to decipher each conditional on the fly. Of course, that means keeping comments up to date as well.
One of the best programmers I've ever met stubbed out functions with comments detailing how the function was supposed to work. He could read it back in plain English to make sure it made sense, and then implementation was, as he said, a simple matter of translation. This may not be for everyone, but it may help you keep focused.
Simplify complex conditionals and inner logic with appropriate function calls. Refactor you code to make it more clear, into small chunks. Use switch statements if appropriate, polymorphism if dealing with similar objects, etc.
Seeing some sample code would help give a more appropriate example, but consider the following contrived example:
if($a.isAnimal && $a.animalIsAlive){
if($a.isDog){
if(!$a.hasHadWalk && date('h') > 6 && date('h') < 20){
getLeash();
attachLeashToCollar();
putOnShoes();
...
}else{
//doNotWalk
}
}else{
//some other stuff here
}
}
could be refactored into
if(canBreathe($a)){
if($a.isDog){
if(shouldWeWalk($a)){
walkDog();
}
}else{
//some other stuff here
}
}
function canBreathe($a){
return $a.isAlive && $a.isAnimal;
}
function walkDog(){
getLeash();
attachLeashToCollar();
putOnShoes();
...
}
function shouldWeWalk($a){
return (!$a.hasHadWalk && date('h') > 6 && date('h') < 20);
}
First make a copy of the PHP file ;-)
Then try to refactor some of the deeply nested conditionals code blocks into their own functions and choose the name of these functions carefully.
That will force you to think about the code.
I think
if (condition1True()) {
handleCondition1();
}
else if (condition2True()) {
handleCondition2();
}
else {
handleDefaultCondition();
}
this variant is more preferable, because of better understanding what program doing.
I feel dirty every time I "break" out of a for-each construct (PHP/Javascript)
So something like this:
// Javascript example
for (object in objectList)
{
if (object.test == true)
{
//do some process on object
break;
}
}
For large objectLists I would go through the hassle building a more elegant solution. But for small lists there is no noticeable performance issue and hence "why not?" It's quick and more importantly easy to understand and follow.
But it just "feels wrong". Kind of like a goto statement.
How do you handle this kind of situation?
I use a break. It's a perfectly cromulent solution.
It's quick and more importantly easy to understand and follow.
Don't feel bad about break. Goto is frowned upon because it's quick and more importantly not easy to understand and follow.
See, the break doesn't bug me at all. Programming is built on goto, and for-break - like all control structures - is merely a special-purpose form of goto meant to improve the readability of your code. Don't ever feel bad about writing readable code!
Now, I do feel dirty about direct comparisons to true, especially when using the type-converting equality operator... Oh yeah. What you've written - if (object.test == true) - is equivalent to writing if (object.test), but requires more thought. If you really want that comparison to only succeed if object.test is both a boolean value and true, then you'd use the strict equality operator (===)... Otherwise, skip it.
For small lists, there's no issue with doing this.
As you mention, you may want to think about a more 'elegant' solution for large lists (especially lists with unknown sizes).
Sometimes it feels wrong, but it's all right. You'll learn to love break in time.
Like you said ""why not?" It's quick and more importantly easy to understand and follow."
Why feel dirty, I see nothing wrong with this.
I think is is easier to read and hence easier to maintain.
It is meant to be like it. Break is designed to jump out of a loop. If you have found what you need in a loop why keep the loop going?
Breaks and continues are not gotos. They are there for a reason. As soon as you're done with a loop structure, get out of the loop.
Now, what I would avoid is very, very deep nesting (a.k.a. the arrowhead design anti-pattern).
if (someCondition)
{
for (thing in collection)
{
if (someOtherCondition)
{
break;
}
}
}
If you are going to do a break, then make sure that you've structure your code so that it's only ever one level deep. Use function calls to keep the iteration as shallow as possible.
if (someCondition)
{
loopThroughCollection(collection);
}
function loopThroughCollection(collection)
{
for (thing in collection)
{
if (someOtherCondition)
{
doSomethingToObject(thing);
break;
}
}
}
function doSomethingToObject(thing)
{
// etc.
}
I really don't see anythign wrong with breaking out of a for loop. Unless you have some sort of hash table, dictionary where you have some sort of key to obtain a value there really is no other way.
I'd use a break statement.
In general there is nothing wrong with the break statement. However your code can become a problem if blocks like these appear in different places of your code base. In this case the break statements are code small for duplicated code.
You can easily extract the search into a reusable function:
function findFirst(objectList, test)
{
for (var key in objectList) {
var value = objectList[key];
if (test(value)) return value;
}
return null;
}
var first = findFirst(objectList, function(object) {
return object.test == true;
}
if (first) {
//do some process on object
}
If you always process the found element in some way you can simplify your code further:
function processFirstMatch(objectList, test, processor) {
var first = findFirst(objectList, test);
if (first) processor(first);
}
processFirst(
objectList,
function(object) {
return object.test == true;
},
function(object) {
//do some process on object
}
}
So you can use the power of the functional features in JavaScript to make your original code much more expressive. As a side effect this will push the break statement out of your regular code base into a helper function.
Perhaps I'm misunderstanding your use-case, but why break at all? I'm assuming you're expecting the test to be true for at most one element in the list?
If there's no performance issue and you want to clean up the code you could always skip the test and the break.
for (object in objectList)
{
//do some process on object
}
That way if you do need to do the process on more than one element your code won't break (pun intended).
Use a
Object object;
int index = 0;
do
{
object = objectList[index];
index++;
}
while (object.test == false)
if breaking from a for loop makes you feel uneasy.
My preference is to simply use a break. It's quick and typically doesn't complicate things.
If you use a for, while, or do while loop, you can use a variable to determine whether or not to continue:
for ($i = 0, $c = true; ($i < 10) && $c; $i++) {
// do stuff
if ($condition) {
$c= false;
}
}
The only way to break from a foreach loop is to break or return.
Sorry if this is a comp-sci 101 question. I'm just unsure if I'm missing something obvious.
So let's say some user input throws an error, and I want to catch it and return some feedback. The error will be a number, 0 - 8. 0 means "No Error". I want to give the user very specific feedback if the error is 3 (No numbers allowed, let's say). For the other 7 possibilities, I just want to end the script and echo the error.
I was working this out and decided to go with this:
$no_errors ($_error != 0 || $_error != 3) ? FALSE : TRUE;
if (!$no_errors)
echo $error_msg['$_error'];
$error_3 ($no_errors && $_error == 3) ? TRUE : FALSE;
if ($error_3)
bunch of stuff happens;
else
bunch of other stuff;
Anyways, I was then noticing the OR operator on the first line and was thinking that it might be better/safer to user an AND operator. But the more I contemplate, the less I see a difference.
So the real question is, if you want to eliminate two possibilities of a specific variable, are AND and OR identical, or is one logically/functionally more optimal?
It will be much more readable if you use a switch statement:
switch ($_error) {
case 0;
nothing happens;
break;
case 3:
bunch of stuff happens;
break;
default:
bunch of other stuff;
break;
}
First of all, I think I would recommend using another way of identifying errors than using "magic numbers". They are hard to maintain, as you easily forget what "3" meant. It looks like your language is PHP, which has support for exceptions. I'd recommend using them instead, you can read more about them here: http://dk.php.net/exceptions
As for logical operators, there aren't really any that are considered "good practice". Use what you want. If you have trouble figuring out when your expression is true/false, try making a truth table: http://en.wikipedia.org/wiki/Truth_table
Performance-wise, keep in mind that that the evaluation will be lazy in most languages. Using OR, if the first condition is true, it will return true without evaluating the second condition. For AND, it will return false if the first conditions is false, without evaluating the second.
Otherwise, the performance of the operators themselves is not really different. Use what is most readable to you.
logically the following are identical ( excuse my pseudo code )
(! expression_one || ! expression_two) /** this is the same as the one below **/
! (expression_one && expression_two)
Functionally which one is more optimal? They are both as optimal as each other. Both ways (&& and ||) allow short circuiting if the first expression is true (in the || case) or false ( in the && case)
The best is the one that helps you read code faster. It is the only true optimization you can make here, and possibly in millions of other places.
This would look more simple to read:
if($_error==3)
do stuff;
else if($_error>0)
do some other stuff
else
do normal stuff
Nobody notices the microseconds that you may win.
Personally I would eliminate the use of those numbers and use constants instead. Besides being easier to maintain, they make the coding itself much easier and allows you to update the values tomorrow e.g. if some circumstance foreces you to change the number from 3, you have to pretty much look through all your code
As suggested by gkrogers, a switch
while accomplishing the same thing
is much easier to read and maintain
Performance wise I believe they are very similar (see post by wvanbergen), however there are obvious differences in behaviour. I think that your current posting may not be doing what you are hoping for. In the first line if you $_error = 3 then you will have $no_errors = false. As you are checking for two conditions that both need to be satisfied maybe an and would be more appropriate.
Sometimes I find the easiest way to check my logic is to actually say what I want out loud. For example, "We have no errors if the error code is not 0 and not 3"
I generally find that in situation like this with only a few variables, the way I would write the sentence in English provides me with the most intuitive (and accurate) method for determining the logical operators.
If you find that the code looks messy after this process then you may find this link on De Morgan's laws useful
(A || B) = !(A && B). So it really doesn't make a difference
EDIT: (A || B) = !(A && B) is wrong. Tks for the comment. The correct form is (!A || !B) = !(A && B).
My apologies
If you use:
$no_errors ($_error != 0 && $_error != 3) ? FALSE : TRUE;
This means if $error != 0 AND $error != 3 which is invalid logic because $error cannot be == to 3 and 0 it can be 3 OR 0 but not both.
In the above example if $error = 0 then it would evaluate to FALSE because it is not 3 && 0 you are looking for it to be either 3 || 0.