Is this possible in PHP?
try {
$obj = new Clas();
if ($obj->foo) {
// how to exit from this try block?
}
// do other stuff here
} catch(Exception $e) {
}
I know I can put the other stuff between {}, but that increases indenting on a bigger code block and I don't like it :P
With a goto of course!
try {
$obj = new Clas();
if ($obj->foo) {
goto break_free_of_try;
}
// do other stuff here
} catch(Exception $e) {
}
break_free_of_try:
Well, there is no reason for that, but you can have fun forcing an exception in your try block, stopping execution of your function.
try {
if ($you_dont_like_something){
throw new Exception();
//No code will be executed after the exception has been thrown.
}
} catch (Exception $e){
echo "Something went wrong";
}
I also faced this situation, and like you, didn't want countless if/else if/else if/else statements as it makes the code less readable.
I ended up extending the Exception class with my own. The example class below was for validation problems that when triggered would produce a less severe 'log notice'
class ValidationEx extends Exception
{
public function __construct($message, $code = 0, Exception $previous = null)
{
parent::__construct($message, $code, $previous);
}
public function __toString()
{
return __CLASS__ . ": [{$this->code}]: {$this->message}\n";
}
}
In my main code I call it;
throw new ValidationEx('You maniac!');
Then at the end of the Try statement I have
catch(ValidationEx $e) { echo $e->getMessage(); }
catch(Exception $e){ echo $e->getMessage(); }
Happy for comments and criticisms, we're all here to learn!
try
{
$object = new Something();
if ($object->value)
{
// do stuff
}
else
{
// do other stuff
}
}
catch (Exception $e)
{
// handle exceptions
}
Couldn't you just do like this?
try{
$obj = new Clas();
if(!$obj->foo){
// do other stuff here
}
}catch(Exception $e){
}
In php 5.3+ the nice thing about using exceptions with a try catch block, is that you can make your own Exceptions and handle them how and when you want. See: Extending Exceptions
class AcceptedException extends \Exception
{
//...
}
You can then catch specific exceptions or use if ($e instanceof AcceptedException) within your catch \Exception block to determine how you want to handle the exception(s).
Handled Example: http://ideone.com/ggz8fu
Unhandled Example: http://ideone.com/luPQel
try {
$obj = (object) array('foo' => 'bar');
if ($obj->foo) {
throw new \AcceptedException;
}
} catch (\AcceptedException $e) {
var_dump('I was accepted');
} catch (\Exception $e) {
if ($e instanceof \InvalidArgumentException) {
throw $e; //don't handle the exception
}
}
This makes your code much more readable and easier to troubleshoot as opposed to a lot of alternative solutions.
Personally I like to exit try/catch statements by using a
throw new MyException("optional message", MyException::ERROR_SUCCESS);
which I obviously catch by using:
switch($e->getCode()) {
/** other cases make sense here */
case MyException::ERROR_SQL:
logThis("A SQL error occurred. Details: " . $e->getMessage());
break;
case MyException::ERROR_SUCCESS:
logThis("Completed with success. Details: " . $e->getMessage());
break;
case MyException::ERROR_UNDEFINED:
default:
logThis("Undefined error. Details: " . $e->getMessage());
break;
}
This is the way I'd do that :
<?php
echo 'this' . PHP_EOL;
switch(true) {
default:
try {
echo 'is' . PHP_EOL;
break;
echo 'not' . PHP_EOL;
} catch (Exception $e) {
// error_log($e->getMessage());
}
}
echo 'fun !';
:-)
Related
I have code that requires a lot of repeated code such as try and catch exceptions. Looking at the code below could I put the try and catch exception into a function to keep it clean?
public function home(){
try{
$variable = DB::table($tableone)->first();
}catch(\Exception $e){
}
//some code
try {
$variabletwo = DB::table($tabletwo)->first();
}catch(\Exception $e){
}
//some code
try {
$variablethree = DB::table($tablethree)->first();
}catch(\Exception $e){
}
}
function GetFirst($tbl) {
try
{
return DB::table($tbl)->first();
}
catch (Exception $e)
{ ... }
}
$variableone = GetFirst($tableone);
$variabletwo = GetFirst($tabletwo);
You should only make one try catch for the whole block.
You can refer to this answer for best practice on try catch.
I have a situation where it would be nice to be able to have a catch block where the type of the Exception is determined at run time. It would work something like this:
$someClassName = determineExceptionClass();
try {
$attempt->something();
} catch ($someClassName $e) {
echo 'Dynamic Exception';
} catch (Exception $e) {
echo 'Default Exception';
}
Is this at all possible?
That doesn't work as far as I'm aware. You could mimic that functionality with a control statement like this:
$someClass = 'SomeException';
try
{
$some->thing();
}
catch (Exception $e)
{
switch (get_class($e))
{
case $someClass:
echo 'Dynamic exception.';
break;
default:
echo 'Normal exception.';
}
}
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);
}
I have an extended class for dateTime who makes some extra validation steps.
When a given date is invalid, it throws an exception.
Now I have some MySQL records with dates in zero (0000-00-00 00:00:00). In those cases, I want to show the text "never", so I have to catch the exception, and now I have this horrible mess...
try
{
$sellDate = new Date();
$sellDate ->setFromMySQL($this->_data['lastSell']);
$sellDateDMY = $dateSell->getDMY(TRUE);
}
catch (Exception $e)
{
if($e->getMessage() == 'Invalid date.')
$sellDateDMY = 'Never';
else
throw new Exception($e->getMessage());
}
$info[] = array('desc' => 'Last Sell: ' , 'data' => $sellDateDMY);
Any better way to do this?
Depends on which method it is that throws. The simplest would be to subclass Date again (maybe as NullableDate?) and override that method to not throw. The getDMY method would then return null, at which point you can display Never using the ternary operator ?:.
This way you won't have to use the ugly try/catch, and the intent of the code will also be clear to anyone who reads it for info on validation requirements -- by instantiating a NullableDate you definitely don't mind if its value is empty.
class DateException extends Exception {
public function __construct(Exception $e) {
if($e->getMessage() == 'Invalid date.') {
$this->message = 'Never';
} else {
$this->message = $e->getMessage();
}
}
}
try
{
$sellDate = new Date();
$sellDate ->setFromMySQL($this->_data['lastSell']);
$sellDateDMY = $dateSell->getDMY(TRUE);
}
catch (Exception $e)
{
throw new DateException($e);
}
You could start throwing different type of exceptions. Specific to the problem. Instead of the generic catch, you could do this
catch (DateInvalidException $de) {
//code
} catch (DateSomeOtherException $dso) {
//code
} catch (Exception $e) {
//general
}
But that's not a good solution. You're mixing up program exceptions and error validations.
Make your own Exception class for your Date functions.
class MyOwnDateException extends Exception {
... // Do something or probably nothing
}
And call it in your code:
try {
if($someErrorYouWantToCatch) {
throw new MyOwnDateException("error message", 100 /* Error code = optional */);
}
} catch(MyOwnDateException $mode) {
$sellDateDMY = 'Never';
}
Is there something similar in PHP to the try ... else in Python?
I need to know if the try block executed correctly as when the block executed correctly, a message will be printed.
PHP does not have try/catch/else. You could however set a variable in the catch block that can be used to determine if it was run:
$caught = false;
try {
// something
} catch (Exception $e) {
$caught = true;
}
if (!$caught) {
}
I think the "else" clause is a bit limiting, unless you don't care about any exceptions thrown there (or you want to bubble those exceptions)... From my understanding of Python, it's basically the equivalent of this:
try {
//...Do Some Stuff Here
try {
// Else block code here
} catch (Exception $e) {
$e->elseBlock = true;
throw $e;
}
} catch (Exception $e) {
if (isset($e->elseBlock) && $e->elseBlock) {
throw $e;
}
// catch block code here
}
So it's a bit more verbose (since you need to re-throw the exceptions), but it also bubbles up the stack the same as the else clause...
Edit Or, a bit cleaner version (5.3 only)
class ElseException extends Exception();
try {
//...Do Some Stuff Here
try {
// Else block code here
} catch (Exception $e) {
throw new ElseException('Else Clasuse Exception', 0, $e);
}
} catch (ElseException $e) {
throw $e->getPrevious();
} catch (Exception $e) {
// catch block code here
}
Edit 2
Re-reading your question, I think you may be overcomplicating things with an "else" block... If you're just printing (which isn't likely to throw an exception), you don't really need an else block:
try {
// Do Some stuff
print "Success";
} catch (Exception $e) {
//Handle error here
print "Error";
}
That code will only ever print either Success or Error... Never both (since if the print function throws the exception, it won't be actually printed... But I don't think the print CAN throw exceptions...).
Not familiar with python but it sounds like you're after Try Catch blocks used with exceptions...
http://php.net/manual/en/language.exceptions.php
There is try-catch in php.
Example:
function inverse($x) {
if (!$x) {
throw new Exception('Division by zero.');
}
else return 1/$x;
}
try {
echo inverse(5) . "\n";
echo inverse(0) . "\n";
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";
}
// Continue execution
echo 'Hello World';
try {
$clean = false;
...
$clean = true;
} catch (...) { ... }
if (!$clean) {
//...
}
That's the best you can do.
You can use try { } catch () { } and throw. See http://php.net/manual/en/language.exceptions.php
try {
$a = 13/0; // should throw exception
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";
}
or manually:
try {
throw new Exception("I don't want to be tried!");
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";
}