I am having an issue where an exception is being thrown but not caught in Module.php. The code that throws the exception is wrapped in a try/catch. There's nothing really fancy going on so I am assuming ZF2 has a quirk and/or reason for not allowing exceptions to be caught here.
The code is as follows (simplified as necessary):
class Module
{
public function onBootstrap(MvcEvent $e)
{
// Get service manager, etc.
// Set up some environment stuff
try {
// exception is thrown
}
catch (\Exception $e) {
echo $e->get_message();
exit;
}
}
}
Why is the exception not being caught?
In an ideal world there would be a way to catch this exception here. But if that is not possible, or is too convoluted to be worth the effort, an alternative process to fetching this data (regardless of source) as early in the page loading process as possible would be appreciated.
meta
I know the code in Module.php is supposed to be lightweight. But we have to fetch some data immediately before any action is performed as it will contain data vital to those actions to be performed. This data is cached after the first visit so every other page load will avoid this overhead.
I also have Googled this but apparently no one else has either experienced this, asked about it, or documented it.
This code works just fine for me in a module class:
public function onBootstrap(MvcEvent $e)
{
try {
// exception is thrown
throw new \Exception('My exception here');
}
catch (\Exception $e) {
echo $e->getMessage();
exit;
}
}
It displays the exception message and exits.
One way to investigate what is happening is to use xdebug for step by step debugging.
Just add a breakpoint in your Module and see what ZF is doing.
Related
I am currently maintaining a application with a large code base. The application is still under development.
My goal is to log all the exceptions that are thrown in the application. Also the ones that are caught in the try catch block. Due to the large code base I cannot add single lines of code in the catch blocks or create my custom exception class.
The way I tried to solve it or look for a solution are:
Listen for class construction in the whole application
Override the Exception class (can't do this because it is an core php class)
My most recent code that I tried is:
My test exception (dashboardcontroller.php)
try {
throw new \Exception('custom thrown exception');
} catch (\Exception $e) {
Log::info('Exception caught');
}
Exceptions\Handler.php
public function report(Exception $exception)
{
Log::info($exception);
parent::report($exception);
}
Log
[2020-03-10 17:19:09] local.INFO: Exception caught
So the question is: How can I log / handle thrown exceptions that are caught in the try catch block without adding code that requires lot of changes?
Short answer: You can't (as far as I know that is).
Exceptions that are caught are, normally, caught for a reason; they are handled (or: they should be) in the catch-statement (i.e. exception handler). It's the uncaught exceptions that you want to log.
Exceptions should never be used for program-flow, but it does happen anyway and sometimes for good reason:
if (fileExists('foo.txt')) {
fileDelete('foo.txt'); // May result in a race-condition
}
V.s.:
try {
fileDelete('foo.txt')
catch (IOException) {
// NO-OP
}
Another common pattern:
while (true) {
try {
item = queue.Receive(10); // Wait max. 10 seconds
process(item); // Process item
} catch (TimeOutException) {
// Nothing on queue, handle other stuff and then continue waiting...
DoStuff();
}
}
Above patterns are quite common. Again: exceptions shouldn't be used for program-flow and the queue example above surely shouldn't exist but the reality is that it happens. Real world applications, libraries, API's etc. sometimes just work that way and as soon as you're dealing with 3rd party applications, libraries or API's you're in trouble because you can't always change everything to what you would like it to be.
Can you imagine your logfile in the above queue-example with your 'generic application wide catch logger' for an application running 24/7?
When to log an exception (and maybe just as important: what to log) should be considered on a case-by-case basis.
In Laravel framework whenever you try to fetch some data from your eloquent model, if an exception occurs, it'll throw aModelNotFoundException. In my project I need to catch this exception and redirect user to specific route.
the solution that I've ended up is like this:
try{
$foundUser = $this->user->whereId($id)->firstOrFail();
}catch(ModelNotFoundException $e){
throw new NonExistantUserException;
}
I know that I can put my redirect code inside the catch block, however I'm already catching these sort of exceptions in global.php:
App::error(function(NonExistantUserException $e)
{
return Redirect::back()->WithInput();
});
I want to know is there any way to say, for example no matter what kind of exception would occur inside try block I want to catch it as NonExistantUserException just for this try block!
I'm asking because catching an exception an throw another one. seems a bad practice to me.
Thanks in advanced.
Absolutely not bad practice and even common practice. But you should not simply discard the previous exception as it might be useful for debugging purposes.
<?php
try {
$foundUser = $this->user->whereId($id)->firstOrFail();
} catch (ModelNotFoundException $e) {
throw new NonExistentUserException(
"Could not find user for '{$id}'.",
null,
$e // Keep previous exception.
);
}
This ensures that you have the full chain of exceptions at your disposal. Other than that your approach looks good to me.
i've got a try catch in the framework i'm using which when the catch is triggered it displays an error report page, one thing in this report page is that it displays a menu where the times came from the database
what i thought it's do is that i'd put another try catch in the catch in case if the database can be connected to, something like this
try
{
code that would throw an excpetion
}
catch(Exception $e)
{
try
{
connect to database
run query
log error in database
output screen using database data
}
catch(Exception $e)
{
output screen using static html
}
}
this way if the exception was a database connection error it will use a static html output rather than the dynamic one generated from database data
however when i cause a database error (deleting a required table) my static html doesn't work
i am wondering if it is even possible for a try catch to work in the catch or weather it's the framework (i'm using magento), i ask this because if it is possible to be done then i'll spend time figuring out why the framework is stopping me
Yes, it is possible to put a try/catch block in a catch block.
However, from your description, it sounds like you want more 'intelligent' exception catching. You can do something like this:
try {
// some operations including something with a database
}
catch (DatabaseException $e) {
// the exception thrown by the code above was a DatabaseException
// output some error message without using the database
}
catch (Exception $e) {
// the exception thrown by the code above could have been any type of exception EXCEPT a DatabaseException
// so you can still try to use the database to compose the error message
}
Note that anything that can throw exceptions can also throw these exceptions when run from a catch block. For example, when the try block throws an exception before it reaches any database code, a database exception can still occur when handling the original, non-database, exception.
I'm using an external file with $errmsg array for displaying errors, like:
'app_init' => 'Cannot initialize application',
Using conditionals, I call the function to display the message on failure:
if(!$condition)
{
$arraywithmessages->functionforfiltering($err,'app_init',$aim);
}
...where $err is the array of messages, and $aim is predefined method of publishing error (e-mail, view, etc...)
Now I'd like to make use of Exception Handling, but I don't know where to start. Can anyone help? This doesn't seem to work:
try {
if (!$condition) {
throw new Exception('app_init');
}
// continue
} catch (Exception $e) {
$arraywithmessages->functionforfiltering($err,$e->getMessage(),$aim);
}
I don't know exactly what you want to achive but you should remember that try, catch should be used wisely. It should be used for Exceptional situations only. If you don't use them in that way then it's GOTO code.
About exceptions, remmeber that you can extend Exception class and make your own exceptions and catch them in multiple catch blocks, there is also finally block.
About the constructor of Exception. It has the second param which is $code you can use it to show proper message.
$err = array(0x1 => 'my error app init');
try {
if (!$condition) {
throw new Exception('app_init', 0x1);
}
// continue
} catch (Exception $e) {
echo $err[$e->getCode()]; //it shouldn't be only echo it should do some tries to fix the code close streams etc. not just echo.
}
There is also function
set_exception_handler(). which:
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.
Consider using it. There are a lot of things that can be found in manual.
I got a try-catch block in my php application like this:
try {
if ($userForgotToEnterField) {
throw new Exception('You need to fill in your name!');
}
...
doDifferentThingsThatCanThrowExceptions();
...
} catch (ExpectedException $e) {
$template->setError('A database error occured.');
} catch (Exception $e) {
$template->setError($e->getMessage());
}
I would like to only output $e->getMessage() for the exceptions I have manually thrown with a custom error text and not the ones that have been thrown by the other code as these might contain sensitive information or very technical info that the user should not see.
Is it possible to differentiate from a manually thrown exception and a random exception thrown by some method without using a custom exception class?
I agree that it might be best to just write your own exceptions. If for whatever reason you don't want to, you could set a custom error message and a custom error code (the second parameter for the Exception constructor.) Check each thrown Exception if the error code is yours, and display only those:
public Exception::__construct() ([ string $message = "" [,int $code = 0[, Exception $previous = NULL ]]] )
and then use getCode
I've thought about this a bit and I'd say that what you are doing DOES call for a custom exception class. If you want to get around it (which in the end is going to be more confusing), you would basically create a global (or same-scope) variable that all exceptions can modify, and in your throw block flag it.
$threwCustomException = false;
try {
if ($userForgotToEnterField) {
throw new Exception('You need to fill in your name!');
$threwCustomException = true;
}
...
doDifferentThingsThatCanThrowExceptions();
...
} catch (ExpectedException $e) {
$template->setError('A database error occured.');
} catch (Exception $e) {
if($threwCustomException){
//Whatever custom exception handling you wanted here....
}
$template->setError($e->getMessage());
}
That's the best I can think of. However, this is a bad idea, and it's the whole reason you are allowed to create your own exception classes. I know you're not looking for this answer, but since you look like you're trying not to create a TON of extra code, I would just extend Exception to "CustomException" or some other name specific to your project, and throw that for all cases, and handle it that way.
Hope that helps.