Seeing the exit() PHP documentation got me thinking:
$filename = '/path/to/data-file';
$file = fopen($filename, 'r')
or exit("unable to open file ($filename)");
Couple questions:
What are common use cases besides opening files for using exit()?
Since not every function everyone ever writes ends in exit(), how do you know to use it in some contexts vs. others?
Are if/else and or/exit interchangeable?
In that context, the or in that statement is one of PHP's logical operators which when used like that, will execute the second statement if and only if the first one fails due to short circuit evaluation.
Since fopen returned false, the or exit statement gets executed since the first part failed.
To understand it better, here is a quick explanation of short-circuit evaluation.
$x = 5;
$y = 42;
if ($x == 5 or $y == 42) {
echo "x or y is true";
}
In the above code, the expression $y == 42 is never evaluated because there is no need since the first expression was true.
In that example, they are using the same logic for deciding whether or not to evaluate the statement that calls exit.
To address your questions:
I wouldn't use exit when opening a file failed unless the program was very specific. The better thing to do would be to log an error and then return the error to the caller so they can decide what to do.
When to use exit completely depends on the code you are writing.
Given the explanation about short-circuiting, yes they are interchangeable in that sense. Using or exit is just a bit shorter than using if/else.
Hope that helps.
CLI scripts, exit can take an integer parameter which is fed back to the console to indicate success or some form of error
I'm not inclined to use exit() or die() in application code, since exceptions are preferred. However, I personally think you might be overcomplicating things a little bit... it kills script execution, so use it when you need to kill a script. Truthfully I mostly only ever kill scripts mid-execution when debugging (one-off breakpoints) and that's not ideal either (again exceptions do a better job).
The use of or is mostly convenient. Here's an interesting point though...
Why does
$resource = mysql_connect() || die('dead')
not work?
The answer is that the = operator takes precedence over or so that the assignment is made first like so: ($resource = mysql_connect()) or die(). In this way its exactly like doing an if(!($resource = mysql_connnect())) { die() }
I tend to avoid using exit() at all as it's a really ugly way to handle errors from the user's perspective.
If you must use it, any non recoverable error would be a candidate. For example, database query or connection failures, or remote request failures.
if/else is equivalent to ...or whatever(). It's just a style thing, with the latter form being more succinct.
I would say you use exit in a situation where your code cannot continue if the function you were doing failed. For example reading a file that is needed.
Related
I do not have control over the code I'm executing. This is a third party function, but not user-entered. These are things that are versioned so it is impractical that I poke there and change all die()'s into something more sane. Because a new version is coming from time to time and then I could paradoxically make the code even more insecure by trying mess with it poor error handling.
so let's say we have a function:
fuction myfunc() {
// lot's of complicated code
if (!is_file('myfile.txt') exit('file not found');
// and so on
}
What I'm trying to do is to somewhat run that piece of code and return to my main thread and then act accordingly with that error.
I've tried die() or eval() but this returns the whole script.
Bummer ?
A Hail Mary approach is to use runkit's runkit_function_redefine or function_override to redefine the functions die and exit to throw an Exception instead.
A potential problem is that the 3rd party can catch those exceptions and might not deal with them correctly. It's also very likely that you can't properly deal with the exception either.
You can use register_shutdown_function to run code after exit has been called. You are somewhat limited in what you can do at this point as some services have already been shut down (such as autoloading). I think you can still output content, not sure about sessions and other headers.
Another approach would be to run the code in a seperate php process (or http request), for instance by calling php through exec.
A more solid approach can be to add predicitions to your own code, ensuring the bad states are never reached when calling the 3rd party code. It is possible that not all preconditions can be met.
Ideally only code that is an entry point (like a router script) may exit. Using exit anywhere else is just shoddy programming really.
If you have not read Halcyon's answer, you should have a look at it first.
Since you mention eval(), I assume you have the code as a string. I will refer to both die() and exit() by just the latter, but things should be relevant for both.
You can try and replace occurrences of die() and exit() with something, and then eval. It's simple but that can be very messy.
One thing to look out for, IF you decide to do this, is that you may end up replacing occurrences which are not really 'code'. For example, echo "Let him exit()";.
Also, when you consider possible equivalent syntax, like exit (); , exit; or exit(1);, it gets much more unpleasant. You'll have to handle those with a regex.
But if you can safely assume that
those two signatures (die() and exit()) are the only ones you need to worry about; and
that strings (or other content) are not going to contain those 'phrases'
then you can use this approach.
Today I was looking through the php manual and stumbled upon a control structure declare.
The declare construct is used to set execution directives for a block
of code
This is what declare is supposed to do. To be honest I didn't understood it. On reading again it found a new thing Ticks
A tick is an event that occurs for every N low-level tickable
statements executed by the parser within the declare block. The value
for N is specified using ticks=N within the declare block's directive
section.
I didn't understand it either. what does it mean by N low-level tickable statements If there had been a good sample code, then it would have been easy to understand. But none was found in the manual. I have found some on SO Q1, which actually increased my curiosity and confusion. So can anyone what is this for and where can we use this.
My actual confusion is with this statement (from the linked so post) you can declare a tick-function which checks each n executions of your script whether the connection is still alive or not. So when I register a tick function with tick = 20 on a php file and execute it, the file will be alive till 20 execution is complete(got this idea when it was wrongly considered as multithreaded). This is the idea i have got, I dont think its correct..
Or is it a simple replacement for while($x = 20)
[EDIT 1]
I have also seen the implementation of declare() another section of php manual Function arguments
[EDIT 2]
Also in Process Control
You use the declare() statement to specify the locations in your
program where callbacks are allowed to occur. This allows you to
minimize the overhead of handling asynchronous events
When PHP is executing your script, the execution can be seen as a lot of statements being executed. Most statements cause a Tick, though not necessarily all statements do so. (Manual says: Typically, condition expressions and argument expressions are not tickable.)
This block would normally cause 5 ticks, as you are executing 5 statements:
$a = 1;
$B = 2;
$a = 3;
$B = 4;
$a = 5;
And this block would normally cause 5 ticks, and one more tick as the end of the while loop also is counted as a statement/tick:
while ($i < 5)
$a++;
With the help of declare(ticks=N) and register_tick_function(), you can now execute code in between the statements/ticks. The register_tick_function specifies which function should be called when a tick event occurs. And the declare sets how many tick should pass, before a tick event occurs.
With declare(ticks=1) and register_tick_function('someFunction'); you will call someFunction() code in between every statement/tick.
If you use declare(ticks=3), then someFunction() will be executed on every third statement/tick.
Example:
function handler(){
echo "x";
}
register_tick_function("handler");
$i = 0;
declare(ticks = 4) {
while ($i < 9)
echo ++$i;
}
This script will output: 1234x5678x9
It's that simple.
Now what is meant in the linked question with "whether the connection is still alive", is not really interesting on itself and is not actually related to the above mentioned. It is just something you COULD do on every tick event. But you can also do something totally different. What is mentioned is simply that some scripts can take quite some time to execute and that during the execution, the client can disconnect. (Imagine closing the browser, while the script is still running.) PHP will by default continue to run the script, even if the client has disconnected. You can use the function connection_aborted() to detect if the client has disconnected. This is something you COULD also do without using ticks at all.
Now let's say for example that you want your script to stop running as soon as the client disconnects. Simply use ...
function killme() {
if (connection_aborted()) {
die();
}
}
register_tick_function('killme');
declare(ticks=1);
... and your script will call killme() after each statement of your code. killme() will check if the client is still connected and die() when it isn't.
In practice: Ignore the declare() directive. Unless you run into code that makes use of it — which is very rare — you can safely forget that it ever existed.
That being said, here's the details. The declare() directive is currently used for two completely unrelated things:
As declare(encoding=…), for declaring the encoding of a PHP file. (In this sense, it's comparable to a server-side version of <meta charset="…">.)
But don't use this. Under most circumstances, the script encoding doesn't matter. If by some chance it does, the PHP encoding should be set globally (hopefully to "UTF-8") by the zend.script_encoding configuration value. Setting it at the file level is confusing and unnecessary.
As declare(ticks=…), for defining the frequency at which tick functions are called. Tick functions are called periodically by the PHP interpreter, and are set up using register_tick_function.
While some of the comments on php.net suggest using it to implement timeouts on network accesses, that doesn't actually work as expected, as ticks are not fired while the interpreter is blocked in a native function call. It might have some applications in benchmarking, but outside of that it's basically useless. I'd avoid it.
The one usage not mentioned in this or the possible duplicate answer is catching signals.
If you have a CLI script and want to catch user signals (like SIGHUP or SIGTERM (CTRL+C)), you need declare(ticks... together with pcntl_signal https://secure.php.net/manual/en/function.pcntl-signal.php which allows you to catch those signals (same like trap in shell scripts)
Reading this question I want to copy #Your Common Sense's error checking when using mysqli
$query="INSERT INTO testtable VALUES (23,44,56)";
$stmt_test->prepare($query);
$stmt_test->execute() or trigger_error($stmt_test->error);
$stmt_test->close();
How does or work? Another example of it's use is
$fh = fopen($myFile, 'w') or die("can't open file");
How is it different than using an if statment and would should it be used instead?
If the first statement returns false, then the second one is executed. That's it.
This is often how boolean "or" expressions are evaluated in programming languages. If you have a statement involving functions thus:
if (a() or b()) { ... }
then PHP works out that, if a() returns true, there is no need to evaluate the second function, since the overall result will be true regardless of the outcome of the second part. We can use this trick as a simple if mechanism:
(operation_that_might_fail() or report_error());
Here, I've removed the if around the clause. This will be evaluated just as before - except the result of ORing the two is then thrown away, since we don't need to do anything with it.
For this to work, operation_that_might_fail() must return boolean true on success, and false otherwise. As it happens, many PHP functions do exactly that, so we can often use this approach.
Side note: whilst the statement or is arguably clearer, PHP programmers tend to prefer the operator ||. Similarly, and will do what it says, but && is more common.
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 believe that all of these (and even die() or die(0)) are identical. If they are not identical, which is preferred for exiting a script successfully? If they are identical, is there any preferred standard to indicate successful script completion? I tend to use exit;.
EDIT: All of the answers have "die() and exit() are identical" even though I say that in my question. I updated to the title to hopefully make it clearer that this is NOT my question. I want to clearly indicate success from a command line script.
These are all identical. I'm pretty sure die() is just a straight-up alias to exit(), but even if it isn't, it still acts identically.
When one of these functions is given a string argument, it prints out the string before terminating the process. When it encounters an integer under 255, that integer is considered the return code for the process, which gets passed back to the process which invoked the PHP script. This is particularly useful when writing command line applications (PHP isn't web-only!).
As far as the difference between exit, exit(), and exit(0), there really is none. There is definitely no difference between the first two because exit is technically a language construct, not a function, so it can be called with or without parentheses, just like echo. Returning a code of 0 means "this program ran successfully/without errors", and while I don't know what exactly happens when you don't pass an argument, PHP.net says that an argument-less exit indicates success, so I would bet it returns 0, though again PHP.net doesn't show a default for the argument.
As several people have mentioned, die() and exit() are exactly the same.
If you look at the PHP documentation, there are two options for arguments:
An numeric value. This is only useful if you are using PHP from the command line, as opposed to a web server. A value of zero indicates success. Nonzero indicates a failure condition occurred.
A string value. This will be displayed to the browser when the exit occurs.
Instead of die() or exit(), I recommend using exceptions and a custom top-level exception handler to manage failure conditions.
You have more flexibility that way to do things like automatic error logging. Also, if you're using PHP to implement a JSON API, this exception handler can hand back a valid, error-indicating JSON snippet instead.
I would say that in regards with a better semantics die($arg); should be used for an abnormal or unexpected termination, even when -of course- you still have caught it. And exit($arg); should be used for a normal (expected / controlled) end of a process, like in break; for a for or while or a switch structure but with a definitive end.
Nevertheless .. I personally often use a general if { } else { } structure to control different branches of huge processes or output buffering so not having to use "exit" ..
I also use die($arg) in simple error-catching semantics like in
$db = mysql_connect([$args]) or die ($error); ...
die(); is just a synonym for exit(); and is functionally identical.
The standard way is to use exit code zero to signify success, and anything else to denote an error condition.
die() is typically used to kill the script with an error output:
die("There was a fatal error");
where-as exit is typically used as a successful exit (At least in my coding)
The PHP Manual says that the functions are identical.
I will get downvoted to hell, but in some cases when hacking in CLI, we do not want the program to get killed, while not wanting to continue the full execution.
Here the goal is to avoid making api calls to a separate hand-point file. Say I have a nice play button in my interface, that execute system calls.
Example 1: The program get killed after the job , no datas returned. This is not wanted.
if ($_GET["play"] != ""){
// Some job
exit;
}
/* Huge amount of data*/
Example 2: The program still runs, feeding the whole data in the GET request. This is unnecessary on this case. This is slowing down the browser with all the data, that he has already.
if ($_GET["play"] != ""){
// Some job
}
/* Huge amount of data*/
Example 3: The program still runs, no data returned as expected, the play command had been executed, but the whole data set get parsed, this is unnecessary job, can slow down php/the machine.
/* Huge amount of data*/
if ($_GET["play"] != ""){
// Some job
}
Example 4: The program still runs, no data returned as expected, the play command had been executed, the whole data had not been parsed, php returned super quickly 200OK with an empty response, as expected. Everyone happy!
if ($_GET["play"] != ""){
// Some job
goto END;
}
/* Huge amount of data*/
END;
Yes! Using GOTO, sometimes is to be considered -as the best to do 🔨 -!
https://www.php.net/manual/en/control-structures.goto.php
die is exactly equivalent to exit.
From the manual:
If status is an integer, that value will be used as the exit status..
This is only useful if you have some sort of wrapper that does something based on the exit status. Unless you have a specific need to report an exit code to the outside world, just exit;.