php exceptions: should exception be rethrown - php

UPDATE:
I want to do something like this: http://framework.zend.com/wiki/display/ZFDEV2/Proposal+for+Exceptions+in+ZF2
thats way I need every separate exceptions for each framework component
<?php
class ClassA {
public function doSomething() {
throw new ClassA\Exception\BadMethodCallException('bad method called');
}
}
class Application {
public function MainMethod() {
$ClassA = new ClassA();
$ClassA->doSomething();
}
}
try {
$Application = new Application();
$Application->MainMethod();
} catch(\Application\Exception $e) {
// exception cannot be catched, because ClassA\Exception\BadMethodCallException was thrown
}
?>
In my framework eatch components has its own exception classes. So, is it logical that Application throws ClassA exception or should I catch ClassA\Exception\BadMethodCallException in MainMethod and rethrow as Application\Exception\BadMethodCallException like this:
<?php
class Application {
public function MainMethod() {
$ClassA = new ClassA();
try {
$ClassA->doSomething();
} catch(\ClassA\Exception\BadMethodCallException $e) {
throw new Application\Exception\BadMethodCallException('message', null, $e);
}
}
}
?>

I don't have much of a solution for your problem, but having an Exception Class for each part of your App is a bad way to go in my opinion. It doesn't make much sense.
I would just work with the error codes and identify the "Exception thrower" by that.

Related

Laravel is throwing exception event when I have try, catch

I am using laravel 5.4. I have a method in a class that gets a new instance of a model class. The class's full name is computed at run time, so there is a chance the computed class name does not exists. In the case the class does not exists, I want to ignore any exception and I want to return null instead.
But, when an exception takes place, Laravel still throw the exception below even thought I believe it should not
[Symfony\Component\Debug\Exception\FatalThrowableError]
Class 'App\Models\CreatedBy' not found
Note that the string App\Models\CreatedBy was computed at run-time.
Here is my code
private function getForeignModelInstance()
{
try {
if (!$this->foreignModel) {
$model = $this->getFullForeignModel();
if ($model) {
$this->foreignModel = new $model();
}
}
return $this->foreignModel;
} catch (\Exception $e) {
return null;
}
}
How can ignore any error thrown and settle by returning null?
I think the best way is to prevent exception happen instead of hiding it. So before make a new class instance, check if its exists:
private function getForeignModelInstance()
{
try {
if (!$this->foreignModel) {
$model = $this->getFullForeignModel();
if ($model && class_exists($model)) {
$this->foreignModel = new $model();
}
return null;
}
return $this->foreignModel;
} catch (\Exception $e) {
return null;
}
}
Note: class_exists will not work using the short, aliased class name.

Can one call an instance's method inside a class without recreating the instance within class' scope?

I'm relatively new to PHP, I'm trying to make a script to log errors from try/catch blocks. I've run into a scope problem trying to do so.
First, I attempted to make the class instance a global variable but that didn't work.
I know it is possible to make a new instance each time 'AnotherClass' is called; however, that would clear the '$errors' array in 'errorhandler'.
I've been stuck on this issue for a few hours and any help would be greatly appreciated!
<?php
class errorhandler
{
private $errors = [];
function log($e = '')
{
print "Opps! An error occured: " . $e;
array_push($this->errors, $e);
}
}
# global $errorhandler; # Doesn't work...
$errorhandler = new errorhandler();
class AnotherClass
{
function __construct()
{
try {
$not_possible = 1/0;
} catch (Exception $e) {
$errorhandler->log($e); # Doesn't work
}
}
}
new AnotherClass();
?>
Thanks :)
You have to import the global $errorhandler variable into your local scope:
class AnotherClass
{
function __construct()
{
global $errorhandler;
try {
$not_possible = 1/0;
} catch (Exception $e) {
$errorhandler->log($e); # Doesn't work
}
}
}
P.S. 1/0 is not an exception, it's a runtime error. You can't catch those with a try/catch block.

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

Why doesn't PHP catch a "Class not found" error?

In the following example, if the class does not exist, I want to catch the error and create a Null class instead.
But in spite of my try/catch statements, PHP simply tells me Class 'SmartFormasdfasdf' not found.
How can I get PHP to catch the 'class not found' error?
<?php
class SmartFormLogin extends SmartForm {
public function render() {
echo '<p>this is the login form</p>';
}
}
class SmartFormCodeWrapper extends SmartForm {
public function render() {
echo '<p>this is the code wrapper form</p>';
}
}
class SmartFormNull extends SmartForm {
public function render() {
echo '<p>the form "' . htmlentities($this->idCode) . '" does not exist</p>';
}
}
class SmartForm {
protected $idCode;
public function __construct($idCode) {
$this->idCode = $idCode;
}
public static function create($smartFormIdCode) {
$className = 'SmartForm' . $smartFormIdCode;
try {
return new $className($smartFormIdCode);
} catch (Exception $ex) {
return new SmartFormNull($smartformIdCode);
}
}
}
$formLogin = SmartForm::create('Login');
$formLogin->render();
$formLogin = SmartForm::create('CodeWrapper');
$formLogin->render();
$formLogin = SmartForm::create('asdfasdf');
$formLogin->render();
?>
Solution:
Thanks #Mchl, this is how I solved it then:
public static function create($smartFormIdCode) {
$className = 'SmartForm' . $smartFormIdCode;
if(class_exists($className)) {
return new $className($smartFormIdCode);
} else {
return new SmartFormNull($smartFormIdCode);
}
}
Because it's a fatal error. Use class_exists() function to check if class exist.
Also: PHP is not Java - unless you redefined default error handler, it will raise errors and not throw exceptions.
Old question, but in PHP7 this is a catchable exception. Though I still think the class_exists($class) is a more explicit way to do it. However, you could do a try/catch block using the new \Throwable exception type:
$className = 'SmartForm' . $smartFormIdCode;
try {
return new $className($smartFormIdCode);
} catch (\Throwable $ex) {
return new SmartFormNull($smartformIdCode);
}
php >= 7.0
php can catch 'class not found' as Throwable
try {
return new $className($smartFormIdCode);
} catch (\Throwable $ex) {
return new SmartFormNull($smartformIdCode);
}
You need to use class_exists to see if the class exists before you try and instantiate it.
Incidentally, if you're using a class autoloader, be sure to set the second arg to true.
Because php emits fatal error when you ty to create new object of non existing class. To make it work you will need php >= 5.3 and autoload function, where you should try to look for file with class definition or throw your custom exception.

Categories