throw and catch handling in php - php

Is there a way to throw an exception in PHP without try and catch?
I mean something like this:
if(!isset($_POST['APIKEY']) || $_POST['APIKEY'] != API_KEY)
throw new Exception(lang("apikey_error"));

Pretty much the whole point of exceptions is to not reflexively catch them.
Exceptions are an error handling mechanism that allows you to propagate errors. That explicitly means that if your application encounters an exceptional state in which it cannot continue working, you signal that by throwing an exception and abandoning the current execution context entirely. If this happens somewhere "at the top" of your application, the application is terminated, because it cannot continue to run. As it should.
Catching exceptions is for when your code is calling a subsystem and that code expects possible errors in that subsystem and knows what to do with them. The subsystem may fail, but the caller can deal with that failure. If the subsystem would be catching its own exceptions... what's the point?
try {
throw new Exception;
} catch (Exception $e) {
// what now?
}
How does the above differ from the below?
// what now?
So, yes, you can and virtually always should throw exceptions without catching them right then and there. Leave the catching up to the caller.
function foo() {
// Something's wrong, can't do my job, I'm outta here!
throw new Exception;
}
try {
foo();
} catch (Exception $e) {
// oh, something's wrong with foo(), let's try bar() instead
bar();
}

Related

Handle specific Exceptions in php

I want to catch a specific Exception and handle it properly. However, I have not done this before and I want to do it in the best way.
Will it be correct to create a separate class something like
class HandleException extends Exception
{
//my code to handle exceptions;
}
and in it have different methods handling the different exception cases? As far as I understand, the Exception class is like an "integrated" class in php so it can be extended and if an Exception is caught it is not obligatory to terminate the flow of the program?
And, an instance of this class will be created when an exception is caught? Sth. like
catch ( \Exception $e ) {
$error = new HandleException;
}
You CAN extend the basic Exception object with your own, to provide your own exception types, e.g.
class FooExcept extends Exception { .... }
class BarExcept extends Exception { .... }
try {
if ($something) {
throw new FooExcept('Foo happened');
} else if ($somethingelse) {
throw new BarExcept('Bar happened');
}
} catch (FooExcept $e) {
.. foo happened, fix it...
} catch (BarExcept $e) {
... bar happened, fix it ...
}
If an Exception is caught, then the program DOESN'T necessarily have to abort. That'd be up to the exception handler itself. But if an exception bubbles always back up to the top of the call stack and ISN'T caught, then the entire script will abort with an unhandled exception error.
From the manual
Multiple catch blocks can be used to catch different classes of
exceptions. Normal execution (when no exception is thrown within the
try block) will continue after that last catch block defined in
sequence. Exceptions can be thrown (or re-thrown) within a catch
block.
So you can do something like this:
try {
// some code
} catch ( HandleException $e ) {
// handle sthis error
} catch ( \Exception $e ) {
// handle that error
}
This will handle different exceptions. You can also use the finally keyword with newer versions of PHP.

Having issue with extended exceptions using Yii 2

I'm using the Yii 2 framework and it uses a number of extended exceptions and I'm having an issue with them where I threw a UserException but it ended up being caught by the base Exception but I'm not sure why!?
The code:
try {
//........
if ($reader->count() > 0) {
if (!$already_active) {
//.....
} else {
throw new UserException('You have already activated your account; you may continue to login.');
}
}
} catch (\Exception $e) {
// User exception above is caught in here?
} catch (UserException $e) {
// Rethrow the exception
throw $e;
}
Shouldn't the User Exception be passed onto and caught by the second catch?
From http://php.net/manual/en/language.exceptions.php
When an exception is thrown, code following the statement will not be executed, and PHP will attempt to find the first matching catch block.
The catch block for Exception will be executed since Exception is a parent of UserException and therefore any object of type UserException is also of type Exception.
Therefore you should refactor your code to have the catch block for child classes first. In your case UserException should be first.
If you take a look at UserException class you can see:
class UserException extends Exception
Therefore, Exception has the higher priority.
However you can do just:
//if something's wrong
throw new \yii\base\UserException('You have already activated your account; you may continue to login.');

Cleaning up code for a custom exception class in PHP

I'm playing around with custom PHP exceptions for the first time, and would like some help with cleaning up some code. In particular, I'm catching PDO errors, and have written a class to mail myself a stack trace of the errors. The way that I'm currently doing things is as follows:
try {
//db stuff
} catch (PDOException $e) {
throw new My_Own_Exception($e);
exit;
}
where my My_Own_Exception does the job with:
class My_Own_Exception extends Exception
{
/*code to mail myself error info: this part works!
}
While the above works, I feel like I should be able to just write something cleaner such as:
try {
} catch (My_Own_Exception $e) {
exit;
}
where My_Own_Exception is an extension of the PDOException class. A few questions about this: First, is the second way the better approach? Second, if so, is it possible? Third, if it is possible, how do I let PHP know that My_Own_Exception "exists" if My_Own_Exception is never instantiated anywhere? Hopefully the third question makes some sense: my gut tells me that if I can make that happen, then my approach should be possible.
I don't think that an exception is the correct place for logic, it should contain information about the error. A PDOException is useful because you know it originates from your PDO code, if you throw a MyException instead, you need to at least give more (useful) information.
This being set, you should read BiVOC's comment on your original question.
If you have a custom exception handler, you can then differentiate via instanceof.
function exception_handler($exception) {
if ($exception instanceof PDOException) {
//mail
}
//always log/etc.
}
What you are trying to do wont work, because nothing in the PDO code will throw your exception, unfortunately. So you are going to have to throw it yourself, like you were in the first example.
Also, the exit in the first example will never be hit.

Should the Exception Class always be caught in try catch?

Is it good coding practice to always catch the base Exception class in a try catch?
try
{
//
// Piece of code
//
}
catch (CustomException $my_ex)
{
// Handle CustomExcepton
}
catch (Exception $other_exceptions)
{
// Handle all other exceptions
}
If so, why?
In PHP you can install a global exception handler.
When needed you can catch exceptions in your code, all unhandled exceptions go to the global exception handler. Depending on your strategie, you decide what to do.
Of course, when you decide to die, a clear error message and a log is appreciated.
In general, if you can recover from a exception, use a try .. catch block, otherwise let the global exception handler do his work, and do not recover.
You should catch only exceptions you now how to handle. Others should bubble up to calling method and some global handler in the end.

Is there a way to catch an Exception without having to create a variable?

In PHP, I sometimes catch some exceptions with try/catch :
try {
...
} catch (Exception $e) {
// Nothing, this is a test that an exception is thrown.
}
With that kind of code, I end up with the variable $e that is created for nothing (lots of resources), and PHP_MD (PHP Mess Detector) creates a warning because of an unused variable.
Starting with PHP 8, it is possible to use a non-capturing catch.
This is the relevant RFC, which was voted favourably 48-1.
Now it will be possible to do something like this:
try {
readFile($file);
} catch (FileDoesNotExist) {
echo "File does not exist";
} catch (UnauthorizedAccess) {
echo "User does not have the appropriate permissions to access the file";
log("User attempted to access $file");
}
With this, for some edge cases where the exception details are not relevant and exception type already provides all the necessary context, it will be possible to catch the exception without creating a new variable.
You can with PHP 8 #see
PHP 5,7
No, but you can unset it.
try {
...
} catch (Exception $e) {
// Nothing, this is normal
unset($e);
}
If it is PHPMD causing this issue then you can suppress the warning.
PHPMD suppress-warnings
class Bar {
/**
* This will suppress UnusedLocalVariable
* warnings in this method
*
* #SuppressWarnings(PHPMD.UnusedLocalVariable)
*/
public function foo() {
try {
...
} catch (Exception $e) {
// Nothing, this is normal
unset($e);
}
}
}
I'm assuming you are only catching the exception because you need to not because you want to.
With PHP 5,7 you have to use a catch if you want to use try and if you use a catch you have to declare a variable.
That's the whole point of exceptions - you can have multiple different catch blocks to catch any exceptions you'd want to handle. The exception's data has to be assigned somewhere, hence the variable. You could just do something like unset($e) inside the catch block if you really don't want to see those warnings... or disable the warnings (generally a bad idea).
I disagree fundamentally with Marc B's and Artefacto's answers. There are cases where ommitting the catch is better or even the only option. Especially when using external libraries (where you have no control over what exceptions are thrown) and/or async operations.
For example:
I want to create a file only if it doesn't exist yet. I'm using an external I/O library. Imagine it has File::exists($fileName) and File::create($fileName) methods.
Option 1 (if ommitting the catch was possible):
try {
File::create($fileName);
}
// Go on with the rest of the code.
Option 2 (without try/catch):
if (!File::exists($fileName))
File::create($fileName);
Here, option 1 is perfectly valid, since option 2 has two important issues:
If multiple threads are running and going through this code section at the same time, it could be that thread A first checks if the file exists. Next, thread B checks if the file exists. They both find that it doesn't exist. Thread A creates the file. Thread B then attempts to create it again and throws an exception even though you're using the if check.
It's very likely that the library itself already performs the !File::exists($fileName) check. Therefore you're wasting a call that is already made.
Note that if File::create throws other exceptions that might be unexpected it would be good to catch those.
Conclusion
Stating that something is never a good idea, is almost never a good idea. There are always exceptions (hehe) to the rule. Like any convention or design pattern, it's just a rule of thumb meant to help less experienced developers make the right decision.
No.
In any case, it's generally a bad idea to catch an exception and do nothing; exceptions exist precisely to force you to handle the exceptional circumstance (otherwise execution is aborted), so it's comprehensible the language doesn't facilitate such a use case.
As of PHP 8.0 it may be typed without variables, but the general case for each Exception is now Throwable. Class Exception implements Throwable.
try {
...
} catch (CustomException) {
// CustomException
} catch (Throwable) {
//All other classes implementing Throwable interface
}

Categories