views:

299

answers:

4

I'm experiencing what I believe is a circular dependency issue with my PHP application. Please let me know if this is incorrect. Here is the situation:

Two classes, LogManager and DBSession.

DBSession is used to interact with the database, and LogManager is used to log to files. Both are widely used in my application. When you create an instance of DBSession, you must give it an instance of LogManager via a constructor parameter. This because DBSession will sometimes log information to a file, and will use the LogManager instance to do this.

Now, I wanted to extend LogManager so that it could also log to a database table, rather than a text file. Naturally, my preference is to re-use existing classes, but I soon realized this brought about an interesting situation.

DBSession already requires an instance of LogManager for construction. If I want to re-use the DBSession class in LogManager, it will now require an instance of DBSession. How can I satisfy both demands? Clearly, something must be wrong with my approach.

How would you suggest I fix this?

Thanks in advance, guys.

+1  A: 

Maybe you can apply some pattern, like the Singleton Pattern to ensure that you only have one instance of your LogManager class for example.

CMS
+7  A: 

Don't extend LogManager, let it be an aggregate type. And delay the choice of where you want to log, i.e.:

$logManager = new LogManager();
$dbSession = new DbSession($logManager);
$logManager->add(new FileLog($filename) );
$logManager->add(new DBLog($dbSession) );

Where of course FileLog and DBLog share a common interface. This is an application of the Observer pattern, where add() is the "subscribe" operation, and FileLog/DBLog are the observers of logging events. (In this way you could also save logs in many places.)

Owen edit: adjusted to php syntax.

Federico Ramponi
$logManager = new LogManager();$dbSession = new DbSession($logManager);$logManager->add(new FileLog($filename));$logManager->add(new DBLog($dbSession));
micahwittman
It's not consistent in the class names..
Eran Galperin
@Owen: thank you for editing!
Federico Ramponi
This approach sounds much better, thank you!
Matt Refghi
+1  A: 

One of these objects doesn't actually need the other: you guessed it, it's the DBSession. Modify that object so that the logger can be attached to it after construction.

Edward Z. Yang
+1  A: 

Why demand a LogManager object for the creation of a DbSession object, if it only sometimes writes to files? lazy load it instead only when you need it. Also, in my opinion both should be independent from each other. Each could instance the other when needed.

Eran Galperin
Never really tried implementing lazy loading, but thanks for the recommendation. I admit it would be more suitable given that LogManager is only sometimes used with DBSession. Thanks!
Matt Refghi