I have exception class:
class MartbooksException extends Exception
{
public function __construct($msg)
{
parent::__construct($msg, 0, null);
echo $msg;
Kohana::$log->add(Log::ERROR, $msg);
}
}
Kohana::$log->add(Log::ERROR, $msg);
Is this all I should do to write logs in application/logs files?
Is this good solution?
To follow the Kohana style I would recommend that you use:
Class Martbooks_Exception Extends Kohana_Exception
as declaration and place the file with name exception.php in classes/martbooks. This follows the style of Kohana.
Extending Kohana_Exception instead of Exception allows you to use variable substitution along the lines of
throw new Martbooks_Exception ('this is a :v', array (':v' => 'variable', ));
As for the defining a __construct()-method, the echo $msg; part would not be my preferred way of solving error handling, any echoing should be done in the block that catches the exception. The same could be argued for in the case of calling Kohana::$log->add(), but if you want log every Martbooks_Exception, your solution is perfectly valid. In that case I would rewrite your code to:
Class Martbooks_Exception Extends Kohana_Exception
{
public function __construct($message, array $variables = NULL, $code = 0)
{
parent::__construct ($message, $variables, $code);
Kohana::$log->add (Log::ERROR, __ ($message, $variables));
}
}
with a definition of __construct() that conforms to Kohana_Exception's __construct().
The only objection that I would have against logging with Log::ERROR level in the constructor is that it assumes that every exception is an application level error, which might be true of some exception types, but it could also be used to signal other meanings. The exact meaning of an exception should be left to the exception handling block.
To add a log message all you need is a single line indeed; Kohana::$log->add($level, $message[, $values]) see the api
Besides that, I don't think this is a valid solution. You had better create your own exception handler, as you can see on this page of the userguide
Related
I've been searching for an existing question that already asks this, but I wasn't able to find any questions that quite ask what I'm trying to figure out. The most similar question I could find was this: php 5.3 avoid try/catch duplication nested within foreach loop (code sandwich)
Okay so the place I work at has a web application with a PHP back end. We use an MVC type structure. I'm writing a controller that has multiple methods and in each of my methods I'm wrapping my code with identical try / catch code. In the catch, I pass the exception, a reference to the class, and a reference to the function to a method that builds an error message so that the error messages are formatted the same across the application. It looks something this:
class MyController {
public function methodA() {
try {
// code for methodA
} catch(Exception $e) {
$errorMessage = Tasks::buildErrorMessage($e, __CLASS__, __FUNCTION__);
throw new Exception($errorMessage);
}
}
public function methodB() {
try {
// code for methodB
} catch(Exception $e) {
$errorMessage = Tasks::buildErrorMessage($e, __CLASS__, __FUNCTION__);
throw new Exception($errorMessage);
}
}
public function methodC() {
try {
// code for methodC
} catch(Exception $e) {
$errorMessage = Tasks::buildErrorMessage($e, __CLASS__, __FUNCTION__);
throw new Exception($errorMessage);
}
}
}
So the buildErrorMessage function prevents each method from repeating the code that formats the error message, but there is something that really bothers me about have the same code spread through out every method in the class. I know that PHP doesn't support python-like decorator syntax, but just to demonstrate what I'm envisioning conceptually; I want the code to behave something more like this:
class MyController {
#DefaultErrorHandling()
public function methodA() {
// code for methodB
}
#DefaultErrorHandling()
public function methodB() {
// code for methodB
}
#DefaultErrorHandling()
public function methodC() {
// code for methodC
}
}
Where the #DefaultErrorHandling decorator would wrap each method in that standard try / catch. Is there a way I could achieve this behavior so I don't have to have all of these methods that have repeated code? Or am I thinking about error handling incorrectly?
Thanks to anyone who takes the time to answer this.
Have you looked at a writing a custom exception handler and using set_exception_handler?
What you are doing seems a bit like reinventing the wheel. Does the Exception not already have the info you are collecting in the trace? See: Exception::getTrace
Maybe buildErrorMessage does more? Anyway, I assume a custom exception handler is what you are after.
Not sure if there is a better way to solve this or not, but I created a logging class that formatted the log for me. Then just called this in my catch block.
To log the correct Class and Method, I the debug_backtrace() function. See this answer for more information.
Entry point that calls controller methods can wrap those calls with try / catch. That being said, if you are planning to use different type of error handlers on those methods then you can implement something in your base controller (or use trait) that keeps track of which handler should be invoked on each particular method. Something like
<?php
class MyController extends Controller
{
function __construct()
{
$this->setActionErrorHandler('function_name', 'handler');
}
}
Or just call it at the beginning of action method body. Keeping this type of configuration within class itself will help with readability. Not as neat as python example but better than somewhere in configuration files.
More generic error handlers can be implemented in php by using set_exception_handler mentioned by others.
I'm not really getting why there is such a requirement.
Hi devs
I have a simple PHP OO project. I have an exception who appears 2 times.
Something like :
if (!$x) {
throw new Exception("Don't use this class here.");
}
I want to dev a class in order to edit this code like that :
if (!$x) {
throw new ClassUsageException();
}
How to dev the Excpetion class with default Exception message ?
Thanks
I'd advise creating new exception classes sparsly. It is no fun to check a multitude of exceptions left and right. And if you really feel the need, check what kinds of exceptions are already defined and where in that hierarchy your exception will fit and then extend that class, i.e. give the developers a chance to catch a (meaningful) range of exceptions without having to explicitly write one catch-block after the other.
I'm really not sure what you're trying to achieve here with Don't use this class here. but it could be an InvalidArgumentException (or something derived from that exception, if you really must). There are other mechanisms to prevent an instance of a certain class at a specific place though.
You can extend the Exception class
<?php
Class ClassUsageException extends Exception {
public function __construct($msg = "Don't use this class here.", $code = 0) {
parent::__construct($msg, $code); //Construct the parent thus Exception.
}
}
try {
throw new ClassUsageException();
} catch(ClassUsageException $e) {
echo $e->getMessage(); //Returns Don't use this class here.
}
Is there anyway to disable the Laravel error handler all together?
I want to simply display standard PHP errors, not the Whoops, looks like something went wrong errors.
Not without majorly violating the principles of the framework (which I'll tell you how to do below, if you're still interested).
There's a few things that make this difficult to accomplish. It's easy enough to unset the default error and exception handlers
set_error_handler(null);
set_exception_handler(null);
but that leaves you with two major hurdles.
The first is Laravel registers a shutdown handler as part of its bootstrapping, and this shutdown function will look for the last error, and if it was a fatal error, manually call the exception handling code. There's no easy way to un-register a shutdown function.
The second is, the main Laravel Application handler looks like this
#File: vendor/laravel/framework/src/Illuminate/Foundation/Application.php
public function handle(SymfonyRequest $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true)
{
try
{
$this->refreshRequest($request = Request::createFromBase($request));
$this->boot();
return $this->dispatch($request);
}
catch (\Exception $e)
{
if ($this->runningUnitTests()) throw $e;
return $this['exception']->handleException($e);
}
}
That is -- if you application code throws an exception, Laravel catches it here and manually calls the exception's handleException method (which triggers the standard Laravel exception handling). There's no way to let PHP handle a fatal exception that happens in your application, Laravel blocks that from ever happening.
The part where I tell you how to do what you want
All this means we need to replace the main Laravel application with our own. In bootstrap/start.php, there's the following line
#File: bootstrap/start.php
$app = new Illuminate\Foundation\Application;
Replace it with the following
ini_set('display_errors','1');
class MyApplication extends Illuminate\Foundation\Application
{
function startExceptionHandling()
{
//do nothing
}
public function handle(Symfony\Component\HttpFoundation\Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true)
{
$this->refreshRequest($request = Request::createFromBase($request));
$this->boot();
return $this->dispatch($request);
}
}
$app = new MyApplication;
The first thing we're doing is setting PHP's display errors ini to 1. This makes sure errors are output to the browser.
Next, we're defining a new application class that extends the real application class.
Finally, we replace the real Laravel $app object with an object instantiated by our class.
In our application class itself we blank out startExceptionHandling. This prevents Laravel from setting up custom exception, error, and shutdown callbacks. We also define handle to remove the application boot/dispatch from a try/catch. This is the most fragile part of the process, and may look different depending on your Laravel version.
Final Warnings
If the handle method changes in future version of Laravel this will break.
If custom packages rely on adding custom exception handlers, they may break.
I'd recommend staying away from this as anything other than a temporary debugging technique.
Then set 'debug' => false, in \config\local\app.php file
<?php
return array(
'debug' => false,
);
In laravel 5 to disable debug, you just need to comment
//'debug' => env('APP_DEBUG'),
in \config\app.php file
Exception handling is hardcoded into the Application class. You can override the classes in your bootstrap/start.php file:
class ExceptionHandler {
public function handleException($exception) {
throw $exception;
}
public function handleConsole($exception) {
throw $exception;
}
}
class MyApplication extends Illuminate\Foundation\Application
{
public function registerExceptionProvider() {}
public function startExceptionHandling() {}
}
$app = new MyApplication;
It should go without saying that this is definitely not encouraged.
In file .env, just change:
APP_DEBUG=true
To:
APP_DEBUG=false
Related to the question: Laravel has a built in method for disabling exceptions in unit tests:
$this->withoutExceptionHandling()
Laracast on the subject: https://laracasts.com/series/whats-new-in-laravel-5-5/episodes/17
This will get you close. There might be a more proper way of doing this. It replaces Laravel's current exception handler with a single-method class. I haven't tested this, besides the basic route below, so you may need to add other methods to satisfy different situations.
class ExceptionHandler
{
public function handleException($e)
{
echo $e;
die;
}
}
App::bind('exception', App::share(function($app)
{
return new ExceptionHandler;
}));
Route::get('/', function()
{
throw new Exception('Testing');
});
I witnessed some strange behaviour regarding PHP's exception handling in a recent project. Case goes as follows.
In my app, I use namespaces. All classes are in individual source code files. The code relevant to this particular case, is spread over 3 classes.
The "outermost" class is a dispatcher (or router), which wraps the dispatch call inside a try-catch block. The dispatched request, calls a method in a third class, which runs code (wrapped in a try-catch block), which causes an exception.
Because I had omitted a use Exception; statement in the class where the error happens, the thrown exception trickles all the way back to the outermost layer (the dispatcher), where it is caught - causing me to scratch my head why the catch around the code causing the error isn't working.
To me this seems strange. Logically, PHP should in this situation (IMO) throw a Class not found exception/error, leading me to the actual error in my code, instead of trying to "stay alive" as long as possible.
Should this be filed as a bug, or is this expected behaviour?
Edit: Code example
File: class-a.php
<?php
namespace hello\world;
class classA {
protected $b;
public function __construct() {
$this->b = new \hello\world\classB();
}
public function doSomething() {
try {
$this->b->throwException();
} catch (Exception $e) {
}
}
}
File: class-b.php
<?php
namespace hello\world;
class classB
{
public function throwException() {
throw new \Exception("bar closed");
}
}
File: run.php
<?php
include 'class-a.php';
include 'class-b.php';
$a = new \hello\world\classA();
$a->doSomething();
ClassB throws an \Exception in ClassB::doSomething(), for which ClassA has a catch-clause, but because ClassA doesn't declare use Exception or catch (\Exception), the catch doesn't match and execution ends with a Uncaught exception error1. But in my opinion, it should cause a Class not found error.
I might be expecting too much of the permissive PHP compiler, but it would help in tracking down silly errors that should be easy for the compiler to spot.
1 If the $a->doSomething() in run.php was surrounded by a try..catch clause, the Exception would (or at least could) be caught there, since it trickles down the stack.
PHP's exception catching mechanism does not validate that the class you catch actually exists.
It exhibits the same behavior when using typehinting in functions, so I suspect it merely converts the exception/function type hint into a string or something and compares that with the type of the relevant object.
Whether this is a bug or not is questionable. Personally I think it should be classified as a bug, but PHP has all sorts of wonky behaviors :D
I'm having a little trouble organizing my error messages for two interacting classes. One object has states that are 'error-ish', where something went wrong, or happened unexpectedly, but the situation is still salvageable. I don't want to use exceptions, 1. because they only have a single string for the message, and 2. because I want to access the object after the error. At the very least, I want to use some of its get() methods to construct a useful error message after the exception!
Ultimately I have two messages I want to communicate: one to myself as the coder, that something went wrong. This string would have the technical details of the file, line, function/method, arguments, and results. Obviously, I don't want to show this to the user, so there is another string of an error message that I want to show the user ("That email address was not found" kind of thing ).
So the thought occurs to me to build an error message array, which could use the error code from exceptions, or a status code, as keys for various messages. ( Though if I do this, where do I store the array of messages? ) Another option might be to make an error status object.
Is there anything like "error patterns", similar to design patterns?
Exceptions really are your best option, they do everything you asked. Even multiple messages are possible, since exceptions are just classes that you can extend. You could just pass the object that causes the exception to said exception.
<?php
class ExampleException extends Exception {
private $secondMessage;
private $objectThatCausedIt;
public function __construct( $secondMessage, $objectThatCausedIt ) {
parent::__construct(
"Descriptive message for developer",
// error code for this type of error
1000 );
$this->secondMessage = $secondMessage;
$this->objectThatCausedIt = $objectThatCausedIt;
}
public function getSecondMessage() {
return $this->secondMessage;
}
public function getObjectThatCausedIt() {
return $this->objectThatCausedIt;
}
}
class Example {
public function causeException() {
throw new ExampleException( "Second Message", $this );
}
}
Now you just use the class and wrap the call that might throw the exception in a try-catch block.
<?php
$example = new Example();
try {
$example->causeException();
}
catch ( ExampleException $e ) {
// kind of pointless here, just an illustration
// get object that caused it and do something with it.
dump_and_log_function( $e->getObjectThatCausedIt() );
// or just use $example, which is still "alive"
// and references the same instance
dump_and_log_function( $example );
}
Extending Exception has the benefit that you also get a stack backtrace. The backtrace contains information like in what file, line and function the exception occured. You can also access the error code, the message and more. I suggest you read the PHP documentation on Exceptions (http://php.net/manual/en/class.exception.php) for more information.
Regarding the error messages and logging, I usually use a singleton class for that. A singleton class has only one instance of itself (in case you didn't know.) Here is an extremely simple example:
<?php
class Log {
private $logFile;
private static $instance;
/* Log instances may only be constructed in Log::getInstance */
private function __construct() {
$this->logFile = fopen( "path/to/log/file", "a" );
}
public logMessage( $message ) {
fwrite( $this->logFile, $message );
}
public static getInstance() {
if ( !self::$instance ) self::$instance = new self();
return self::$instance;
}
}
Now going back to the exception handling throw-catch block, you can change it to something like this:
<?php
$example = new Example();
try {
$example->causeException();
}
catch ( ExampleException $e ) {
// log developer message and backtrace
Log::getInstance()->logMessage( $e->getMessage() );
Log::getInstance()->logMessage( $e->getTraceAsString() );
// or more compact by casting to string
Log::getInstance()->logMessage( (string)$e );
// and now print error for users
echo "<p>An Error has occured: {$e->getSecondMessage()}</p>";
}
Instead of echoing the error message right away, you could make the Log class have a property with an array of messages. Then you could list them later in a view script all at once. You could also make the logMessage method store the messages in the session so they could be displayed after a refresh (just don't forget to clear the messages from the session or they will be displayed over and over again ;-).
I don't want to use exceptions, 1.
because they only have a single string
for the message, and 2. because I want
to access the object after the error.
At the very least, I want to use some
of its get() methods to construct a
useful error message after the
exception!
You can create your own exception classes and you can extend PHP's exception classes, adding the support you need. However, possibly you can have two settings, developer and client, where client errors goto the display and developer errors don't instead going to a log file or something.
Which, translates into two custom exception types (though you could have many more, I'm saying two distinct base classes).