Should I rethrow an exception in this case? - php

Is this approach ok? Am I handling exceptions correctly? See my class:
class Email extends String
{
protected function validate($email)
{
try{
parent::validate($email);
} catch(InvalidArgumentException $e) {
throw $e;
}
if(!filter_var($value,FILTER_VALIDATE_EMAIL))
{
throw new InvalidArgumentException('etc.');
}
}
}

If you are not going to do anything with the exception within that catch block, it's not necessary to enclose that parent method call in its own try-catch block. The method will automatically pass the exception up from the parent's implementation if it encounters one outside a try-catch block, just like if you threw an exception from the same context (as you do after your if condition):
protected function validate($email)
{
parent::validate($email);
if (!filter_var($value, FILTER_VALIDATE_EMAIL))
{
throw new InvalidArgumentException('etc.');
}
}

Related

PHP: Prevent nested try-catch from catching a specific error

I have a PHP script which needs to execute a callback function and catch a specific type of error.
<?php
class MyException extends Exception{}
function doStuff(callable $callback){
try{
$callback();
}
catch(MyException $e){
#Deal with it
}
}
?>
The callback function can use a try-catch which will prevent my exception being bubbled up. How can I allow the callback function to implement try-catch blocks but not allow it to catch MyException?
Forgive me if I've read the question wrong - I can not think of a use case where this is required - but I think something like this will work:
<?php
class MyException extends Exception {}
/*
* This method is in the library. It's not in your control
*/
function doStuff(callable $callback) {
try {
$callback();
} catch(Exception $e) {
die($e->getMessage());
}
}
/*
* We want to do something, but not let any MyException pass through to doStuff()
*/
doStuff(function() {
try {
connect('mysql:dbname=IDoNotExist;host=127.0.0.1', 'batman', 'robin');
} catch(MyException $e) {
return; // Do nothing with MyException, continue as if it didn't happen
} catch(Exception $e) {
throw new Exception($e); // Not an instance of MyException ... let the library handle it
}
});
/*
* This is dummy code that will throw MyException if the username and password are incorrect
*/
function connect($dsn, $username, $password) {
try {
$dbh = new PDO($dsn, $username, $password);
} catch(PDOException $e) {
throw new MyException($e->getMessage());
}
}
I'm assuming, by reading the comments and your responses, that doStuff() is some library call that you pass a callable to. If the code inside your callback catches a MyException you want to completely ignore this.
The code above will completely ignore MyException as if nothing happened. Although I would never advocate such a solution.

Is it possible to catch any exception thrown by an object in it's factory?

For example:
class Test{
public function doStuff(){
throw new Exception("Something gone wrong...");
}
}
class TestFactory{
public static function getTest(){
try{
$testObj = new Test();
return $testObj;
}catch(Exception $e){
//... handle $e ...
throw new Exception("Exception from factory");
}
}
}
When I call "doStuff()", its possible to throw "Exception from factory" instead of "Something gone wrong..." ?
$obj = TestFactory::getTest();
$obj->doStuff(); //Called outside TestFactory
No, try catches errors only within its scope. In your example it will catch exceptions in the Test::__construct only. As soon as object is returned from the factory, it left the try/catch scope.
You can handle "Something gone wrong..." this way:
try {
$obj = TestFactory::getTest();
$obj->doStuff(); //Called outside TestFactory
} catch(Exception $e) {
//... handle $e ...
}
As mentioned by Alex, it is not possible to catch exceptions in the factory method, because when the exception occurs, the factory method is long finished.
From op's comment
The case is I'm extending Pdo and PdoStatement, that throws PdoException in methods like "execute", "prepare" , etc... I have my CustomException class that log those errors and i would like to throw it instead of PdoException, whenever its thrown
PDO will by itself always throw PDOExceptions. I don't think we should change PDO code in a way that it throws other types of Exceptions, nor should we ever throw PDOExceptions ourselves.
What we can do however, is catch those PDOExceptions and throw our CustomExceptions on top of it:
public function doStuff()
{
try { /* PDO code that can throw PDOException */ }
catch (\PDOException $ex)
{
throw new CustomPDOException("Something gone wrong", $ex->getCode(), $ex);
}
}
You have to wrap your code in a way to catch all errors that can be thrown by PDO.

PHP: how to get all defined variables inside exception_handler

I'm working on a exception logging script, I use set_exception_handler() to handle uncaught exception.
Inside my custom exception handler, I use get_defined_vars() but it only return an array with a exception object, every variables created before exception thrown were disappear
$testing_var = 'testtesttest';
try {
throw new Exception("Error Processing Request");
} catch (Exception $e) {
var_dump(get_defined_vars()); // this could get $testing_var
}
set_exception_handler('exception_handler');
function exception_handler(exception)
{
var_dump(get_defined_vars()); // no, it can't get $testing_var, exception object only
}
throw new Exception("Error Processing Request");
In the scope where you are calling get_defined_vars() the variable you are after is not defined, so of course it will not be returned. from the docs:
This function returns a multidimensional array containing a list of all defined variables, be them environment, server or user-defined variables, within the scope that get_defined_vars() is called.
What are you trying to achieve? In general you should pass all information needed to handle the exception to the exception when constructing it. possibly using a custom exception class:
<?php
// custom exception class
// could be extended with constructor accepting an optional context
class ContextAwareException extends Exception
{
private $context;
public function setContext($context)
{
$this->context = $context;
}
public function getContext()
{
return $this->context;
}
}
function exception_handler($exception)
{
if ($exception instanceof ContextAwareException) {
$exception->getContext();
} else {
// we have no context
}
}
/*
* using this exception
*/
$testing_var = 'testtesttest';
$exception = new ContextAwareException("Error Processing Request");
$exception->setContext(get_defined_vars());
throw $exception;
I have found an alternate way to do this. I'm also looking for exception solution but this one works for me. If you use errors instead of exceptions - it seems to work.
set_error_handler('test','handler');
class test {
public static function handler($code, $error, $file = NULL, $line = NULL) {
throw new Exception($error, $code, 0, $file, $line);
return true;
}
}
$testVar='carolines';
try {
trigger_error('megamsg');
}
catch(Exception $e) {
var_dump($e);
$vars=$E BLABLABLA
}
Find yourself how to extract from $e. But if you debug You will see in trace handler function call with $testVar variable

PHPUnit - Throwing, capturing and handling custom exceptions

I'm trying to test a capturing and handling a custom exception in PHP.
I've extended the base exception type with some extra properties and methods.
One of the classes I'm stubbing can throw an exception, I want to be able to test that I'm correctly capturing and handling that exception (which in this case means building a response object to return from the call).
e.g.
try {
$objectBeingStubbed->doSomething();
} catch (\Exception $ex) {
if ($ex instanceof CustomExceptionType) {
$this->_errorResponse->error->message = $exception->getMessage();
$this->_errorResponse->error->code = $exception->getCode();
$this->_errorResponse->error->data = $exception->getData();
} else {
throw $ex;
}
}
I'm attempted to simulate the exception being thrown with:
$objectStub->expects($this->any())
->method('doSomething')
->will($this->throwException(new CustomExceptionType()));
But when the exception arrives in the class I'm testing it's now an instance of "Mock_ErrorResponse_????" which doesn't extend my custom exception. My exception is instead contained in a "$exception" property on the Mock_ErrorResponse.
Is there any way of handling this without being forced to do something horrible like:
if ($ex instanceof PHPUnit_Framework_MockObject_Stub_Exception) {
$ex = $ex->exception;
}
if ($ex instanceof CustomExceptionType) {
...
Inside the class I'm testing?
First of all, instead:
} catch (\Exception $ex) {
if ($ex instanceof CustomExceptionType) {
you should use try/catch structure:
// (...)
} catch (CustomExceptionType $e) {
// (...)
} catch (\Exception $e) {
// (...)
}
So, answering your question, basically probably you're doing sth wrong. Because when the stubbed method throws an exception, it should throw exactly exception that you've set with throwException method.
I don't know how you build your stub (maybe there something is broken, maybe namespaces) but please consider an example below which works fine.
class Unit
{
public function foo()
{
throw new \InvalidArgumentException();
}
public function bar()
{
try {
$this->foo();
} catch (\InvalidArgumentException $e) {
return true;
} catch (\Exception $e) {
return false;
}
return false;
}
}
class UnitTest extends \PHPUnit_Framework_TestCase
{
public function testBar()
{
$sut = $this->getMock('Unit', array('foo'));
$sut->expects($this->any())
->method('foo')
->will($this->throwException(new \InvalidArgumentException()));
$this->assertTrue($sut->bar());
}
}
Of course you can replace InvalidArgumentException with your own implementation exception and this still should work. If you'll still have problems with figure out what is wrong with your code please post more complete example (eg. how you build your stub). Maybe then I can help more.
Nowadays you can use the #expectedException php-doc annotation built-in in PHPUnit: https://phpunit.de/manual/current/en/writing-tests-for-phpunit.html#writing-tests-for-phpunit.exceptions
/**
* #expectedException InvalidArgumentException
*/
public function testBar()
{
$sut = $this->getMock('Unit', array('foo'));
$sut->expects($this->any())
->method('foo')
->will($this->throwException(new \InvalidArgumentException()));
}

How to prevent further execution of class if something fails in constructor

How to prevent further execution of class if something fails in constructor.
........Worker.php..............
class Worker {
public function __construct() {
try {
$this->pheanstalk = new Pheanstalk('127.0.0.1');
}
catch (Exception $e) {
logFatal('Pheanstalk: '.$e->getMessage());
}
}
.............
.............
.............
.............
}
.
............processing.php..........
require_once ROOTPATH.'worker.php';
$worker = new worker();
$worker -> put($Data);
.............
.............
.............
.............
Now if the try block fails in the constructor i dont want to execute put() but rest of code should continue in processing.php
new Pheanstalk('127.0.0.1'); throws a exception which is caught by catch.
Best solution is to catch the exception outside your class. Not only can you skip the put, logging errors is also not really the responsibility of that class anyway. Oh and Unit testing is easier too!
class SomeClass
{
public function __construct()
{
if ($somethingFails === true)
throw new Exception();
}
}
try {
$instance = new SomeClass();
$instance->put();
} catch (Exception $exception) {
// Handle here
logFatal('Pheanstalk: '.$e->getMessage());
}
If it's another piece of application throwing the exception, and your constructor is wrapped around it. Consider catching the exception, and then throwing your own.
Why don't you throw an exception in the constructor?
See http://php.net/manual/en/language.exceptions.php

Categories