PHP: how to get all defined variables inside exception_handler - php

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

Related

Uncaught exception when passing exception up through class

I have a class named User that calls one of its own methods, setUsername(), upon construction, within a try/catch block. If setUsername() fails, it will throw an exception:
class User {
private $username;
public function __construct($input_username) {
try {
$this->setUsername($input_username);
} catch(Exception $e) {
throw $e;
}
}
private function setUsername($username) {
if(1 != 0)
throw new Exception("1 does not equal 0!!!");
$this->username = $username;
}
}
I then create a new User in an external function, in a separate file, within its own try/catch block. It's supposed to catch the exception passed through from the User class constructor:
namespace UserController;
function createUser(){
try {
$user = new \User('sample-user');
} catch(Exception $e) {
echo $e->getMessage();
}
}
Why, then, am I still getting an "Uncaught Exception" error?
It seems I was missing a statement at the top of the file that instantiates the class, since it is namespaced. After the namespace declaration, it needs to say:
use \Exception;

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.

In __destruct(), how can you see if an exception is currently in flight?

How can I see if an exception is currently in flight, i.e. the stack is unwinding?
In the example below how would you implement isExceptionInFlight()?
<?php
class Destroyer
{
function __destruct() {
if (isExceptionInFlight()) {
echo 'failure';
} else {
echo 'success';
}
}
}
function isExceptionInFlight() {
// ?????
}
function createAndThrow()
{
$var = new Destroyer;
throw new \Exception;
}
createAndThrow();
The purpose of this would be to implement D's scope statement, which is available as a library in multiple other languages. This allows you to get rid of nested try-catch blocks, which in turn makes it easier to do transactions with rollbacks correctly.
Addendum1:
I've looked around in the Zend PHP Engine and executor_globals.exception seems to be what I'm looking for (https://github.com/php/php-src/blob/master/Zend/zend_globals.h). However this value is always nullptr when I inspect it during __destruct(). Any idea where I should look next?
Addendum2:
Inspecting executor_globals.opline_before_exception has led to some progress. However it is not reset to nullptr when the exception has been caught.
Addendum3:
I've found the following code (line 135)
/* Make sure that destructors are protected from previously thrown exceptions.
* For example, if an exception was thrown in a function and when the function's
* local variable destruction results in a destructor being called.
*/
old_exception = NULL;
if (EG(exception)) {
if (EG(exception) == object) {
zend_error_noreturn(E_CORE_ERROR, "Attempt to destruct pending exception");
} else {
old_exception = EG(exception);
EG(exception) = NULL;
}
}
zend_call_method_with_0_params(&obj, object->ce, &destructor, ZEND_DESTRUCTOR_FUNC_NAME, NULL);
if (old_exception) {
if (EG(exception)) {
zend_exception_set_previous(EG(exception), old_exception);
} else {
EG(exception) = old_exception;
}
}
This seems to actively PREVENT me from doing what I want, and explains why executor_globals.exception is always nullptr.
Although I don't recommend, I have implemented it in the past. My approach was (simply put) like this:
Implement custom Exception class
class MyException extends Exception {
public static $exceptionThrown = false;
public function __construct($your parameters) {
self::$exceptionThrown = true;
}
}
Now, every exception should be your own exception implementation instead of default Exception.
class Destroyer {
public function __destruct() {
if(MyException::exceptionThrown() {
Database::rollback();
} else {
Database::commit();
}
}
}

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()));
}

Should I rethrow an exception in this case?

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.');
}
}

Categories