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');
});
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.
Consider the following method:
function m1()
{
$ent = new Entity;
...
try {
$ent->save();
} catch (QueryException $e) {
...
}
I've got to trigger an exception. Preferably with mockery. How do I do that?
P.S. I can't pass $ent into the method.
UPD Let me describe my particular case to confirm if I do need to trigger an exception. Here I'm trying to test controller's action that is triggered by payment system to notify that user has made a payment. In it I, among other things, store in database all the data coming from payment system in PaymentSystemCallback model, and link it to Order model, which is created before redirecting user to the payment system. So, it goes like this:
function callback(Request $request)
{
$c = new PaymentSystemCallback;
$c->remote_addr = $request->ip();
$c->post_data = ...;
$c->headers = ...;
...
$c->save();
$c->order_id = $request->request->get('order_id');
$c->save();
}
But if incorrect order_id comes in, foreign constraint fails, so I change it this way:
try {
$c->save();
} catch (QueryException $e) {
return response('', 400);
}
But it doesn't look good to handle any database exception this way, so I'm seeking for a way to rethrow the exception unless $e->errorInfo[1] == 1452.
And here's what I came up with:
/**
* #runInSeparateProcess
* #preserveGlobalState disabled
*/
function testExceptionOnSave()
{
$this->setUpState();
Mockery::mock('overload:App\PaymentSystemCallback')
->shouldReceive('save')
->andReturnUsing(function() {}, function() {
throw new QueryException('', [], new Exception);
});
$this->doRequest();
$this->assertBalanceDidntChange();
$this->assertNotProcessed();
$this->seeStatusCode(500);
}
I use #runInSeparateProcess because preceding tests trigger the same action, and therefore the class is loaded before mockery has a chance to mock it.
As for #preserveGlobalState disabled it doesn't work without it. As phpunit's documentation put it:
Note: By default, PHPUnit will attempt to preserve the global state from the parent process by serializing all globals in the parent process and unserializing them in the child process. This can cause problems if the parent process contains globals that are not serializable. See the section called “#preserveGlobalState” for information on how to fix this.
I deviate a little from what mockery's documentation says when I'm marking only one test to run in a separate process, since I need it only for one test. Not the whole class.
Constrictive criticism is welcome.
The easiest way around this is to call a factory method that creates a mock instance of your Entity. Something like:
function testSomething()
{
$ent = $this->getEntity();
...
try {
$ent->save();
} catch (QueryException $e) {
...
}
}
function getEntity()
{
$mock = $this->createMock(Entity::class);
$mock
->method('save')
->will($this->throwException(new QueryException));
return $mock;
}
Your method is not designed for test. Fix that. If you can't, then you have to monkey patch, which PHP does not support natively.
My recommended approach would be to have your test suite install its own priority autoloader. Have your test case register a mock class into that autoloader, associated with class name Entity. Your mock class will do its magic to throw an exception. If you're using PHP 7, you have access to anonymous classes, which makes fixtures easier: new class Entity {}.
Per the accepted answer, Mockery supports this autoloading trick using the overload: quantifier on mocked classes. This saves a lot of work on your part!
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
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
Working on a symfony application that uses nusoap (is this the best method for integrating soap work with php/symfony?) for taking credit card payments.
I've simplified an example of my code below.
What I'm struggling with is the best way to handle exceptions. The example below only has 1 custom exception (where should my custom exceptions reside within the directory structure of symfony? (lib/exception?)) But what happens when there are several different types of exceptions that handle a specific error? It's not very elegant to have a try/catch block with 20 odd exceptions.
I'm also not sure of where I should be throwing and catching. I need to set some user flashes to alert the user of any problems, so I figure the catching should be done in the actions controller rather than within the class that handles the soap call.
Could anyone please advise where I might be going wrong?
I hate messy code/solutions and want to stick to the DRY principle as much as possible. I think I might also be missing some built in symfony functionality that might help with this but whenever I search I usually find examples that are for symfony 1.2, I'm using 1.4.
Some examples would be great, thanks.
lib/soap_payment.class.php
class SoapPayment
{
public function charge()
{
/*assume options are setup correctly for sake of example*/
try
{
$this->call();
}
catch (SoapPaymentClientFaultException $e)
{
/* should this be caught here? */
}
}
private function call()
{
$this->client->call($this->options);
if ($this->client->hasFault())
{
throw new SoapPaymentClientFaultException();
}
}
}
apps/frontend/payment/actions/actions.class.php
class paymentActions extends sfActions
{
public function executeCreate(sfWebRequest $request)
{
/* check form is valid etc */
$soap_payment = new SoapPayment();
try
{
$soap_payment->charge();
}
catch (SoapPaymentClientFaultException $e)
{
/* or throw/catch here? */
$this->getUser()->setFlash('error', ...);
$this->getLogger()->err(...);
}
/* save form regardless, will set a flag to check if successful or not in try/catch block */
}
}
One not very well known feature of Symfony is that exceptions can manage the content sent in a response. So you could do something like this:
class SoapException extends sfException
{
public function printStackTrace() //called by sfFrontWebController when an sfException is thrown
{
$response = sfContext::getInstance()->getResponse();
if (null === $response)
{
$response = new sfWebResponse(sfContext::getInstance()->getEventDispatcher());
sfContext::getInstance()->setResponse($response);
}
$response->setStatusCode(5xx);
$response->setContent('oh noes'); //probably you want a whole template here that prints the message that was a part of the SoapException
}
}
If you need a cleaner handling of SOAP exceptions, like setting flashes, etc. you'll probably have to catch each exception. One idea here might be to create a generic SoapException class that is extended by more specific SoapExceptions so you don't have to catch a bunch of different types. The above code may be a useful fallback mechanism as well.
Finally, yes, you should place custom exceptions in lib/exception.