Jump to content

dependency injection and error handling


topcat

Recommended Posts

Hi there,

 

I have been writing my own MVC framework which is basically a lightweight version of ZF1. One thing I am tying to improve on in my version is the decoupling of objects. As I am  on a tight deadline I decided to implement Zend_DB until I can develop/find a better alternative, I quickly realised that all of the Zend components have their own error objects which extend the PHP Exception object, this obviously creates a dependency, if you don't use Zend framework then you do not have access to the Zend_Db_Exception object.

 

To avoid this I was thinking of injecting the  name of a specialised error class in the constructor call to each of my classes. It would not make sense to pass an error object instance as there may be more than one error object required but I could pass the class name and initialise an error object using the class name from within each object. DI is something that I am aware of as a concept but have had no practical experience of implementing and I was wondering what people thought of the approach I intend to take? Alternatively if someone is aware of a common clean technique for error handling without adding dependency and coupling I'd love to hear about it.

 

Cheers.

 

An example:

class router{
 private $error_class

 public function __construct(Array $Params = Array()){
    $this->error_class = $Params['error_class_name'];
    ...
 }

 public function routeStuff($url){
  try{
     ......
  }catch($e){
     throw new $this->error_class("something went wrong");
  } 
 }
}

 

Link to comment
Share on other sites

I would suggest that the whole issue revolves around the fact that your using ZF1 components which are out of date and (as you can see) are not very easily used as stand alone "components".

 

Why don't you use ZF2 stuff? or Symfony2 stuff, or Laravel stuff or any other modern framework that uses namespaces, PSR-0 and composer ?

 

This, would solve a number of your issues out of the box.

 

Injecting a string and relying on that being a valid class name for a class that may or may not exist just seems very unreliable. If your going to "inject" something, it should be an object that implements some interface. You then rely on the interface, not the implementation.

Link to comment
Share on other sites

Thanks for the reply trq. I see your point and agree with it. However I also don't like the idea of instantiating an object that may not (and hopefully will not) be used. It doesn't feel right either. If this were a functional component which will definitely be required by the class I wouldn't consider any other option other than instantiating the object and injecting it in the constructor, eg if it were a db connection object etc. but that isn't really the case.

 

To be honest I'm using ZF1 components because I have used them a lot and I am familiar with them. I don't really have the time right now on this project to learn another framework from the ground up. Especially ones such as zf2 or Symfony2 which have a completely different design principle to zf1.

I will take a look at some zf2 classes to see how they implement error handling.

Link to comment
Share on other sites

I'm not saying you need to learn some other framework from the ground up. I'm saying these frameworks are much better designed and are much less tightly coupled.

 

For instance, you should be able to install whatever database stuff Zf2 now provides (I don't use Zf1 or Zf2) via composer and this will install everything it needs to work.

 

It's actually pretty hard to see from your example what your stuck on. I meen, it looks like "your" router class, surely it should know what type of exception it is going to be throwing? I meen, any calling code is going to need to know what exception is being thrown too, how do you propose that is handled?

 

Anyway, if you don't want to be injecting actual objects, you could go down the path of IoC containers and all that jazz. Iv'e built them before and a simple implementation is just that, simple, it's only as you start adding more functionality that they become more complex.

Link to comment
Share on other sites

Again, thanks for the reply, I appreciate your time.

The calling code does not need to know what type of error object has been created in the router (in this example), only that it is an instance of the Exception class (which it will be as all exception classes would be a child of Exception) the exception object is then just dispatched to an error controller which logs the error and displays the details in a view script for debugging.

My understanding of DI at least at a basic level was that the poiint  (or at least a point) was to inject classes depended on by another class rather than instantiating them within the "consuming" class. This avoids the refactoring required if for any reason you wish to substitute the injected class for another at some point. Eg as I wish to do so now by using my own error objects rather than Zend's error classes. Basically to remove coupling based on dependency?

Edited by topcat
Link to comment
Share on other sites

My understanding of DI at least at a basic level was that the poiint (or at least a point) was to inject classes depended on by another class rather than instantiating them within the "consuming" class. This avoids the refactoring required if for any reason you wish to substitute the injected class for another at some point.

That is indeed correct. However there is no point passing any old object into a class if that class doesn't know what to do with it. Hence, most people use type hinting along with dependency injection so as to ensure there is some form of contract between the two classes.

I wish to do so now by using my own error objects rather than Zend's error classes

That was what I was trying to get at. Why are you using Zf1's error classes within your own router?
Link to comment
Share on other sites

Aha I see the confusion - the example was a purely abstract one simply to show my thinking regarding the instantiation of a named class. Sorry about that. Should have made it clearer that this was a hypothetical scenario. The actual issue I am facing is that when I use Zend_Db if there is any error with the SQL statement then it tries to throw a Zend_Db_Exception. However Zend_Db_Exception is not available in my framework. I realise that I could easily make it available but this is avoiding the issue rather than solving it. I wish to remove this dependency. Also I do not want to substitute it with another dependency by simply replacing all of the Zend_Db_Exceptions with my own hardcoded classes. I would have the same situation if I wished to move the component to another system later on.

Link to comment
Share on other sites

Actually looking at ZF2 the exceptions are still hardcoded however the exceptions seem much more standardized across all components with each exception being defined within each namespace. So there is at least no dependency on a file outside the namespace used by that particular component.

Link to comment
Share on other sites

That doesn't sound any different to the example you told us about in Zend_DB and Zend_DB_Excpetion. They are both in the pseudo DB namespace.

 

It's a nice idea to try and decouple your components as best you can but going as fare as removing all hard coded dependencies is not always achievable nor really required. A few exceptions, utilities and other bits and pieces are always going to be excepted as dependencies and no one is really going to be looking to swap these things out or test your components within mocked versions of these things anyway really.

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.