Exception isn't being picked up in catch - php

I current have a class that holds this method:
public function getUser(
) {
if (!empty($this->UserName)){
return $this->UserName;
} else {
throw new Exception('Empty UserName');
}
}
When I then run this method when the UserName is NOT set, the catch is not picking up the thrown exception, the page just silently dies.
try {
$example = $obj->getUser();
} catch (Exception $ex) {
die($ex->getMessage());
}
Suggestions? - I have read documentation and found nothing.

This seems to work, I had to recreate what I assumed would be your class.
<?php
class User {
public $UserName = '';
public function getUser() {
if (empty($this->UserName))
throw new Exception('UserName is empty!');
return $this->UserName;
}
}
try {
$user = (new User())->getUser();
} catch (Exception $e) {
echo $e->getMessage();
}
?>
Output
I can only assume that your variable is not actually empty.
Notice
In PHP a string with a space in it is NOT classed as empty,
var_dump(empty(' ')); // false
Unless you trim,
var_dump(empty(trim(' '))); // true
Error Reporting
If it isn't done so already, enable error_reporting,
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

Related

How do I catch more than one exception type?

I have the following code -
public function getPosts($limit = 25, $author = null) {
try {
} catch(\GuzzleHttp\Exception\ClientException $e) {
return [];
}
return [];
}
I added this b/c when the page 404s I get the ClientException, however if the server returns a 500 error I get a ServerException - I tried just replacing this with catch(Exception $ex), but I still get the unhandled/uncaught exception error.
You can have multiple catch blocks for different exception types in php:
try {
} catch(\GuzzleHttp\Exception\ClientException $e) {
return [];
} catch(\GuzzleHttp\Exception\ServerException $e) {
//handle it...
}
However, the assuming the Guzzle exceptions extend the general php Exception class (which of course they do), changing it to just Exception $e should work. Are you sure this is where the exception is being thrown?
On the guzzle site http://docs.guzzlephp.org/en/latest/quickstart.html#exceptions you can see GuzzleHttp\Exception\TransferException base for all the client/server extensions, so you could just try to catch a GuzzleHttp\Exception\TransferException;
just list multiple catches:
try {
...
} catch (FooException e) {
...
} catch (BarException e) {
...
} catch (Exception e) {
...
}
Just keep catching
public function getPosts($limit = 25, $author = null) {
try {
} catch(\GuzzleHttp\Exception\ClientException $e) {
return [];
} catch (ServerException) {
//some code
}
return [];
}
be aware of namespaces, if you try to catch Exception it will catch all exceptions, if it did not, maybe you didnt include the exception as use Exception or tried to catch \Exception
The catch can be chained one after the other for handling multiple Error Types.
public function getPosts($limit = 25, $author = null) {
try {
} catch(\GuzzleHttp\Exception\ClientException $e) {
return [];
} catch(\GuzzleHttp\Exception\ServerException $e) {
return [];
}
return [];
}

Some try catch issue with php

I'm trying to create a class for work with crontab in php.
I used this tutorial.
I've installed libssh2 but as you can see there is no work with it yet. So I have a file Ssh2_crontab_manager.php on my server. Here it's content:
<?php
Class Ssh2_crontab_manager
{
private $connection;
private $path;
private $handle;
private $cron_file;
function __construct($host=NULL, $port=NULL, $username=NULL, $password=NULL)
{
$path_length = strrpos(__FILE__, "/");
$this->path = substr(__FILE__, 0, $path_length) . '/';
$this->handle = 'crontab.txt';
$this->cron_file = "{$this->path}{$this->handle}";
/*try
{
if ((is_null($host)) || (is_null($port)) || (is_null($username)) || (is_null($password))) throw new Exception("Please specify the host, port, username and password!");
}
catch
{
}*/
}
}
?>
And here is noReplyCrontab.php where I try to use this class:
<?php
include './lib/Ssh2_crontab_manager.php';
//$crontab = new Ssh2_crontab_manager('host', '22', 'user', 'pass');
echo 'WORKS';
?>
If I run it now, it says 'works', but if I uncomment try/catch block it shows just white screen, so I suppose that there is some mistake. Any one can show it to me?
Your code says
catch
{
}
But catch What?
You have to provide that value to catch clause
catch (Exception $e)
{
//now it will work fine
}
Manual
try this
try
{
if (true) throw new Exception("Please specify the host, port, username and password!");
}
catch(Exception $e)
{
echo $e->getMessage();
}

PHP try, catch, and try again (depending on output)?

I currently have the following PHP which uses a try/catch block checking for exceptions.
try {
$obj->login('User', 'Pass');
$obj->joinServer('Server');
} catch(ConnectionException $objException){
die();
}
...and this is the ConnectionException class:
class ConnectionException extends Exception {
public function __construct($strError, $intError, $mixOther = null){
$this->strError = $strError;
$this->intError = $intError;
echo $this->intError, ' - ', $this->strError, chr(10);
}
}
Now let's say if the "catch" part returns a specific error (if ConnectionException outputs a specific message), how can I "retry" the try/catch again?
I guess you can nest the try/catch, wrap it the code into a function to avoid code repetition:
function login($obj){
$obj->login('User', 'Pass');
$obj->joinServer('Server');
}
try {
login($obj);
} catch(ConnectionException $objException){
try {
login($obj);
} catch(ConnectionException $objException){
die();
}
}
If you want to do this at this level, instead of having it throw a ConnectionException every time, throw a different exception that's a subclass of ConnectionException that signifies when you would want to rerun the logic. Then, encapsulate the logic that you have within the try to a function, and call it again.
try {
doWork( $obj);
} catch( ConnectionTimeoutException $e) {
// Wait a bit, then retry
try {
sleep(10);
doWork( $obj);
} catch( ConnectionException $e) {
// Because of the subclass, this would catch both ConnectionException and ConnectionTimeoutException
die();
}
} catch( ConnectionException $e) {
die();
}
You can also change how you're calling this function, and call it twice depending on the result of ConnectionException. Although, in that manner, it may make more sense to base this decision on a return value instead of an Exception.
My suggestion would be to create a simple while loop that checks for a condition:
try_connection = true;
while(try_connection) {
try {
$obj->login('User', 'Pass');
$obj->joinServer('Server');
} catch(ConnectionException $objException){
if(!specific_message)
try_connection = false;
}
}

Handling an exception, and only executing code if an exception was not thrown

My script_a.php:
try {
Class1::tryThis();
}
catch (Exception $e) {
// Do stuff here to show the user an error occurred
}
Class1::tryThis() has something like:
public function tryThis() {
Class2::tryThat();
self::logSuccessfulEvent();
}
The problem is that Class2::tryThat() can throw an exception.
If it does throw an exception, it seems that the line self::logSuccessfulEvent(); still gets executed.
How can I refactor this code so that self::logSuccessfulEvent() only occurs when an exception is not thrown, yet at the same time letting script_a.php know when an exception has been thrown?
This function will return whether or not the operation was successful (true = success, false = failure)
public function tryThis() {
$success = true;
try {
Class2::tryThat();
self::logSuccessfulEvent();
} catch( Exception $e) {
$success = false;
}
return $success;
}
What you're describing does not seem to be the case.
Code:
<?php
class Class1 {
public function tryThis() {
echo "Class1::tryThis() was called.\n";
Class2::tryThat();
self::logSuccessfulEvent();
}
public function logSuccessfulEvent() {
echo "Class1::logSuccessfulEvent() was called.\n";
}
}
class Class2 {
public function tryThat() {
echo "Class2::tryThat() was called.\n";
throw new Exception('Exception generated in Class2::tryThat()');
}
}
try {
Class1::tryThis();
} catch (Exception $e) {
echo $e->getMessage(), "\n";
}
Output:
Class1::tryThis() was called.
Class2::tryThat() was called.
Exception generated in Class2::tryThat()
As you can see, the Class1::logSuccessfulEvent() method is never executed when an exception is generated in Class2::tryThat(), and it shouldn't (won't) either. Exceptions bubble up until they are caught or produce a fatal error. Once an exception is caught, control of the program returns to the code after the catch block. In this particular case, that would mean that control of the program never reaches the logging method.

How to change exception message of Exception object?

So I catch an exception (instance of Exception class) and what I want to do is change its exception message.
I can get the exception message like this:
$e->getMessage();
But how to set an exception message? This won't work:
$e->setMessage('hello');
For almost every single case under the sun, you should throw a new Exception with the old Exception attached.
try {
dodgyCode();
}
catch(\Exception $oldException) {
throw new MyException('My extra information', 0, $oldException);
}
Every once in a while though, you do actually need to manipulate an Exception in place, because throwing another Exception isn't actually what you want to do.
A good example of this is in Behat FeatureContext when you want to append additional information in an #AfterStep method. After a step has failed, you may wish to take a screenshot, and then add a message to the output as to where that screenshot can be seen.
So in order to change the message of an Exception where you can just replace it, and you can't throw a new Exception, you can use reflection to brute force the parameters value:
$message = " - My appended message";
$reflectionObject = new \ReflectionObject($exception);
$reflectionObjectProp = $reflectionObject->getProperty('message');
$reflectionObjectProp->setAccessible(true);
$reflectionObjectProp->setValue($exception, $exception->getMessage() . $message);
Here's that example the Behat in context:
/**
* Save screen shot on failure
* #AfterStep
* #param AfterStepScope $scope
*/
public function saveScreenShot(AfterStepScope $scope) {
if (!$scope->getTestResult()->isPassed()) {
try {
$screenshot = $this->getSession()->getScreenshot();
if($screenshot) {
$filename = $this->makeFilenameSafe(
date('YmdHis')."_{$scope->getStep()->getText()}"
);
$filename = "{$filename}.png";
$this->saveReport(
$filename,
$screenshot
);
$result = $scope->getTestResult();
if($result instanceof ExceptionResult && $result->hasException()) {
$exception = $result->getException();
$message = "\nScreenshot saved to {$this->getReportLocation($filename)}";
$reflectionObject = new \ReflectionObject($exception);
$reflectionObjectProp = $reflectionObject->getProperty('message');
$reflectionObjectProp->setAccessible(true);
$reflectionObjectProp->setValue($exception, $exception->getMessage() . $message);
}
}
}
catch(UnsupportedDriverActionException $e) {
// Overly specific catch
// Do nothing
}
}
}
Again, you should never do this if you can avoid it.
Source: My old boss
Just do this, it works I tested it.
<?php
class Exception2 extends Exception{
public function setMessage($message){
$this->message = $message;
}
}
$error = new Exception2('blah');
$error->setMessage('changed');
throw $error;
You can't change Exception message.
You can however determine it's class name and code, and throw a new one, of the same class, with same code, but with different message.
You can extend Exception and use the parent::__construct to set your message. This gets around the fact that you cannot override getMessage().
class MyException extends Exception {
function __construct() {
parent::__construct("something failed or malfunctioned.");
}
}
here a generified snippet i'm using.
foreach ($loop as $key => $value)
{
// foo($value);
thow new Special_Exception('error found')
}
catch (Exception $e)
{
$exception_type = get_class($e);
throw new $exception_type("error in $key :: " . $e->getMessage());
}
An ugly hack if you don't know which kind of exception you're handling (that can have its own properties) is to use reflection.
try {
// business code
} catch (\Exception $exception) {
$reflectedObject = new \ReflectionClass(get_class($exception));
$property = $reflectedObject->getProperty('message');
$property->setAccessible(true);
$property->setValue($exception, "new message");
$property->setAccessible(false);
throw $exception;
}
You should use this crap wisely in very specific case when you don't have any other choice.
You can't change the message given by the Exception class. If you wanted a custom message, you would need to check the error code using $e->getCode() and create your own message.
If you really wanted to do this (in the only situation I can think that you might want to do it), you could re-throw the exception:
function throwException() {
throw new Exception( 'Original' );
}
function rethrowException() {
try {
throwException();
} catch( Exception $e ) {
throw new Exception( 'Rethrow - ' . $e->getMessage() );
}
}
try {
rethrowException();
} catch( Exception $e ) {
echo $e->getMessage();
}
The php Exception class has a __toString() method which is the only method within the Exception class that is not final, meaning it can be customised.
class HelloMessage extends Exception {
function __toString() {
return $this->getMessage()." you have an error with code: ".$this->getCode();
}
}
You use it as follows within try-catch block:
try {
if (2 > 0) {
throw new HelloMessage("Hello", 10);
}
} catch (HelloMessage $e) {
echo $e;
}
Output would be:
Hello you have an error with code: 10
You can extend Exception with your own, and put a setter in it
class MyException extends Exception
{
private $myMessage = '';
public function getMessage()
{
if ($this->myMessage === '') {
return parent::getMessage();
} else {
return $this->myMessage;
}
public function setMessage($msg)
{
$this->myMessage = $msg;
}
}
This is an improved version of David Chan's answer. It's a re-throw solution which uses get_class to rethrow the same exception type, and it passes all parameters to the constructor, even in the case of ErrorException, which has six rather than three constructor parameters.
foreach ($loopvar as $key => $value)
{
doSomethingThatMightThrow($value);
}
catch (\Exception $e)
{
$exception_type = get_class($e);
$new_message = "[key '" . $key . "'] " . $e->getMessage();
if ($e instanceof \ErrorException) {
throw new $exception_type($new_message, $e->getCode(), $e->getSeverity(), $e->getFile(), $e->getLine(), $e);
}
throw new $exception_type($new_message, $e->getCode(), $e);
}

Categories