Which better ways exist to avoid an abundance of isset()
in the application logic, and retain the ability to see debug messages (E_NOTICE) when required?
Presumption first: E_NOTICE is not an error, it's a misnomer and should actually be E_DEBUG. However while this is true for unset variables (PHP is still a scripting language), some file system functions etc. throw them too. Hence it's desirable to develop with E_NOTICEs on.
Yet not all debug notices are useful, which is why it's a common (unfortunate) PHP idiom to introduce isset()
and @ throughout the application logic. There are certainly many valid use cases for isset/empty, yet overall it seems syntactic salt and can actually obstruct debugging.
That's why I currently use an error_reporting bookmarklet and a dumb on/off switch:
// javascript:(function(){document.cookie=(document.cookie.match(/error_reporting=1/)?'error_reporting=0':'error_reporting=1')})()
if (($_SERVER["REMOTE_ADDR"] == "127.0.0.1")
and $_COOKIE["error_reporting"])
{
error_reporting(E_ALL|E_STRICT);
}
else {/* less */}
However that still leaves me with the problem of having too many notices to search through once enabled. As workaround I could utilize the @ error suppression operator. Unlike isset() it does not completely kill debugging options, because a custom error handler could still receive suppressed E_NOTICEs. So it might help to separate expected debug notices from potential issues.
Yet that's likewise unsatisfactory. Hence the question. Does anyone use or know of a more sophisticated PHP error handler. I'm imagining something that:
Surely some framework must already have a user error handler like that.
Oh my, someone please help rewrite this. Lengthy explanation fail.
The isset() function is an inbuilt function in PHP which checks whether a variable is set and is not NULL. This function also checks if a declared variable, array or array key has null value, if it does, isset() returns false, it returns true in all other possible cases.
PHP isset() Function The isset() function checks whether a variable is set, which means that it has to be declared and is not NULL. This function returns true if the variable exists and is not NULL, otherwise it returns false.
It is possible to develop a large PHP application that never emits any E_NOTICEs. All you have to do is avoid all situations where a Notice can be emitted, the vast majority of which are un-initialized variables and non-existist array keys. Unfortunately, this clashes with your wish to avoid isset()
- and by extension array_key_exists()
- because they are designed for handling that exact problem.
At best, you can minimize their use by careful framework building. This generally means (for example) an input layer which is told what GET
variables to expect and what to default missing ones to. That way the page-specific code will always have values to look at. This is, in general, a worthwhile technique that can be applied to a variety of APIs. But I question whether this should be a high-priority design goal.
Unlike some other languages, PHP distinguishes between a variable not existing and containing a generally "empty" value (usually null
). It is probably a design artifact from an earlier version, but it nonetheless is still present, so you cannot really avoid it.
I am using isset()
only for $_GET
and $_SERVER
variables, where the data comes from outside the control of my application. And I am using it in some other situation when I don't have time to write a proper OOP solution to avoid it, but I'm sure that it can be avoided in most if not all places. For example it's better to use classes instead of associative arrays, this way you don't need to check the existence of an array key.
My advices are:
@
operator.xdebug.collect_params=4
and xdebug.show_local_vars=on
configuration parameters). Second, it can disable the @
operator with xdebug.scream=1
config value. You can use Xdebug for profiling and for code coverage analysis as well. It's a must have on your development machine.I am using a modified version of the example in the PHP manual:
<?php
//error_reporting(0);
set_error_handler("errorHandler");
function errorHandler($errno, $errstr, $errfile, $errline)
{
echo "errorHandler()<br />\n";
// filter out getImageSize() function with non existent files (because I'am avoiding using file_exists(), which is a costly operation)
if ( mb_stripos($errstr, 'getimagesize') !== false )
return true;
// filter out filesize() function with non existent files
if ( mb_stripos($errstr, 'filesize') !== false )
return true;
// consoleWriter is my class which sends the messages with FirePHP
if (class_exists('consoleWriter'))
consoleWriter::debug(array('errno'=>$errno, 'errstr'=>$errstr, 'errfile'=>$errfile, 'errline'=>$errline, 'trace'=>debug_backtrace()), "errorHandler");
switch ($errno) {
case E_USER_ERROR:
$out .= "<b>FATAL_ERROR</b> <i>$errno</i> $errstr<br />\n";
$out .= "Fatal error on line $errline in file $errfile";
echo "</script>$out"; // if we were in a script tag, then the print is not visible without this
//writeErrorLog($out);
echo "<pre>";
var_export(debug_backtrace());
echo "</pre>";
exit(1);
break;
case E_USER_WARNING:
$out .= "<b>WARNING</b> <i>$errno</i> $errstr<br />\n";
$out .= "On line $errline in file $errfile<br />\n";
break;
case E_USER_NOTICE:
$out .= "<b>NOTICE</b> <i>$errno</i> $errstr<br />\n";
$out .= "On line $errline in file $errfile<br />\n";
break;
default:
$out .= "<b>Unknown</b> <i>$errno</i> $errstr<br />\n";
$out .= "On line $errline in file $errfile<br />\n";
break;
}
if (!class_exists('consoleWriter'))
echo $out;
//writeErrorLog($out);
//addJGrowlMessage($out);
// Don't execute PHP internal error handler
return true;
}
function testNotice($a)
{
echo $a;
}
testNotice();
One more advice is not to use the closing ?>
tag at the end of the php-only files, because it can cause headers already sent
errors on configurations where the output buffering is disabled by default.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With