I tried to catch an exception inside a PHPUnit test but it does not work as I expected. The exception seems to be caught in a higher level and I do not understand why.
public function testException()
{
echo 'Enter';
try {
throw new Exception('error.');
} catch (Exception $e) {
echo 'catch Exception';
}
echo 'End';
}
In the output only 'Enter' is visible. I do not reach the 'End'.
(I am using PHP7)
Thanks
Edit:
Replacing all Exception with \Exception solved my issue
Handling exceptions can be tricky, especially when they are called Exception :-)
Just look at all the feedback this (almost the same) question has generated.
Now, the exception is not caught only if does not match to the expected class. In this case it is definitely because of non-precise Exception class names specification, which will most certainly be fixed by specifying them as \Exception.
As smartly put by a commenter from the mentioned question thread:
Without the backslash Exception is specific to the namespace and won't be matched (or caught).
Related
I have a code like this one:
public function one()
{
try {
$this->two();
} catch (Exception $E) {
$this->three();
}
}
How can i test that $this->three() function is called?
I've tried to "mock by code" $this->two() and throw error instead of it's original code, but that ends up with error caught by phpunit itself.
Tried setExpectedException, but it also doesn't solve the problem - catch runs inside phpunit again and just ignored.
Function $this->three() never called in both cases.
Thanks!
The problem was that the described method were in a class which was placed in a namespace containing it's own Exception implementation. So I was catching an \Namespace\Exception while throwing an \Exception.
Throwing correct exception did the thing.
#sectus, thank you!
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.
I want to catch an exception that is thrown by the Google API PHP library, but for some reason it generates a 'Fatal error: uncaught exception' before reaching my catch block.
In my app I have something like this:
try {
$google_client->authenticate($auth_code);
} catch (Exception $e) {
// do something
}
This is Google_Client's authenticate():
public function authenticate($code)
{
$this->authenticated = true;
return $this->getAuth()->authenticate($code);
}
The authenticate($code) above is Google_Auth_OAuth2::authenticate(), which at some point throws the exception:
throw new Google_Auth_Exception(
sprintf(
"Error fetching OAuth2 access token, message: '%s'",
$decodedResponse
),
$response->getResponseHttpCode()
);
If I put a try/catch block in the Google_Client's authenticate, it catches the exception, but without it the program just dies instead of reaching the main try/catch block from my app.
As far as I know this shouldn't be happening. Any ideas?
The problem was that the try/catch block was in a namespaced file and PHP requires you to use "\Exception". More info: PHP 5.3 namespace/exception gotcha
Example (taken from the link above):
<?php
namespace test;
class Foo {
public function test() {
try {
something_that_might_break();
} catch (\Exception $e) { // <<<<<<<<<<< You must use the backslash
// something
}
}
}
?>
I'm not sure how the structure of Google's API is, and I'm not a real fluent PHP programmer, but you're catching a specific exception type of Exception, with which Google's Google_Auth_Exception may not inherit from.
Therefore, since your try-catch block is looking for an exception that is a member of Exception and the Google_Auth_Exception is perhaps not a member of Exception, then your try catch block will miss it.
Try catching the specific exception. This has happened to me before in many different languages.
Edit
The link you posted inherits its exception from: Google/Auth/Exception
Google/Auth/Exception inherits its exception from: Google/Exception
Google/Exception extends Exception, which may, in this context be the Exception that your class is referring to.
It seems my justification for your try-catch block not catching an exception is completely wrong, but the wisdom could still be true. Try catching the specific exception, then use instanceof to see if PHP recognizes Google_Auth_Exception as a member of Exception.
I have some code that looks like this
# Try to import file
try
{
DataManager::fileImport($_FILES['datafile']['tmp_name'],
$_POST['zones'], $_POST['statuses']);
}
catch(Exception $e)
{
print 'Herp.';
$response->body = Helpers::getVarDump($e);
}
DataManager::fileImport is literally a one-line function that throws a normal Exception:
static function fileImport($filepath, $zones, $statuses)
{
throw new Exception('SOME EXCEPTION');
}
And yet I get
Fatal error: Uncaught exception 'Exception' with message 'SOME EXCEPTION'...
From the try block. Also 'Herp.' is never printed. Why doesn't the Exception trigger the catch block?
EDIT: I should mention I'm using Tonic and PHP 5.3.9
EDIT AGAIN: Here's DataManager (with names replaced with ... for anonymity) http://pastebin.com/daHWBJDC
Solution
I neglected to specify use \Exception; in the file containing the try/catch.
Pondering
I know it's intentional that each namespace in PHP should define its own Exception for many reasons, but I still find it odd that catch(Exception e) didn't cause any errors when Exception in that context wasn't defined. If I were to write new Exception() I would get an error.
Oh well, at least I learned something.
Strange. If i run this code i get the "Herp."
<?php
class DataManagerTest {
static function fileImport($filepath, $zones, $statuses)
{
throw new Exception('SOME EXCEPTION');
}
}
# Try to import file
try
{
DataManagerTest::fileImport("param1","param2","param3");
}
catch(Exception $e)
{
print 'Herp.';
}
?>
You might have an issue with your DataManager class because i copied your code, adapted it to run and i get the exception handled... You problem is elsewhere...
class DataManager {
static function fileImport($filepath, $zones, $statuses){
throw new Exception('SOME EXCEPTION');
}
}
try{
DataManager::fileImport('', '', '');
}catch(Exception $e){
print 'Herp.';
}
Results in
Herp.
4 years later...
#Hubro, thank you for saving me with that namespace fix!
It does seem counterintuitive at first that it's necessary when throwing a root-level Exception, even though it ultimately makes sense in the general context of namespaces.
For anyone who doesn't want to utilize #Hubro's file-level fix:
use \Exception;
You could instead add the backslash in front of Exception in the higher level catch block:
} catch (\Exception $e) {
We could all benefit from someone smarter than me providing suggestions on best practices around defining a custom Exception for each namespace. Any takers?
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
}