Is it possible to point all notices and warnings inside try/catch in exceptions. But do it only in try, the rest of the code should use default error handling. The main problem is that the try is in the while loop and can be called several times so i think it isnt a good idea to use set_error_handler and restore_error_handler several times. Maybe php have something like in java?
The only way is to use error handler. But you can configure the error handler to throw or not to throw exceptions:
class ErrorHandler {
public static $throw = false;
public static function handler() {
if(self::$throw) throw new Exception();
}
}
set_error_handler(array('ErrorHandler', 'handler'));
ErrorHandler::$throw = true;
Related
I want to get an errors object from a callback function. here is what i have done so far.
$errors = null;
set_exception_handler(function($exception) use (&$errors) {
$errors = $exception;
var_dump($exception); // works fine
});
var_dump($errors); // give null ????
throw new Exception("blablblablablabla", 0);
I am sure with an anonymous function and a variable would work very fine !
But in this case with a callback and object I am not sure what's going on ? i can't get my head a round. any help explanation would be really appreciated.
set_exception_handler does not stop execution. It just defines what will happen if/when an exception occurs, so you can var_dump($errors); errors after setting it. $errors will still be null at that point because you have set it to null, and nothing has happened yet to change that.
The thing that does stop execution is when an exception actually occurs and the anonymous function defined in set_exception_handler is called. At that point, the var_dump($exception); within that function is called, but any other code in the main program after the point where the exception occurred will not be executed.
Storing the exception in a global variable from within the exception handler doesn't make really sense, because if the exception handler is called, no more code in the main program will be executed, so you won't be able to use that variable anyway.
You are assigning the anonymous function as an exception handler with set_exception_handler().
Yet you do not throw an exception in your code. Therefore the anonymous function is never called, because there was no event to handle, which means that $error was never set.
If you add a try catch block your function will also not be called. This can be seen by the fact, that the line var_dump($exception) from within your handler is not called either.
If you want to store the last called exception in your code, you may need to use a wrapper function around that code, that uses try catch to overwrite a static resource with the last exception encountered.
Note, that the exception within the given function is never fully thrown, because it was catched by the wrapper!
class Catcher {
private static $_EXCEPTION = null;
public static function GET_EXCEPTION () {
return self::$_EXCEPTION;
}
public static function run($func) {
try {
return $func();
} catch (Exception $e) {
self::$_EXCEPTION = $e;
}
}
}
var_dump(Catcher::GET_EXCEPTION()); //dumps NULL
Catcher::run(function(){
throw new Exception('I was called');
});
var_dump(Catcher::GET_EXCEPTION()); //dumps the last thrown exception
From my previous question I understand that isn't a good practice manage each exception with try/catch block, 'cause if I've hundred functions I should put hundred try/catch block.
Now I noticed the set_error_handler function, if I've understand correctly (never used it), allow me to swith in a file or function all the error generated in the whole scripts. So instead of put try catch block this function should automatically intercept the error and call a function, is right?
Now I already have a Log class that help me to write a stack trace in a file. This file is daily so I can see all system transaction in separated file.
My Log class is a SingleTon, so in each classes if I want write some trace in the log file I just need to do this:
Log::warning('some parameter here');
My goal is create an error.php file where all the error are switched in the Log::warning('...');. I think that this set_error_handler should be placed in the system core. As I said I never worked with it, someone could help me to achieve this with a bit example? I'll be glad.
set_error_handler is used to handle errors in a script not exceptions.
If you want to catch all exceptions from your application to apply the same process you have to call set_exception_handler PHPDoc.
This function takes a callable in argument, so your handler must be defined in another function.
The main difference between this function and a try catch block is that
Execution will stop after the exception_handler is called.
It's a also good practice to keep existing exception handlers possibly introduce by an included lib.
You can create a class to do this
class ErrorHandler
{
private $previousExceptionHandler;
public function registerExceptionHandler($callPrevious = true)
{
$prev = set_exception_handler(array($this, 'handleException'));
if ($callPrevious && $prev) {
$this->previousExceptionHandler = $prev;
}
}
public function handleException(\Exception $e)
{
// DO YOUR STUFF
if ($this->previousExceptionHandler) {
call_user_func($this->previousExceptionHandler, $e);
}
}
}
And to use it
$errorHandler = new ErrorHandler();
$errorHandler->registerExceptionHandler();
There are some good libs to do that and more, especially if you want to catch your exceptions for logging purpose. You can try the excellent Monolog lib wihich is widely used, and its ErrorHandler class
Is a good idea throw exceptions on chained methods?
For example:
class Mailer(){
private $attachment;
public function addAttachment($attachment){
if($this->validateAttachment($attachment)){
$this->attachment = $attachment;
}
throw new \InvalidArgumentException('Invalid attachment');
}
public function send(){
[...]
}
private function validateAttachment($attachment){
if($attachment === 'test'){
return true;
}
return false;
}
}
$mailer = new Mailer();
$mailer->addAttachment('invalid')->send();
Of course, this will fail and cause a fatal error unless we use try / catch.
Otherwise, if we don't thrown an error when addAttachment fails, use will not notice if anything went wrong.
And if the send can work without attachments, we cannot return an error on that method neither.
So, there is any good practice on error logging / handling when using chained methods?
You should throw an Exception anywhere you want to interrupt the flow of the program. It doesn't matter if it's chained or not. In your case, if the adding of the attachment fails, you want to stop it before it reaches send(). That's a perfectly fine use of an Exception.
Obviously, you need to make sure you wrap the whole execution in try/catch or you'll get a Fatal error (where all PHP stops).
I recently have been asking question on exceptions and handling exceptions and such, which as recently best explained to me in this question. My question now is how would I use the
set_exception_handler();
in a class to set up a error handling class in php, that when ever an error is thrown is handled by this class. As the definition states:
Sets the default exception handler if an exception is not caught within a try/catch block. Execution will stop after the exception_handler is called.
I was thinking I could do something like:
class Test{
public function __construct(){
set_exception_handler('exception');
}
public function exception($exception){
echo $exception->getMessage();
}
}
But then the problem is that if the user is setting up the application or using any API from the application they have to do a whole: new Test();
So how could I write an exception handler class that is:
Automatically called when an exception is thrown to deal with the "uncaught" exception.
Done in an OOP way that is extendible.
The way I have shown is the only way I can think to do it.
For your class to work, the line inside your contructor should be:
// if you want a normal method
set_exception_handler(array($this, 'exception'));
// if you want a static method (add "static" to your handler method
set_exception_handler(array('Test', 'exception'));
Everybody thinks that using set_exception_handler would catch all the error in the PHP but it is not true as some errors are not handled by the set_exception_handler the proper way to handle all types of errors have to be done as:
//Setting for the PHP Error Handler
set_error_handler( call_back function or class );
//Setting for the PHP Exceptions Error Handler
set_exception_handler(call_back function or class);
//Setting for the PHP Fatal Error
register_shutdown_function(call_back function or class);
By setting these three setting you can catch all the errors of PHP.
I came across some code recently that used a custom error handler to turn any PHP errors into an generalized application exception. A custom exception handler was also defined that would log the exception if it was within a particular error code range. Example:
class AppException extends Exception
{
}
function error_handler($errno, $errstr, $errfile, $errline)
{
throw new AppException($errstr, $errno);
}
function exception_handler($exception)
{
$min = ...;
$max = ...;
if ($exception->getCode() >= $min && $exception->getCode() <= $max)
{
// log exception
}
}
set_error_handler('error_handler');
set_exception_handler('exception_handler');
$a[1]; // throws exception
The problem is that I saw things like:
try
{
do_something();
}
catch (AppException $exception)
{
}
Which implies that there is no distinction between actual programming errors and "Exceptional" behavior. Upon further digging, I came across parts of the code that were designed around the idea that PHP errors represented "Exceptional" behavior such as:
...
function my_function($param1, $param2)
{
// do something great
}
try
{
my_function('only_one_param');
}
catch (AppException $exception)
{
}
Which ends up obfuscating errors and the design of the application's interface.
What is your opinion on handling errors this way? Is it worth turning PHP's native errors into exceptions? What do you do in situations like the above where a codebase is designed around this idea?
Personally, I do this all the time. The only difference is that in my error_handler function, I check to see if the error is an E_NOTICE first, and only throw if it is not (I log the notice anyway)...
I would change the AppException to something that extends ErrorException... Something like: PhpRuntimeErrorException extends ErrorException which you ONLY use for PHP errors... The reason is so that it's more readable (it's easier to tell what a PhpRuntimeErrorException is without needing to figure out where it's thrown). The other reason, is that the ErrorException will store the generating line/file/etc information, where it would not be stored elsewhere (since the backtrace starts from the throw line)...
So, then you can "try" code like this:
try {
$f = fopen('foo.bar', 'r');
$ret = '';
while ($data = fread($f)) {
$ret .= process($data);
}
fclose($f);
return '';
} catch (PHPRuntimeErrorException $e) {
throw new RuntimeException('Could not open file');
} catch (ProcessException $e) {
fclose($f);
throw new RuntimeException('Could not process data');
}
return $ret;
I also make my default exception handler generate a 500 server error page. That's because any exceptions should be caught, and if they were not, it really is a server error...
Just my experience and opinion...
There has been some debate about this in the PHP community. I believe the general thinking is that errors are things thrown by internal PHP functions, and are coding problems you really need to fix; whereas exceptions are things thrown by your application code that you may just need to 'handle'.
However some of the newer SPL extensions (which tend to be more object oriented) do use exceptions for things previously might have thrown errors, so there is some grey area.
There's also a PHP core class ErrorException - http://www.php.net/manual/en/class.errorexception.php which looks a little easier to use than your code example, if this is a route you want to go down.
I convert everything, including notices to exceptions. There's no reason to allow exceptions to continue normally as it does. Undefined variable or offset? That's a problem.
https://github.com/KyleWolfe/PHPErrorNet