PHPSTAN : catch an exception without throwing it - php

I everyone, I have this simple try catch snippet, written in PHP :
try {
...
// some code
...
} catch (Throwable $e) {
$response = ['message' => $e->getMessage(), 'trace' => $e->getTraceAsString()];
}
return $response;
This code works good, but PHPSTAN does not think it is well-done :
caught "Throwable" must be rethrown. Either catch a more specific exception or add a "throw" clause in the "catch" block to propagate the exception.
I understand the message, but I wonder if it is anyway possible to catch an exception whitout throwing it, and still validate phpstan checks ?
Thank you very much for reading and if you have a clue, I take it!

This is coming from thecodingmachine/phpstan-strict-rules which you must have installed. If you're not interested in this rule, you can uninstall the package.

Related

Laravel try / catch on not working

I've searched a few questions for a reason my code is not throwing an error correctly, but I can't figure it out.
I have the following function in my controller
<?php
public function suspend($id)
{
try {
$this->collection = $this->class::find($id);
$this->collection->delete();
return $this->respond_with_success();
} catch (\Exception $e) {
return $this->respond_with_error('Failed to suspend resource with id: ' . $id);
}
}
For reference, I'm using soft deletes. I can suspend a resource once no problem. If I try to suspend one that's already suspended, Laravel correctly throws a 500 as I can see in the log file /storage/logs/laravel.log
This is part of the error I see;
local.ERROR: Call to a member function delete() on null....
Without using
withTrashed() in the query, a row quite obviously cannot be found. So this makes sense.
Great...so why does my catch not actually catch anything? I see a 500 error in the browser, but my application should allow me to continue and handle that error correctly. But it just falls over completely...
The respond_with_error function is below. I've tried changing the $code to 200 in testing, but this doesn't change anything. I've tested returning a simple string rather than with this function to no avail, so I don't think there's anything wrong with this part.
<?php
protected function respond_with_error($message = 'error', $code = 500)
{
return Response::json([
'success' => false,
'message' => $message,
], $code);
}
I'm running Laravel 5.6.29
There are two ways to address this. The first thing to note is ERROR: Call to a member function delete() on null is not an exception, it is a fatal error.
You can use findOrFail instead of find to throw an Exception when the model is not found and that will work.
You could also catch Throwable instead of Exception to catch errors and exceptions (as of PHP7) or just Error to catch errors.
As the Error hierarchy does not inherit from Exception, code that uses catch (Exception $e) { ... } blocks to handle uncaught exceptions in PHP 5 will find that these Errors are not caught by these blocks. Either a catch (Error $e) { ... } block or a set_exception_handler() handler is required.
Read more on PHP7 Error Handling here: http://php.net/manual/en/language.errors.php7.php

php exception not raised of fatal error,such as "class not exist"

I suppose that the exception system of PHP will catch all. but it doesn't.
try{
$obj = new Asdfasdfasdf()
} catch(Exception $e){
trace(...something...)
}
But it doesn't catch this kind of error, and I have searched php document, which didn't say which kind of exception/error is catch-able in try,catch clause.
So, how can I know that which kind of exception/error will be catched by my catch clause ?
P.S.
I finnally understand the 'error' from php engine is not the 'exception' from use land code. If you want use exception to handle engine 'error', you should manually wrap all 'error' in exception.
If you want to throw an Exception in the event that a class does not exist it, you could use class_exists().
A naive example might look something like:
function createClass($class)
{
if (!class_exists($class)) {
throw new Exception(
sprintf('Class %s does not exist', $class)
);
}
return new $class;
}
try {
$asdfasdfasdf = createClass('Asdfasdfasdf');
} catch (Exception $e) {
echo $e->getMessage();
}
From my experience, most PHP frameworks throw some sort of exception when a class is not found - for example, Symfony2 throws a ClassNotFoundException. That said, I don't know if you can 'catch' that, it's probably really just a development aid.
PHP 7 has just been released and from what I understand from the spec, you will be able to catch a fatal error as an EngineException. I don't know if it would work for your example; I haven't tested it because I have not installed PHP 7 stable yet. I tried your example with an alpha release of PHP 7 on an online REPL, and it appears that it does not work.
However for completeness, here's an example from the RFC:
function call_method($obj) {
$obj->method();
}
try {
call_method(null); // oops!
} catch (EngineException $e) {
echo "Exception: {$e->getMessage()}\n";
}
// Exception: Call to a member function method() on a non-object
In any case, as noted by #MarkBaker and #MarcB in the question's comments, you cannot "catch" a fatal error in previous versions of PHP.
Hope this helps :)

Understanding try and catch

This probably sounds ridiculous. However, if you don't ask you'll never learn.
I'm relatively new to PHP and self-taught so I haven't exactly learnt everything "to the book".
Is the following required:
try {
}
catch {
}
Am I right in thinking that the try will try to "execute" the code within the brackets and the catch will try and catch the result of the outcome? If there is nothing to catch then it will throw an error?
The first assumption is correct: the code in try will be attempted to run.
However, if no error is thrown, then the block exits normally. If there is an error thrown, then the try execution ends early and goes into the catch block. So your second idea is switched.
try catch is used for exception handling or error handling.Put your script in try block and write your custom error message in catch block.
try{
// put here script
}catch(Exception $error){
//your custom message
echo 'Caught exception: ', $error->getMessage(), "\n";
}
If your script does not execute then it will be jump catch block and access message using $error object.
What is the benefit? The benefit is the whole script will not be stop to execute. It will be continue other block.
In the try block you execute code, whenever something fails in that block it will jump to the catch block. You usually define a variable holding the exception.
So to answer your question, no it will not process the catch block when there is nothing going wrong in the try block. (unless you specifically throw an exception)
try {
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";
}
Try block is hold the code which you want to execute. and Catch block is hold the code if you have cause any error then it will execute the catch code or error message.
Basically try and catch we are using for the error handling and avoid to break the control flow of the program and page.
Simple example:
<?php
class A {
public function getA($a = 0)
{
if ($a === 0) {
throw new ItCantBeZeroException("Message");
}
return $a;
}
}
// I want to throw default exception because I'm not sure
// am I doing it right or what can I do with bad parameter.
$a = new A;
echo $a->getA(0);
// Now, I know what I can do if developer write bad input.
// It can't be 0, so I just print my custom error message
// to my page.
try {
$a = new A;
echo $a->getA(0);
} catch (ItCantBeZeroException $e) {
echo "Parameter can't be zero. Try again.";
}
?>
You can define your own exceptions (like ItCantBeZeroException). Exceptions throw error on site (like "Message") but we can catch them and change to something we want.
You write simple class where some code must be string or integer between 0 and 20.
You use this code, but when user make variable 21, simple class throw error.
You refactor code to catch exception and try to fix code, e.g. change any integer greater than 20 to 20. Then code works properly.
Try and Catch is known as Exception Handling
According to w3schools:
Exceptions Handling are used to change the normal flow of a script if a specified error occurs.
For More:
http://www.w3schools.com/php/php_exception.asp

catch an exception an throw another one... is there any other way?

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.

How to bypass Laravel Exception handling

I have a method that checks if a user has valid Session info. This is supposed to throw an Exception, Guzzle\Http\Exception\BadResponseException but when I try to catch it :
catch (Guzzle\Http\Exception\BadResponseException $e)
{
return false;
}
return true
Laravel doesn't get to this code and immediately starts it's own error handling. And ideas on how to bypass Laravels own implementation and use my own Catch.
EDIT: I just found out Laravel uses the same Exception handler as Symfony, so I also added the Symfony2 tag.
EDIT 2:
I sort of fixed the issue by disabling Guzzle exceptions and checking the return header manually. It's a bit of a short cut but in this case, it does the job. Thanks for the responses!
Actually this exception can be catched in Laravel, you just have to respect (and understand) namespacing:
If you have
namespace App;
and you do
catch (Guzzle\Http\Exception\BadResponseException $e)
PHP understands that you are trying to
catch (\App\Guzzle\Http\Exception\BadResponseException $e)
So, for it to work you just need a root slash:
catch (\Guzzle\Http\Exception\BadResponseException $e)
And it will work.
By default, the app/start/global.php file contains an error handler for all exceptions. However, you may specify more handlers if needed. Handlers are called based on the type-hint of the Exception they handle. For example, you may create a handler that only handles your BadResponseException instances, like
App::error(function(Guzzle\Http\Exception\BadResponseException $exception)
{
// Handle the exception...
return Response::make('Error! ' . $exception->getCode());
});
Also, make sure you have a well defined (BadResponseException) class. Read more on Laravel Documentation.
Instead of your code
catch (Guzzle\Http\Exception\BadResponseException $e)
{
return false;
}
return true
use this solution
catch (\Exception $e)
{
return false;
}
return true
to catch all possible exceptions thrown by Guzzle.
If you explicitly want to catch a BadResponseException you can also prepend your exception's class namespace with '\'.
catch (\Guzzle\Http\Exception\BadResponseException $e)
{
return false;
}
return true

Categories