For some reason when I run the .php script:
$s = yaml_parse_file("../config.yaml") || die("YAML file not found");
var_dump($s);
it returns:
bool(true)
What on earth is going on? This has happened out of nowhere it was working fine for a week and I can't seem to fix it. I have installed using pecl install yaml and added "extension=yaml.so" to php.ini?
I have used online yaml regex testers and they return that it is okay. The format is (obviously with content):
title:
email: hello#
logo: images/logo.png
download-file: .dmg
recaptcha:
pub:
priv:
meta:
keywords: mac, osx
description:
ico: images/icon.ico
You're assigning the result of the boolean operation to $s, since the || operator has a higher precedence than the assignment. So it's being evaluated as follows:
$s = (yaml_parse_file("../config.yaml") || die("YAML file not found"));
This returns true, since the initial expression returns a "truthy" value.
If you wrap the assignment in brackets, it will work as you are expecting:
($s = yaml_parse_file("../config.yaml")) || die("YAML file not found");
...
See https://eval.in/960405
The code worked before, when it used to read:
$s = yaml_parse_file("../config.yaml") or die("YAML file not found");
You recently changed or with || (why?) without knowing that they are different operators and they have different precedence.
or has the lowest precedence and the expression above is evaluated as:
($s = yaml_parse_file(...)) or die(...)
|| has higher precedence than the assignment (=) and the expression posted in the question evaluates as:
$s = (yaml_parse_file(...) || die(...))
To solve the issue, first you should forget about or die(). It is bad coding practice spread out by PHP tutorial more than 15 years ago. It's sad that many of them are still available on the web and teach the newbies how to throw a white page on the face of their visitors when an error happens.
or die() is useless. If yaml_parse_file() (or whatever function call you "handle" using it) returns FALSE, the next statement that attempts to use the result most probably will fail anyway. And you'll get a more or less descriptive error message in php_errors.log. That error message help you debug the code and identify and fix the errors. or die doesn't help with anything. It just hides the error under the carpet and tells the visitor what they can see by themselves: that your site doesn't work. But it doesn't tell you what was the error or how to fix it.
Related
I am working on file_get_contents func (I know notices on network issue's and Returns FALSE indicating operation failure). For now I don't care about the network errors and I just i want the network res and keep trying until i get it.
So, i put # before the the func to stop notices from making my cli window full of unwanted texts.
And To make the thing work in a loop i added !
while (($data=!#file_get_contents('http://example.com/')) === false);
But What diff does it make from this,
while (($data=#!file_get_contents('http://example.com/')) === false);
So, My question is whats the difference between them??
Quick answer: they're functionally identical
# is the PHP error suppression operator, which results in hiding all errors from the subsequent expression.
When you say
!#function()
, you're saying to suppress all errors that might arise from function() (and any deeper function calls, etc), and then negating the result.
With
#!function()
the whole of !function() is treated as the expression, and so any errors from the function are again hidden.
See https://3v4l.org/dPINA for an example - notice how the warning is suppressed in both cases.
#!file_get_contents = The ! evaluates the result of the function as a boolean (true or false). The # suppresses all warnings from the result of the expression.
!#file_get_contents = The # suppresses all warnings from the function, then the ! evaluates the result of the error-suppressed function as a boolean (true or false).
Edit: My answer was marked as accepted, so I edited with the correct behavior from iainn's answer.
$file= #fopen("ssssss.php", r) or die("not found");
(#include("ssssss.php")) or die("not found");
In the first statement we don't put ( ) around #fopen and it is working fine.
But in the second if I didn't put these () it does't show any message.
so why with include I must round it with ( ) ?
I agree with the suggestions in the other answers but the actual answer to your question is this:
In the PHP documentation they say to take care when comparing the return value of include.
That's because it is a special construct and parentheses are not needed.
So when you do this (without wrapping parentheses):
#include("ssssss.php") or die("not found");
You're actually doing this, because or is evaluated first:
#include (("ssssss.php") or die("not found"));
Now, "ssssss.php" is a non empty string that evaluates logically to true.
or is a logical operator that gives true if any of the parameters is true (or both of them).
Also, this operator is short-circuit: if the first parameter is true, php already knows that the operator or will return true, so it doesn't waste time evaluating the second parameter, and die() is not executed.
So finally, or gives true and your sentence becames this:
#include (1);
Php tries to "include 1", and it would raise a warning but it does not because of the #.
Here you have a similar example in php.net.
Your first sentence is not the same case.
$file= #fopen("ssssss.php", r) or die("not found");
fopen is just a regular Php's function with its parentheses. Here you need to have in mind two operators: = and or.
= has higher precedence than or, so, if fopen's result is correctly assigned to $file (and it is), that operation will return true. And, as I explained before, "true or anything else", gives true but die() is not executed because of the short-circuit operator.
You should be using file_exists instead of using the # as the later covers all sorts of issues. A better solution would be...
if (file_exists("ssssss.php")) {
$file= #fopen("ssssss.php", r);
}
and
if (file_exists("ssssss.php")) {
include("ssssss.php");
}
That's not really a good use of include. If you need to include a php file and generate an error on failure, use require or require_once.
If you need to get the contents of the whole file, you could use file_get_contents().
Also, I agree with Nigel Ren about the use of # - it is a dangerous practice and should be avoided.
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.
This question already has answers here:
Closed 11 years ago.
Possible Duplicates:
PHP - and / or keywords
PHP shorthand syntax
Quick question. I keep seeing shorthand expressions in libraries around the place, and despite having been a PHP developer for over 3 years, I struggle to quite see how the following would evaluate.
What exactly does the PHP interpreter do with the following shorthand lines of code when it encounters them?
<?php
defined('foo') OR exit('foo is not defined!');
$foo AND $this->bar();
I'm guessing that it' obviously conditional execution - i.e. the second statement won't get executed unless the first bit is true... but the use of the bitwise operators confuse me a bit.
Can someone elaborate?
Thanks :)
I believe that this is a form of short-circuit evaluation: http://en.wikipedia.org/wiki/Short-circuit_evaluation
Essentially, when evaluating an entire expression, the interpreter short circuits once it is certain of the result. For example:
true OR do_something();
This expression never calls do_something() because the first operand of OR is true, so the entire expression must be true.
Back when I was learning PHP I remember reading the 'do or die' style commands and not fully understanding them at the time, the classic example is:
mysql_connect() or die('couldn\'t connect');
Bear in mind that the conditions will only run if they're required, for example:
if (a == b && b == c)
Here b == c will only be tested if a == b. The same theory applies to or:
if (a == b || b == c)
Now b == c will only be tested if a != b.
In this case you are relying on this order to run a command (exit or $this->bar()) in certain conditions.
Be Aware... exit() is a bad idea in this circumstance - if you exit('something went wrong') there's nothing anyone can do to hide this error from the user, also it's likely to issue a 200 OK HTTP status where a 500 Internal Server Error would be much more appropriate, I would consider something more like:
defined('foo') OR throw new Exception('foo is not defined!');
Here you have a chance to either catch the Exception or at least let PHP catch it and issue a 500 status.
Mat
Much less elaborate than you think. The or keyword is the same as ||, except it has lower precedence. See the corresponding PHP page for details.
The actual execution of this statement relies on a separate concept involving logical operators: short circuiting. This means that, in the case of or, the second statement is not evaluated if the first statement turns out to be true. (Since in a conditional, for instance, the entire condition would return true without ever needing to see the second half.)
Sometimes you have a function that looks something like:
function test()
{
$foo = TRUE;
$bar = FALSE;
return $foo && $bar;
}
In this case, if some does:
$bla = test();
if($bla) {
... do something
}
The "...do something" will not get executed, because the function as a whole returned false.
return $foo && $bar means that both variables have to be true in order for the function to return true.
On the other hand, if it stated: return $foo || $bar; then the function would return true, because at least one variable is true.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
PHP - and / or keywords
I saw several bits of PHP code using or in a way I was unfamiliar with. For example:
fopen($site,"r") or die("Unable to connect to $site");
Is this equal to this ||?
Why would you use this instead of a try catch block? What will cause the program run the or die()?
It is for the most part, but...
The reason for the two different
variations of "and" and "or" operators
is that they operate at different
precedences.
See http://php.net/manual/en/language.operators.logical.php
or is equal to || except that || has a higher presedense than or.
Reference:
http://www.php.net/manual/en/language.operators.precedence.php
or has an other precedence. The concrete statement is little trick with boolean operators. Like in a common if-test-expression the second part is only executed, if the first is evaluated to false. This means, if fopen() does not fail, die() is not touched at all.
However, try-catch only works with Exceptions, but fopen() doesnt throw any.
Today something like this is "not so good" style. Use exceptions instead of hard abortion
if (!($res = fopen($site, 'r'))) throw new Exception ("Reading of $site failed");
or die happens with the first command fails.
It is similar to a try catch, but this is more direct approach.
Note that this is a classical test:
fopen($site,"r") or die("Unable to connect to $site");
Only if fopen($site,"r") returns false, will the second half of the test be run: 'die('error')'.
Same is if(a || b); b is only run if a returns false.
Die in PHP is the same as exit();
http://www.php.net/manual/en/function.exit.php
Stops execution of the current script entirely, and prints out the error message.
Yes it equals ||
In this case it is explicitly stopping the execution of the page and printing that error message.