简体   繁体   中英

Creating Class Inheritance Dynamically in PHP 5.3

I'm encountering a tricky problem with Inheritance and the hierarchy of Exceptions offered by the Standard PHP Library (SPL).

I'm currently building a helper library in PHP for REST-based APIs. These APIs can return their own error messages in the form of JSON objects, and these objects include information beyond the properties offered by a PHP Exception. Here's a quick example:

{"error":{"time":"2011-11-11T16:11:56.230-05:00","message":"error message","internalCode":10}}

Occasionally, "message" includes internal structure that could benefit from additional parsing. I like the idea of throwing a particular subclass of Exception, like so:

$error = $json->error;
throw new UnexpectedValueException($error->message, $error-internalCode);

Which later can be selectively caught:

catch (UnexpectedValueException $e)
{
  ...
}

And now we arrive at my dilemma: I'd like to extend the SPL Exception objects so that they can have a "time" attribute, and also perform the extra parsing of "message." However, I'd like to extend them at their level as opposed to creating an extension of the base Exception class, so that the ability to selectively catch exceptions is preserved. Lastly, I'd like to avoid creating thirteen different child classes (the number of exception types defined in the SPL ), if at all possible.

Ideally, I could begin with a parent customException object:

class customException
{
  public $time;
  public $message;
  public $internalCode;

  public function __construct($time, $message, $internalCode)
  {
    $this->time = $time;
    $this->message = $message;
    $this->internalCode = $internalCode;
  }

  public function parseMessage()
  {
    // Do some parsing of message
    return $parsedMessage;
  }
}

Then, I'd have a Factory Class that would be able to be invoked like so:

class ExceptionFactory
{
  static public function createException(Exception $e, $exceptionParent)
  {
    $json = json_decode($e->message);
    return new customException($json->time, $json->message, $json->internalCode) extends $exceptionParent;  // Won't work, but hopefully you get the idea
  }
}

After reading php dynamic class inheritance , I can probably get there by using eval() , but that just feels wrong to me. If I have to write the thirteen child classes, then I'll find myself wanting to use multiple inheritance for the desired parent class $exceptionParent and customException . How would you recommend I solve this dilemma? Thank you in advance for your ideas!

Having something like:

class MyException extends \Exception {
  const EXCEPTION_TYPE_FOO = 1;
  const EXCEPTION_TYPE_BAR = 2;
  const EXCEPTION_TYPE_JSON_MESSAGE = 3;

  $protected $_data = array();
  $protected $_exceptionType = null;

  public function __construct( $type = null ) {
    if( null !== $type ) 
      $this->_exceptionType = $type;
  }

  public function __get( $name ) { 
    if( isset($this->_data[$name]) ) {
      if( $name == 'message' ) {
        switch( $this->_exceptionType ) {
           case MyException::EXCEPTION_TYPE_JSON_MESSAGE:
             return json_decode($this->_data[$name]);
           // other exception types
           default:
              return $this->_data[$name];
        }
      } 
      return $this->_data[$name];
    }

    return null;
  }

  public function __set( $name, $value ) {
    $this->_data[$name] = $value;
  }
}

So now you could have:

$e = new MyException(MyException::EXCEPTION_TYPE_JSON_MESSAGE);
$e->time = time();
$e->code = '404';
$e->message = json_encode(array('testing'));

And when you catch it

catch( MyException $e ) {
  print_r( gettype($e->message) );
}

Should return array.

I haven't tested the code, I just wrote it but you get the idea.

One common solution is to use "marker interfaces" to indicate "their level"

interface MyExceptionLevel extends ParentExceptionLevel {}

class MyException extends Exception implements MyExceptionLevel{}

try {
  // code
} catch (MyException $e) {}

// or

try {
  // code
} catch (MyExceptionLevel $e) {}

I recommend not to use too much magic, especially in such a sensible point like error/exception handling.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM