Dangers of mutual dependencies

Much like most people, I try work out my class dependencies through a top-down 'waterfall'-ish approach. By attempting this, I think allows me to keep the structure very clear and understandable.

Example of top-down dependency approach
excuse my non-existent UML skills

In this example the Ingredient class (and subclasses) is Never aware of any Recipe classes, but only the other way round.

I try to apply the same model to instantiated objects and packages (groups of classes). When an object encapsulates another object, I attempt to make sure the sub-object object is not aware of the parent. When I design packages, I attempt to make sure 2 packages don't require 'each other'.

An example where this could be a problem is the following. Say, I have a 'Database' package. I want to log every database error to a 'Log' package. The 'Log' package has a couple of implementations, such as 'Log_File', 'Log_Syslog', but now I added 'Log_Database' to log any problems to the database.

Mutual dependency

Strictly speaking these two packages can no longer be separated and will always have to be used/downloaded together. As a bonus a database-error could occur while logging, resulting in an endless loop (or segmentation fault if you're using PHP).

Another example of a mutual dependency:

  1. file1.php:
  2.  
  3. <?php
  4.  
  5. include 'file2.php';
  6.  
  7. ?>
  8.  
  9. file2.php:
  10.  
  11. <?php
  12.  
  13. include 'file1.php';
  14.  
  15. ?>

You get the idea ;)

However, these types of situations are sometimes simply unavoidable (that's why we have include_once). When they are needed, they should be implemented with care and consideration. The problem with the Log class could be fixed if the Log_Database is aware of errors thrown by itself, and this could be repackaged by creating by separating the Log_Database in a new package, depending on both the 'Connection' and 'Log' classes.

Editors note: this post was part of a much larger article around designing plug-in systems, but I lost inspiration and decided to post just this part.

PHP and circular dependencies

Today I noticed the strangest bug in PHP. Apparently there's a problem with circular dependencies and interfaces.

This is how the problem occurs:

  1. <?php
  2.  
  3. // this is class1.php
  4.  
  5. require_once 'iclass.php';
  6.  
  7. class class1 implements iclass {
  8.  
  9. }
  10.  
  11. ?>
  1. <?php
  2.  
  3. // this is class2.php
  4.  
  5. require_once 'class1.php';
  6.  
  7. class class2 extends class1 {
  8.  
  9. }
  10.  
  11. ?>
  1. <?php
  2.  
  3. // this is iclass.php
  4.  
  5. require_once 'class2.php';
  6.  
  7. interface iclass {
  8.  
  9. function setSomething(class2 $object);
  10.  
  11. }
  12.  
  13. ?>

Now, if you run class1.php, you will get the following error:

  1. Fatal error: Class 'class1' not found in /home/filemobile/testscript/class2.php on line 5

I know this is not proper OOP, but its still a strange error. Normally PHP is pretty good at these weird structures ;). Weirdest thing was that it happened for me on one server, but not the other.

There is a bug marked bogus for this, which is understandable. It would be great though if the PHP could somehow throw an error thats a bit more helpful =P. Its a strange error, especially since I could only reproduce it with this structure, and not with for example just 2 classes with circular dependencies.

 1

About

My name is Evert, and I've been writing semi-regularly on this blog since 2006.

I'm currently available for contract work.

more info.

Subscribe

Dropbox

Dropbox is a simple cross-platform online backup and sync application. The first 2GB of space is free, and both you and me get an extra 250MB extra space if you sign up through this link.