In this code fragment:
$results = $this->getAdapter()->fetchAll($query);
if(count($results)) {
// …
}
…do you consider the if(count()) part to be be a well understood idiom, or confusing code. i.e. should it be
if(count($results) > 0)
???
Using a boolean expression with 'if' requires less understanding of a language than using implicit conversions, so I would always prefer the second option (adding "> 0") - at least if this code is meant to be read by others, too. You never know who will maintain your code. The keyword is "clarity" here.
But I must admit I have written many times code with if's using an int expression myself, too, because I like its elegance.
They are doing exactly the same job in this context, and are both easily readable.
I'll just add (just in case) that if you're performing this query only to if(count()), then you should be issuing a SELECT COUNT(*) instead!
The count and the extraneous > comparison are pointless. If you receive an actualy array, then the test should just be:
if ($results) {
That's what scripting languages are for. Abstracting low level details away.
You would only need the count if your fetchAll function returns an ArrayObject or similar. Should your function sometimes return a false for example, then your if (count( is going to fail (because count(false)==1 in PHP).
erm...not realy sure what the purpose of this question is - but the semantics should be self-evident to anyone whom understands PHP
My opinion is that the > 0 check is redundant and unnecessary.
I know other developers who insist that it should be there for clarity, but frankly I can't why -- anyone who can read PHP should be able to discern that they are identical.
Related
I'm trying to write more functional code in PHP without any helper libraries.
I need to return some JSON that includes the results of a transformed array AND the count of that array (for convenience on the data consumer end). Since you're not supposed to use variables in FP, I'm stumped on how to get the count of the array without recalculating/remapping the array.
Here's an example of what my code currently looks like:
$duplicates = array_filter( get_results(), 'find_duplicates' );
send_json( array(
"duplicates" => $duplicates,
"numDuplicates" => count( $duplicates )
) );
How can I do the same without storing the results of the filter in a temporary variable to avoid running array_filter() twice?
But first, acknowledge the following...
"Since you're not supposed to use variables in FP..." – that's a ludicrous understanding of functional programming. Variables are used constantly in functional programs. I'm guessing you saw point-free functional programs and then imagined that every program can be expressed in such a way...
the receiver of the JSON could easily get the number of duplicates using JSON.parse(json).duplicates.length because every Array in JavaScript has a length property – it's arguably silly to attach a numDuplicates in the first place. Anyway, let's assume your consumer has a specific API that requires the numDuplicates field...
functional programming is concerned with things like function purity – maybe you've simplified your code in your post (which is bad; don't do that) or that is in fact your actual code. In such a case, get_results() and send_json functions are impure; send_json has an obvious (but unknown) side effect (the return value is not used) — You ask for a functional solution but you have other outstanding non-functional code... so...
There's nothing wrong with the code you have. Sometimes removing a point (variable, or argument), it hurts the readability of the code. In your case, this code is perfectly legible. It is at this point that I feel you're only trying to shorten the code or make it more clever. Your intention is to improve it, but I think you'd actually harm it in this case.
What if I told you...
a variable assignment can be replaced with a lambda? 0_0
(function ($duplicates) {
send_json([
'duplicates' => $duplicates,
'numDuplicates' => count($duplicates)
});
}) (array_filter(get_results(), 'find_duplicates'));
But that made the code longer.. and there's added abstraction which hurts readability T_T In this case, using a normal variable assignment (as in your original code) would've been much better
Combinators
OK, so what if you had some combinators at your disposal to massage the data into the desired shape?
function apply (...$xs) {
return function ($f) use ($xs) {
return call_user_func($f, ...$xs);
};
}
function identity ($x) { return $x; }
// hey look, mom! no points!
send_json(
array_combine(
['duplicates', 'numDuplicates'],
array_map(
apply(
array_filter(get_results(), 'find_duplicates')),
['identity', 'count'])));
Did we achieve anything other than writing the weirdest PHP you or anyone else has probably seen? Not to mention, the input is strangely nested in the middle of the expression...
remarks
I'm nearly certain that you'll be disappointed with this answer (or disagree with me), but I'm also pretty confident that you're not sure what you're looking for. A guess: you saw functional programming that "doesn't use variables" and assumed that's how all programs can and should be written; but that's just not the case. Sometimes using a variable or two can dramatically improve the readability of a given expression.
Anyway, all of this is truly beside the point because attaching numDuplicates is arguably an anti-pattern in JSON anyway (point #2 above).
In PHP, you can handle errors by calling or die to exit when you encounter certain errors, like this:
$handle = fopen($location, "r") or die("Couldn't get handle");
Using die() isn't a great way to handle errors. I'd rather return an error code so the parent function can decide what to do, instead of just ending the script ungracefully and displaying the error to the user.
However, PHP shows an error when I try to replace or die with or return, like this:
$handle = fopen($location, "r") or return 0;
Why does or die() work, but not or return 0?
I want to thank you for asking this question, since I had no idea that you couldn't perform an or return in PHP. I was as surprised as you when I tested it. This question gave me a good excuse to do some research and play around in PHP's internals, which was actually quite fun. However, I'm not an expert on PHP's internals, so the following is a layman's view of the PHP internals, although I think it's fairly accurate.
or return doesn't work because return isn't considered an "expression" by the language parser - simple as that.
The keyword or is defined in the PHP language as a token called T_LOGICAL_OR, and the only expression where it seems to be defined looks like this:
expr T_LOGICAL_OR { zend_do_boolean_or_begin(&$1, &$2 TSRMLS_CC); } expr { zend_do_boolean_or_end(&$$, &$1, &$4, &$2 TSRMLS_CC); }
Don't worry about the bits in the braces - that just defines how the actual "or" logic is handled. What you're left with is expr T_LOGICAL_OR expr, which just says that it's a valid expression to have an expression, followed by the T_LOGICAL_OR token, followed by another expression.
An expr is also defined by the parser, as you would expect. It can either be a r_variable, which just means that it's a variable that you're allowed to read, or an expr_without_variable, which is a fancy way of saying that an expression can be made of other expressions.
You can do or die() because the language construct die (not a function!) and its alias exit are both represented by the token T_EXIT, and T_EXIT is considered a valid expr_without_variable, whereas the return statement - token T_RETURN - is not.
Now, why is T_EXIT considered an expression but T_RETURN is not? Honestly, I have no clue. Maybe it was just a design choice made just to allow the or die() construct that you're asking about. The fact that it used to be so widely used - at least in things like tutorials, since I can't speak to a large volume of production code - seems to imply that this may have been an intentional choice. You would have to ask the language developers to know for sure.
With all of that said, this shouldn't matter. While the or die() construct seemed ubiquitous in tutorials (see above) a few years ago, it's not really recommended, since it's an example of "clever code". or die() isn't a construct of its own, but rather it's a trick which uses - some might say abuses - two side-effects of the or operator:
it is very low in the operator precedence list, which means practically every other expression will be evaluated before it is
it is a short-circuiting operator, which means that the second operand (the bit after the or) is not executed if the first operand returns TRUE, since if one operand is TRUE in an or expression, then they both are.
Some people consider this sort of trickery to be unfavourable, since it is harder for a programmer to read yet only saves a few characters of space in the source code. Since programmer time is expensive, and disk space is cheap, you can see why people don't like this.
Instead, you should be explicit with your intent by expanding your code into a full-fledged if statement:
$handle = fopen($location, "r");
if ($handle) {
// process the file
} else {
return 0;
}
You can even do the variable assignment right in the if statement. Some people still find this unreadable, but most people (myself included) disagree:
if ($handle = fopen($location, "r")) {
// process the file
} else {
return 0;
}
One last thing: it is convention that returning 0 as a status code indicates success, so you would probably want to return a different value to indicate that you couldn't open the file.
Return is fairly special - it cannot be anything like a function since it's a tool to exit functions. Imagine this:
if(1==1) return(); // say what??
If it was like this, return would have to be a function that does a "double exit", leaving not just its own scope but the caller's, too. Therefore return is nothing like an expression, it simply can't work that way.
Now in theory, return could be an expression that evaluates to (say) false and then quits the function; maybe a later php version will implement this.
The same thing applies to goto which would be a charm to work as a fallback; and yes, fallbacks are necessary and often make the code readable, so if someone complains about "clever code" (which certainly is a good point) maybe php should have some "official" way to do such a thing:
connectMyDB() fallback return false;
Something like try...catch, just more to the point. And personally, I'd be a lot happier with "or" doing this job since it's working well with English grammar: "connect or report failure".
TLDR: you're absolutely right: return, goto, break - none of them works. Easy to understand why but still annoying.
I've also stumbled upon that once. All I could find was this:
https://bugs.php.net/bug.php?id=40712
Look at the comment down below:
this is not a bug
I've searched in the documentation and I think it's due to the fact that return 0 is a statement whereas die() is essentially an expression. You can't run $handle = return 0; but $handle = fun(); is valid code.
Regarding error handling I would recommend custom codes or using custom handlers and triggers. The latter are described here for example.
I have logical expressions that I need to evaluate. After some expresison template parametrized with its parameters, these expressions could look like this:
$expr1 = '1 or 0 and not(0 or 0)';
$expr2 = "'editor' == 'editor' and not(0 = 1) and 10 > 5";
So, I need to handle numbers, string literals, as well as logical and algebraical operators and round brackets between them.
When using PHP eval I also get undesirable unsecured abilities, like system function call, and so on.
So, is there any way to restrict PHP eval, or may be there is some better solution?
Thanks!
You could use a tokenizer to check that the expressions don't contain function calls.
See the safer eval() class for an example.
Ok, I got another solution. I've dawned that I can use PHP DOMXPath::evaluate to evaluate my logical expression. So, I got a working solution, which has no security issues. I think my problem is solved :)
What is the benefit of using multiple steps to test variables:
$VarLength = strlen($message);
if ($VarLength > 10)
echo "Over Ten";
...versus just pushing the whole process into one if statement:
if ( strlen($message) > 10 )
echo "Over Ten";
I'm wondering if the benefits go beyond code style, and the ability to re-use the results of the (in the example above) strlen result.
Your question is not really possible to answer technically, so this is more a comment than an answer.
Benefits beyond code-style and re-use of the result is when you change the code.
You might want to replace the strlen() function with some other function but you don't want to edit the line with the if clause while you do so. E.g. to prevent errors or side-effects. That could be a benefit, however it depends on code-style somehow. So as you exclude coding style from your question, it makes it hard to answer as that domain touches a lot how you can/should/would/want/must write code.
If the result of a function will be used multiple times, it should be cached in a variable so as to obviate the need to waste resources to re-calculate its result.
If the function result won't be re-used, it can simply be a matter of code readability to clearly delineate what's happening by storing the function return value in a variable before using it in an if condition.
Also, in terms of readability, you should always use curly braces even when not mandated by PHP syntax rules as #AlexHowansky mentions.
Most of it is in the code style. In terms of rapidity of the results, it doesn't change much. If you are using $varLenght more then once, then you are saving the call to the function to obtain the length. But even that, the time difference is extremely minimal (I would even like to say unnoticable).
But: When developping any applications, you have to keep in mind that you might not be the only one making changes to it down the road, or you might not be as fresh and up to date with the exact program you are writing. Therefore, the cleaner the code, the easier it is in terms of maintenance, and THAT'S where you save a lot of time down the road.
Best Practice dictates that functions be called minimally. In your case the practice doesn't violate the rule, but it is not uncommon to find code like:
if ( strlen($message) > 100 )
echo "Over Ten";
else if ( strlen($message) > 20 )
echo "Over Ten";
else if ( strlen($message) > 10 )
echo "Over Ten";
...
A common prevention is to always assign function results to a variable for consistency.
I wouldn't say there is any benefit apart from the re-use case you've already mentioned. Your latter case is more readable, probably faster, and probably less memory-intensive. I would however strongly recommend always using braces, even when your conditional is only one line:
if (condition) {
statement;
}
I have an if statement with two conditions (separated by an OR operator), one of the conditions covers +70% of situations and takes far less time to process/execute than the second condition, so in the interests of speed I only want the second condition to be processed if the first condition evaluates to false.
if I order the conditions so that the first condition (the quicker one) appears in the if statement first - on the occasions where this condition is met and evaluates true is the second condition even processed?
if ( (condition1) | (condition2) ){
// do this
}
or would I need to nest two if statements to only check the second condition if the first evaluates to false?
if (condition1){
// do this
}else if (condition2){
// do this
}
I am working in PHP, however, I assume that this may be language-agnostic.
For C, C++, C#, Java and other .NET languages boolean expressions are optimised so that as soon as enough is known nothing else is evaluated.
An old trick for doing obfuscated code was to use this to create if statements, such as:
a || b();
if "a" is true, "b()" would never be evaluated, so we can rewrite it into:
if(!a)
b();
and similarly:
a && b();
would become
if(a)
b();
Please note that this is only valid for the || and && operator. The two operators | and & is bitwise or, and and, respectively, and are therefore not "optimised".
EDIT:
As mentioned by others, trying to optimise code using short circuit logic is very rarely well spent time.
First go for clarity, both because it is easier to read and understand. Also, if you try to be too clever a simple reordering of the terms could lead to wildly different behaviour without any apparent reason.
Second, go for optimisation, but only after timing and profiling. Way too many developer do premature optimisation without profiling. Most of the time it's completely useless.
Pretty much every language does a short circuit evaluation. Meaning the second condition is only evaluated if it's aboslutely necessary to. For this to work, most languages use the double pipe, ||, not the single one, |.
See http://en.wikipedia.org/wiki/Short-circuit_evaluation
In C, C++ and Java, the statement:
if (condition1 | condition2) {
...
}
will evaluate both conditions every time and only be true if the entire expression is true.
The statement:
if (condition1 || condition2) {
...
}
will evaluate condition2 only if condition1 is false. The difference is significant if condition2 is a function or another expression with a side-effect.
There is, however, no difference between the || case and the if/else case.
I've seen a lot of these types of questions lately--optimization to the nth degree.
I think it makes sense in certain circumstances:
Computing condition 2 is not a constant time operation
You are asking strictly for educational purposes--you want to know how the language works, not to save 3us.
In other cases, worrying about the "fastest" way to iterate or check a conditional is silly. Instead of writing tests which require millions of trials to see any recordable (but insignificant) difference, focus on clarity.
When someone else (could be you!) picks up this code in a month or a year, what's going to be most important is clarity.
In this case, your first example is shorter, clearer and doesn't require you to repeat yourself.
According to this article PHP does short circuit evaluation, which means that if the first condition is met the second is not even evaluated.
It's quite easy to test also (from the article):
<?php
/* ch06ex07 – shows no output because of short circuit evaluation */
if (true || $intVal = 5) // short circuits after true
{
echo $intVal; // will be empty because the assignment never took place
}
?>
The short-circuiting is not for optimization. It's main purpose is to avoid calling code that will not work, yet result in a readable test. Example:
if (i < array.size() && array[i]==foo) ...
Note that array[i] may very well get an access violation if i is out of range and crash the program. Thus this program is certainly depending on short-circuiting the evaluation!
I believe this is the reason for writing expressions this way far more often than optimization concerns.
While using short-circuiting for the purposes of optimization is often overkill, there are certainly other compelling reasons to use it. One such example (in C++) is the following:
if( pObj != NULL && *pObj == "username" ) {
// Do something...
}
Here, short-circuiting is being relied upon to ensure that pObj has been allocated prior to dereferencing it. This is far more concise than having nested if statements.
Since this is tagged language agnostic I'll chime in. For Perl at least, the first option is sufficient, I'm not familiar with PHP. It evaluates left to right and drops out as soon as the condition is met.
In most languages with decent optimization the former will work just fine.
The | is a bitwise operator in PHP. It does not mean $a OR $b, exactly. You'll want to use the double-pipe. And yes, as mentioned, PHP does short-circuit evaluation. In similar fashion, if the first condition of an && clause evaluates to false, PHP does not evaluate the rest of the clause, either.
VB.net has two wonderful expression called "OrElse" and "AndAlso"
OrElse will short circuit itself the first time it reaches a True evaluation and execute the code you desire.
If FirstName = "Luke" OrElse FirstName = "Darth" Then
Console.Writeline "Greetings Exalted One!"
End If
AndAlso will short circuit itself the first time it a False evaluation and not evaluate the code within the block.
If FirstName = "Luke" AndAlso LastName = "Skywalker" Then
Console.Writeline "You are the one and only."
End If
I find both of these helpful.