I have big DB function which has multiple lines like this
RAISE NOTICE 'some step completed';
I want to get all this notices in my PHP application. I found only pg_last_notice() function which only returns the very last notice.
Is there any way I can get all notices?
Example:
DB function:
CREATE OR REPLACE FUNCTION do_smth()
RETURNS void AS
$BODY$
BEGIN
-- some actions
RAISE NOTICE 'Result of the actions:...';
-- some other actions
RAISE NOTICE 'Result of the other actions..';
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
PHP code:
<?php
// ...
$db->exec("SELECT do_smth()"); // executing DB function
$last_notice = pg_last_notice($db_connection);
// returns 'NOTICE: Result of the other actions..'
According to the libpq notice documentation "The default notice handling function prints the message on stderr, but the application can override this behavior by supplying its own handling function."
In your case the "application" (php itself) is overriding this behavior by specifying custom notice handler, called _php_pgsql_notice_handler:
Line #1367: PQsetNoticeProcessor(pgsql, _php_pgsql_notice_handler, (void*)Z_RESVAL_P(return_value));
That means that PostgreSQL notices are not propagated further into stderr, but are captured and processed by that handler.
In the handler itself (line #827) you can see that every time a notice is issued, php updates the variable holding it, and does not append the value to some array. Hence at the end only the last notice is present in that variable, obtainable by calling pg_last_notice().
So, it looks like it is not possible to obtain previous PostgreSQL notices from within PHP.
However, if you look further into the same notice handler, you would see that it is writing the notices to the error log, in case pgsql.ignore_notices = 0, pgsql.log_notices = 1 and E_NOTICE is included into the error_reporting. I guess with some php error handling functions juggling you will be able to obtain something.
pg_last_notice() now accepts an optional parameter to specify an operation.
This can be done with one of the following new constants:
PGSQL_NOTICE_LAST: to return last notice
PGSQL_NOTICE_ALL: to return all notices
PGSQL_NOTICE_CLEAR: to clear notices
More info for Changed Functions in version 7.1 HERE.
Related
I have seen uses of # in front of certain functions, like the following:
$fileHandle = #fopen($fileName, $writeAttributes);
What is the use of this symbol?
It suppresses error messages — see Error Control Operators in the PHP manual.
It suppresses errors.
See Error Control Operators in the manual:
PHP supports one error control operator: the at sign (#). When prepended to an expression in PHP, any error messages that might be generated by that expression will be ignored.
If you have set a custom error handler function with set_error_handler() then it will still get called, but this custom error handler can (and should) call error_reporting() which will return 0 when the call that triggered the error was preceded by an #...
The # symbol is the error control operator (aka the "silence" or "shut-up" operator). It makes PHP suppress any error messages (notice, warning, fatal, etc) generated by the associated expression. It works just like a unary operator, for example, it has a precedence and associativity. Below are some examples:
#echo 1 / 0;
// generates "Parse error: syntax error, unexpected T_ECHO" since
// echo is not an expression
echo #(1 / 0);
// suppressed "Warning: Division by zero"
#$i / 0;
// suppressed "Notice: Undefined variable: i"
// displayed "Warning: Division by zero"
#($i / 0);
// suppressed "Notice: Undefined variable: i"
// suppressed "Warning: Division by zero"
$c = #$_POST["a"] + #$_POST["b"];
// suppressed "Notice: Undefined index: a"
// suppressed "Notice: Undefined index: b"
$c = #foobar();
echo "Script was not terminated";
// suppressed "Fatal error: Call to undefined function foobar()"
// however, PHP did not "ignore" the error and terminated the
// script because the error was "fatal"
What exactly happens if you use a custom error handler instead of the standard PHP error handler:
If you have set a custom error handler function with
set_error_handler() then it will still get called, but this custom
error handler can (and should) call error_reporting() which will
return 0 when the call that triggered the error was preceded by an #.
This is illustrated in the following code example:
function bad_error_handler($errno, $errstr, $errfile, $errline, $errcontext) {
echo "[bad_error_handler]: $errstr";
return true;
}
set_error_handler("bad_error_handler");
echo #(1 / 0);
// prints "[bad_error_handler]: Division by zero"
The error handler did not check if # symbol was in effect. The manual suggests the following:
function better_error_handler($errno, $errstr, $errfile, $errline, $errcontext) {
if(error_reporting() !== 0) {
echo "[better_error_handler]: $errstr";
}
// take appropriate action
return true;
}
Also note that despite errors being hidden, any custom error handler (set with set_error_handler) will still be executed!
Like already some answered before: The # operator suppresses all errors in PHP, including notices, warnings and even critical errors.
BUT: Please, really do not use the # operator at all.
Why?
Well, because when you use the # operator for error supression, you have no clue at all where to start when an error occurs. I already had some "fun" with legacy code where some developers used the # operator quite often. Especially in cases like file operations, network calls, etc. Those are all cases where lots of developers recommend the usage of the # operator as this sometimes is out of scope when an error occurs here (for example a 3rdparty API could be unreachable, etc.).
But what's the point to still not use it? Let's have a look from two perspectives:
As a developer: When # is used, I have absolutely no idea where to start. If there are hundreds or even thousands of function calls with # the error could be like everyhwere. No reasonable debugging possible in this case. And even if it is just a 3rdparty error - then it's just fine and you're done fast. ;-) Moreover, it's better to add enough details to the error log, so developers are able to decide easily if a log entry is something that must be checked further or if it's just a 3rdparty failure that is out of the developer's scope.
As a user: Users don't care at all what the reason for an error is or not. Software is there for them to work, to finish a specific task, etc. They don't care if it's the developer's fault or a 3rdparty problem. Especially for the users, I strongly recommend to log all errors, even if they're out of scope. Maybe you'll notice that a specific API is offline frequently. What can you do? You can talk to your API partner and if they're not able to keep it stable, you should probably look for another partner.
In short: You should know that there exists something like # (knowledge is always good), but just do not use it. Many developers (especially those debugging code from others) will be very thankful.
Suppose we haven't used the "#" operator then our code would look like this:
$fileHandle = fopen($fileName, $writeAttributes);
And what if the file we are trying to open is not found? It will show an error message.
To suppress the error message we are using the "#" operator like:
$fileHandle = #fopen($fileName, $writeAttributes);
# suppresses error messages.
It is used in code snippets like:
#file_get_contents('http://www.exaple.com');
If domain "http://www.exaple.com" is not accessible, an error will be shown, but with # nothing is shown.
If the open fails, an error of level E_WARNING is generated. You may use # to suppress this warning.
PHP supports one error control operator: the at sign (#). When prepended to an expression in PHP, any error messages that might be generated by that expression will be ignored.
If you have set a custom error handler function with set_error_handler() then it will still get called, but this custom error handler can (and should) call error_reporting() which will return 0 when the call that triggered the error was preceded by an #.
<?php
/* Intentional file error */
$my_file = #file ('non_existent_file') or
die ("Failed opening file: error was '$php_errormsg'");
// this works for any expression, not just functions:
$value = #$cache[$key];
// will not issue a notice if the index $key doesn't exist.
?>
Note:-
1) The #-operator works only on expressions.
2) A simple rule of thumb is: if you can take the value of something, you can prepend the # operator to it. For instance, you can prepend it to variables, function and include calls, constants, and so forth. You cannot prepend it to function or class definitions, or conditional structures such as if and foreach, and so forth.
Warning:-
Currently the "#" error-control operator prefix will even disable
error reporting for critical errors that will terminate script
execution. Among other things, this means that if you use "#" to
suppress errors from a certain function and either it isn't available
or has been mistyped, the script will die right there with no
indication as to why.
It might be worth adding here there are a few pointers when using the # you should be aware of, for a complete run down view this post: http://mstd.eu/index.php/2016/06/30/php-rapid-fire-what-is-the-symbol-used-for-in-php/
The error handler is still fired even with the # symbol prepended, it just means a error level of 0 is set, this will have to be handled appropriately in a custom error handler.
Prepending a include with # will set all errors in the include file to an error level of 0
# suppresses the error message thrown by the function. fopen throws an error when the file doesn't exit. # symbol makes the execution to move to the next line even the file doesn't exists. My suggestion would be not using this in your local environment when you develop a PHP code.
I'm referring to How to enable notices on my development server
I expect the following code shall give me some warning, when I execute it through, as my $a is not explicitly declared as array
php a.php
<?php
ini_set('display_errors', 1);
error_reporting(E_NOTICE);
$a['key'] = 123;
echo $a['key'] . "\n";
However, no warning message being printed. Is there anything I had missed?
The PHP I'm using is PHP 5.5.3. I'm not sure this matters?
I expect the following code shall give me some warning, when I execute it through, as my $a is not explicitly declared as array
Wrong... by writing $a['key'] = 123; you declare an array and set the key key to the integer number 123. That's a valid PHP array initialization. (The PHP version does not matter in this case.)
To explicitely produce an error notice for testing purposes…
If you want to provoke an error notice for testing purposes, you could add this line:
count($ThisIsNotDefinedOnPurpose);
which will produce an error notice saying
Notice: Undefined variable: ThisIsNotDefinedOnPurpose in … on line …
Edit 2022: This appears to be fixed as of PHP 7.4 which emits a notice.
In PHP, I have error_reporting set to report everything including notices.
Why does the following not throw any notices, errors or anything else?
$myarray = null;
$myvalue = $myarray['banana'];
Troubleshooting steps:
$myarray = array();
$myvalue = $myarray['banana'];
// throws a notice, as expected ✔
$myarray = (array)null;
$myvalue = $myarray['banana'];
// throws a notice, as expected ✔
$myarray = null;
$myvalue = $myarray['banana'];
// no notice or warning thrown, $myvalue is now NULL. ✘ Why?
It's possible it's a bug in PHP, or I'm just not understanding something about how this works.
There are three types which it might be valid to use the array derefence syntax on:
Arrays
Strings (to access the character at the given position)
Object (objects implementing the ArrayAccess interface)
For all other types, PHP just returns the undefined variable.
Array dereference is handled by the FETCH_DIM_R opcode, which uses zend_fetch_dimension_address_read() to fetch the element.
As you can see, there is a special case for NULLs, and a default case, both returning the undefined variable.
Usually, when you try to use a value of one type as if it were another type, either an error or warning gets thrown or "type juggling" takes place. For example, if you try to concatenate two numbers with ., they'll both get coerced to strings and concatenated.
However, as explained on the manual page about type juggling, this isn't the case when treating a non-array like an array:
The behaviour of an automatic conversion to array is currently undefined.
In practice, the behaviour that happens when this "undefined behaviour" is triggered by dereferencing a non-array is that null gets returned, as you've observed. This doesn't just affect nulls - you'll also get null if you try to dereference a number or a resource.
There is an active bug report started at 2006.
And in documentation it is a notice about this in String section.
As of PHP 7.4, this behavior how emits a Notice.
"Trying to access array offset on value of type null"
See the first item in this 7.4 migration page.
https://www.php.net/manual/en/migration74.incompatible.php
This recently struck one of my colleagues in the butt because he neglected to validate the result of a database query before attempting to access column data from the variable.
$results = $this->dbQuery(...)
if($results['columnName'] == 1)
{
// WHEN $results is null, this Notice will be emitted.
}
And I just noticed #Glen's comment, above, citing the relevant RFC.
https://wiki.php.net/rfc/notice-for-non-valid-array-container
Currently, PHP would trigger (and log if logging is enabled) E_NOTICE 'errors' when accessing undefined variables and array indexes. Is there a way to make it abort on these, so that I know I don't miss any. Frankly, IMO, far too often a script SHOULD abort on such condition anyway, as it will inevitably break something farther down the execution path. In all other cases there is the '#' operator, that's what it is for, right?
I know I can use a custom error handler and abort on any condition. In fact I do use one already, but I do have places where I trigger notices myself (granted, E_USER_NOTICE instead of PHP's own E_NOTICE), and I also always return false letting PHP's own internal handler do its job - logging and aborting on errors, continuing on everything else.
Then there are other cases where PHP produces E_NOTICE without me wanting to abort the script. Basically, there is no way for me to know if a particular E_NOTICE is a result of an unset variable or a totally harmless condition (which notices should be caused by anyway).
Has anyone a neat and non-hackish solution? Some recommended way of doing this?
Cheers.
I'm sure there is no native PHP way to do this.
Extending your already existent error handler to look into the error message (stristr($errmsg, "undefined variable") ...) and die() if necessary is the best (and only) way that comes to mind.
You can user PHP function set_error_handler() to register a custom function that will handles any PHP error. Specify E_NOTICE as the second parameter so that your custom function will only receive E_NOTICE error. Then in that function, simply do 'exit;' if the second parameter which is the error message starts with 'Undefined offset:'.
Rather than try to hack around PHP's error handling, I suggest you enforce some constraints on your script and check your variables with PHP's isset, empty and is_null functions.
I'm not sure what you want. You want to abort on notices, but not every notice? You want to distinguish between the several types of E_NOTICES and abort on some? The only way to do this is to check the message in the error handler and not abort if the message is about undefined variables – which you shouldn't use, by the way.
I have seen uses of # in front of certain functions, like the following:
$fileHandle = #fopen($fileName, $writeAttributes);
What is the use of this symbol?
It suppresses error messages — see Error Control Operators in the PHP manual.
It suppresses errors.
See Error Control Operators in the manual:
PHP supports one error control operator: the at sign (#). When prepended to an expression in PHP, any error messages that might be generated by that expression will be ignored.
If you have set a custom error handler function with set_error_handler() then it will still get called, but this custom error handler can (and should) call error_reporting() which will return 0 when the call that triggered the error was preceded by an #...
The # symbol is the error control operator (aka the "silence" or "shut-up" operator). It makes PHP suppress any error messages (notice, warning, fatal, etc) generated by the associated expression. It works just like a unary operator, for example, it has a precedence and associativity. Below are some examples:
#echo 1 / 0;
// generates "Parse error: syntax error, unexpected T_ECHO" since
// echo is not an expression
echo #(1 / 0);
// suppressed "Warning: Division by zero"
#$i / 0;
// suppressed "Notice: Undefined variable: i"
// displayed "Warning: Division by zero"
#($i / 0);
// suppressed "Notice: Undefined variable: i"
// suppressed "Warning: Division by zero"
$c = #$_POST["a"] + #$_POST["b"];
// suppressed "Notice: Undefined index: a"
// suppressed "Notice: Undefined index: b"
$c = #foobar();
echo "Script was not terminated";
// suppressed "Fatal error: Call to undefined function foobar()"
// however, PHP did not "ignore" the error and terminated the
// script because the error was "fatal"
What exactly happens if you use a custom error handler instead of the standard PHP error handler:
If you have set a custom error handler function with
set_error_handler() then it will still get called, but this custom
error handler can (and should) call error_reporting() which will
return 0 when the call that triggered the error was preceded by an #.
This is illustrated in the following code example:
function bad_error_handler($errno, $errstr, $errfile, $errline, $errcontext) {
echo "[bad_error_handler]: $errstr";
return true;
}
set_error_handler("bad_error_handler");
echo #(1 / 0);
// prints "[bad_error_handler]: Division by zero"
The error handler did not check if # symbol was in effect. The manual suggests the following:
function better_error_handler($errno, $errstr, $errfile, $errline, $errcontext) {
if(error_reporting() !== 0) {
echo "[better_error_handler]: $errstr";
}
// take appropriate action
return true;
}
Also note that despite errors being hidden, any custom error handler (set with set_error_handler) will still be executed!
Like already some answered before: The # operator suppresses all errors in PHP, including notices, warnings and even critical errors.
BUT: Please, really do not use the # operator at all.
Why?
Well, because when you use the # operator for error supression, you have no clue at all where to start when an error occurs. I already had some "fun" with legacy code where some developers used the # operator quite often. Especially in cases like file operations, network calls, etc. Those are all cases where lots of developers recommend the usage of the # operator as this sometimes is out of scope when an error occurs here (for example a 3rdparty API could be unreachable, etc.).
But what's the point to still not use it? Let's have a look from two perspectives:
As a developer: When # is used, I have absolutely no idea where to start. If there are hundreds or even thousands of function calls with # the error could be like everyhwere. No reasonable debugging possible in this case. And even if it is just a 3rdparty error - then it's just fine and you're done fast. ;-) Moreover, it's better to add enough details to the error log, so developers are able to decide easily if a log entry is something that must be checked further or if it's just a 3rdparty failure that is out of the developer's scope.
As a user: Users don't care at all what the reason for an error is or not. Software is there for them to work, to finish a specific task, etc. They don't care if it's the developer's fault or a 3rdparty problem. Especially for the users, I strongly recommend to log all errors, even if they're out of scope. Maybe you'll notice that a specific API is offline frequently. What can you do? You can talk to your API partner and if they're not able to keep it stable, you should probably look for another partner.
In short: You should know that there exists something like # (knowledge is always good), but just do not use it. Many developers (especially those debugging code from others) will be very thankful.
Suppose we haven't used the "#" operator then our code would look like this:
$fileHandle = fopen($fileName, $writeAttributes);
And what if the file we are trying to open is not found? It will show an error message.
To suppress the error message we are using the "#" operator like:
$fileHandle = #fopen($fileName, $writeAttributes);
# suppresses error messages.
It is used in code snippets like:
#file_get_contents('http://www.exaple.com');
If domain "http://www.exaple.com" is not accessible, an error will be shown, but with # nothing is shown.
If the open fails, an error of level E_WARNING is generated. You may use # to suppress this warning.
PHP supports one error control operator: the at sign (#). When prepended to an expression in PHP, any error messages that might be generated by that expression will be ignored.
If you have set a custom error handler function with set_error_handler() then it will still get called, but this custom error handler can (and should) call error_reporting() which will return 0 when the call that triggered the error was preceded by an #.
<?php
/* Intentional file error */
$my_file = #file ('non_existent_file') or
die ("Failed opening file: error was '$php_errormsg'");
// this works for any expression, not just functions:
$value = #$cache[$key];
// will not issue a notice if the index $key doesn't exist.
?>
Note:-
1) The #-operator works only on expressions.
2) A simple rule of thumb is: if you can take the value of something, you can prepend the # operator to it. For instance, you can prepend it to variables, function and include calls, constants, and so forth. You cannot prepend it to function or class definitions, or conditional structures such as if and foreach, and so forth.
Warning:-
Currently the "#" error-control operator prefix will even disable
error reporting for critical errors that will terminate script
execution. Among other things, this means that if you use "#" to
suppress errors from a certain function and either it isn't available
or has been mistyped, the script will die right there with no
indication as to why.
It might be worth adding here there are a few pointers when using the # you should be aware of, for a complete run down view this post: http://mstd.eu/index.php/2016/06/30/php-rapid-fire-what-is-the-symbol-used-for-in-php/
The error handler is still fired even with the # symbol prepended, it just means a error level of 0 is set, this will have to be handled appropriately in a custom error handler.
Prepending a include with # will set all errors in the include file to an error level of 0
# suppresses the error message thrown by the function. fopen throws an error when the file doesn't exit. # symbol makes the execution to move to the next line even the file doesn't exists. My suggestion would be not using this in your local environment when you develop a PHP code.