With PHP's SessionHandler there is SessionHandler::write() which returns a value. The manual is somewhat vague about it:
Return Values
The return value (usually TRUE on success, FALSE on failure). Note this value is returned internally to PHP for processing.
(same for the interface)
I wonder what the meaning of that processing by PHP is.
I already was that clever and looked into session_set_save_handler but there the return value for the write() callback isn't even mentioned.
Well, "returned internally to PHP" in this context means: It is not passed back to your code (as the return type for session_write_close() is void.)
In other words, what PHP does with it should be treated as unknown (unless you look at the actual C source of PHP); thus I would simply follow the advice of returning true on success, and false if your custom session handler was somehow unable to write the session data.
If I should guess, I would say that maybe PHP generates a warning message, or maybe that ist just intended for use in a later version of PHP.
A way to find out would be to simply override SessionHandler::write() to always return false and see what happens. Check the console for any warnings.
Related
My previous question (ob_get_status() has undocumented bits set in 'flags' entry) revealed that there are some undocumented flags that may be passed into output buffer callback functions (i.e. the function specified when setting your output buffer, using ob_start()).
One of these flags (undocumented, but revealed by the PHP source code) is PHP_OUTPUT_HANDLER_DISABLED and this is what I am receiving when I call ob_get_status(true) in my application.
My question is, what are the situations that can cause an output buffer to be marked as disabled?
(Note that I am asking in the general case, rather than specifically asking about my code, as I feel that too much context would be required to give a specific answer. If I understand the possible reasons, I hope I can deduce which of them might apply in my situation.)
I think I've cracked it!
It looks like there is a bug in PHP >= 5.4 that affects the way false is handled when returned from an output buffer callback function after a 'clean' operation.
The documentation states:
If callback returns false original input is sent to the browser.
This statement implies that the following two callbacks are always identical:
function OBCallback($Output) {
return $Output;
}
function OBCallback($Output) {
return false;
}
On PHP 5.3 and below, that is true - they do behave in an identical manner. However, on PHP 5.4 and above, there is a difference when the callback is being called in the context of a 'clean' operation.
In this situation, returning false from the function is treated as an error, and this results in the output buffer being disabled. This is why my code has the PHP_OUTPUT_HANDLER_DISABLED flag set in the handler's status entry; my code includes an ob_clean() at one point and my handler is returning false in all instances.
Paradoxically, returning the supplied buffer in response to a 'clean' operation (which contains the contents of the buffer prior to the clean) does not cause an error, nor does it cause the returned buffer to be output.
This is the exact opposite of what you might expect - surely, returning a non-empty buffer in response to a 'clean' operation should result in an error, whilst returning false (indicating 'continue with default action') should result in the buffer being cleaned automatically.
In addition, no PHP error, warning or notice is raised when this happens, so you will not be notified that your handler was disabled!
I have created a fiddle to demonstrate the two scenarios, to show how it differs between PHP versions: https://3v4l.org/66cai
tl;dr
Make sure you always return a string from your callback function, rather than false, to avoid weird bugs (despite what the documentation says).
Under certain circumstances, the built-in function in PHP called mysqli_query returns null. Such behaviour is not foreseen by the function's documentation that explains how to use it, so I tried to dive in PHP's source code itself, posted on GitHub, to see if I can figure out why sometimes mysqli_query returns null.
The queries themselves doesn't seem to be the problem: I tested the relevant SQL queries in two different ways:
Executing them manually in the MySQL Server. They work correctly.
Within a script that I created with the single purpose of testing the queries through mysqli_query(). They work under this test, and the function returns true.
However, under certain conditions, those same queries return null. The mysqli link object exists when mysqli_query function starts running, when this "returning null failure" happens.
So, looking in the PHP's GitHub repository, i found the file called mysqli_nonapi.c and, in line 556 within this file, what seems to be the built-in mysqli_query definition. Looking at the code within, it looks like it performs a basic check and, if it fails, it returns null. Here are the first lines linked above:
/* {{{ proto mixed mysqli_query(object link, string query [,int resultmode]) */
PHP_FUNCTION(mysqli_query){
MY_MYSQL *mysql;
zval *mysql_link;
MYSQLI_RESOURCE *mysqli_resource;
MYSQL_RES *result = NULL;
char *query = NULL;
size_t query_len;
zend_long resultmode = MYSQLI_STORE_RESULT;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os|l", &mysql_link, mysqli_link_class_entry, &query, &query_len, &resultmode) == FAILURE) {
return;
}
// [...]
}
Even though I have used sometimes C code, I just know a little about C. I am aware that it uses pointers and I guess those parameters which name start with * are pointers. Anyways, I am not sure on how to interpretate this piece of code, or figuring out how it's internal flow affects PHP execution.
Long story short: I can assume somehow, the initial check shown above within the function failed for some reason. But, to find out why, I need to understand that piece of code first.
I am afraid I cannot isolate the issue to trigger the error outside production environment, which would be very useful for exhaustive testing. So, what options do I have left? Is there something I can do to debug that internal piece of code, or otherwise, figuring out why it might be failing within?
I made the tests in both PHP5 and PHP7; it fails the same way in both of them.
This is called undefined behaviour in PHP. Most instances of it have been eradicated in PHP 8, but prior to that version when you passed a wrong parameter to a built-in function, that function would usually throw a warning and return null (or false).
There were a lot of circumstances when no warning was produced at all! This behaviour was not documented on each page as this would be a mess and by definition "undefined behaviour" has no defined behaviour.
This means that code like the following would throw no warning and simply return null:
// V - string passed instead of a numerical value
var_dump(mysqli_query($mysqli, 'SELECT 1', 'foo'));
PHP was very forgiving with parameter types and when you passed the wrong type, it tried to convert it into the proper type, but when this was not possible then PHP had no defined behaviour of what should happen. Thankfully, this has been fixed in 99% of cases in PHP 8.0.
I noticed that in 95% of cases there is always just return; after evaluating zend_parse_parameters to FAILURE inside PHP_FUNCTION. It did not make sense because PHP_FUNCTION are expected to return ZVAL. I am not sure what default value of return_value is when it is not explicitly set.
I searched through all php sources and all extension sources that came bundled with php. In 95% of cases they simply used return. In few extensions - date and intl they do RETURN_FALSE. In an article written by Sara Colemon she used RETURN_NULL().
I feel strongly that I should be using RETURN_FALSE for most cases which make more sense for PHP_FUNCTIONs. Am I missing something somewhere?
If zend_parse_parameters() fails, it is customary to simply return. That is documented in the PHP manual:
If zend_parse_parameters does not recieve what is specified by the Hacker as the correct arguments, and the arguments recieved cannot be converted to conform with type_spec an error will be raised, and by convention, the Hacker should return immediately.
According to the PHP manual, the type of return_value defaults to IS_NULL:
Pointer to a PHP variable that can be filled with the return value passed to the user. The default type is IS_NULL.
Furthermore, the PHP manual notes:
If the parameters given to a function are not what it expects, such as passing an array where a string is expected, the return value of the function is undefined. In this case it will likely return NULL but this is just a convention, and cannot be relied upon.
So the actual return value in case of failing zend_parse_parameters() has to be regarded as implementation detail, and consequently, simply returning appears to be most appropriate – just let the Zend engine decide about the default.
I've seen tons of threads about what to return in case a PHP function fails. But they were all about PHP 4.
Now in my most recent (PHP 5) project, I want to enforce some sort of consistency with return types (I don't even know, if it's gonna be worth it down the road). So if the normal return type of a method is an array, what should I return in case the method fails?
null
empty array()
throw an exception instead
In C# I would return null, so should I write PHP constantly thinking what I would do in a strongly typed language? Or does something make more sense in this specific scenario? What are the pros and cons for each of the options?
If there was no error in performing the logic of your method (in which case I would suggest throwing an exception), I would say return an empty array. It would make an situation like this easier to deal with:
foreach($obj->method() as $item)
{
// ...
}
If YourClass::method() returned null, I would get an "Invalid argument supplied" warning, whereas returning an empty array would never trigger that.
Whatever you end up choosing, stick with it. No one likes working with an API whose return values are inconsistent, and have no logical meaning.
I would throw an exception on an unrecoverable error.
For example, let's say you have a method like getById($id). It is ok to return null if nothing is found. Now let's say you have another method, delete($id) that will itself call getById($id). In this case, if nothing is found (i.e: getById returned null) an exception should be thrown.
Remember that whenever you report an error with a return value, being a null, empty array or string, or even a integer, you will need to handle this error, probably doing some cleanup somewhere else depending on the returned value. This might lead to some dirty in all the methods/functions involved.
Using exceptions will allow you to handle and catch these errors at one place only (at the catch). So you dont have to replicate the code that checks for the error (was the return an empty array? was the return value 1, 2, or 9?, etc). Besides that, using exceptions lets you easily "catalog" the kind of error (like a business logic exception, or an invalid arguments) without writing a lot of if's along the source.
So if a function/method returns something (i.e: it terminated normally), the return value is something you can use (an empty array, a null, or empty string, are all valid return values). If a function/method throws an exception, clearly something went wrong.
Another important thing is that null can be equals to false, 0, and an empty string if you dont use strict checking (=== vs. ==) so this might lead to other kind of bugs. This is where exceptions can also be an advantage.
And of course, whatever you decide, the important thing is to be consistent with your choices along the code.
If a function really 'fails', then I would go for an exception. Exceptions are meant to indicate a failure.
Still, at some point you need to decide what to do with the exception, and then it might very well be that you decide that returning an empty array might be the best. That would for example be useful if you want to keep your existing foreach() loops working.
Thus, use exceptions, but think about where you want to catch them and process them into something useful for the user.
If the method fails it should be classified as an exception IMO this will allow you to properly catch the expected expections and act upon them.
I'm a strong believer in normalizing responses from functions and methods. It makes life a lot easier when you know what the function will return.
In short if it fails throw and exception if it doesn't ensure an array is returned, my $0.02
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;.