I'm working on a fairly simple OO PHP framework (not really important in this case I guess..), with the following basic structure:
application/
classes/
controllers/
includes/
models/
views/
classes/
includes/
I know that using interfaces rather than hardcoding classes is good practice for OOP, but I'm not sure what best practice is when it comes to the actual location/structure of interface directories and files.
Should interfaces be separated into multiple files under a directory:
interfaces/
iDatabase.php
iRouter.php
or should they all be put in a single file since they're not that large:
includes/
interfaces.php (with all Interfaces inside)
With the first option I could use an autoloader to load interfaces and not have to load every file when not all may be used, while with the second option they would all be loaded initially but it would save me having to load multiple files each time.
What are your thoughts? Am I totally looking at this the wrong way (I tend to do this with most of my problems until someone steers me in the right direction! haha)
Thanks heaps!
Ryan
Edit 2011-02-07:
After reading the answers I've been given so far, I've tried out a few things.
Assuming the classes below get autoloaded from the exact location on the disk (Database_Database would get loaded in 'classes/Database/Database.php'), would this set up be effective?
class Database_Mysql_Database extends Database_DatabaseAbstract implements Database_Database {}
Database_Mysql_Database is a normal class, Database_DatabaseAbstract is an abstract class with the basic methods common to different types of databases, Database_Database would be the interface that users would typehint against to ensure compatibility with their classes.
Am I on the right track?
Personally, I would suggest that you put interfaces and exceptions where they are semantically appropriate. There's no reason to lump them all into one folder away from classes. But at the same time, don't put them next to the concrete implementations just for the sake of it. I'll give an example.
Let's say we're dealing with a database abstraction layer. You'll have an iDatabase
interface, and an iDatabaseDriver
interface. Say your folder (and class) structure is like this:
/classes/database/idatabase.php
/classes/database/database.php
/classes/database/drivers/mysql/databasedrivermysql.php
/classes/database/drivers/postgres/databasedriverpostgres.php
Now, there are 2 logical places to put iDatabaseDriver
. You could put it under database, or under drivers. Personally, I would put it under database, since it's kept close to where it's needed (since it's more likely that Database
requires an iDatabaseDriver
, so the dependency is there).
So, with that, you can see that sometimes it's semantically appropriate to put the interface right next to the concrete implementation. But other times it's more appropriate to put the interface next to the dependency than the concrete implementations.
Now this example is a gross-over-simplification, but I think it should get the point across.
Have rules for your naming and storage of interfaces
Come up with a system for organization of code. That way it's more predictable and easier to autoload. Plus, it becomes far easier to maintain when you can tell where something's supposed to be by the rules
Abide by those rules!
This is more important than having rules. If you don't follow the rules, it's worse than not having them at all since you're expecting something that's not going to happen.
Favor semantic relationships over code-level relationships
The semantic relationship between an interface and its concrete implementations is more important than the relationship that an interface is an interface. So put semantically related code in the same (or similar) places.
Edit: Regarding naming and your edit:
Personally, I hate things like Database_Database
. While it may make sense given the structure of the application, it makes no semantic sense whatsoever. Instead, what I like to do in my autoloader(s) is to test for the file, and if it doesn't exist but the directory does, test for the same file inside of that directory. So, Database
would result in a check in /database.php
and if that fails, /database/database.php
. It removes the need for double naming. Database_DatabaseAbstract
would become Database_Abstract
. So your Database_Mysql_Database
could become Database_Mysql
stored in /database/mysql/mysql.php
(which to me seems cleaner).
As far as your naming convention of abstract classes and the such, I personally prefer to identify interfaces by the name. It makes it easier to understand at a glance (You know that public function foo(iDatabase $database)
is looking for an instance of the interface instead of an abstract class or concrete class). Now, there are two real ways of doing this.
Append Interface
to the name, so Database_Database
would become Database_Interface
. I personally feel this is a bit too verbose for my needs, however the benefit here is that all of your special class types (Exceptions, Interfaces, Iterators, etc) can simply be mapped like this. The class name tells you exactly what you have with no ambiguity whatsoever.
Prepend the entire sequence with i
. So Database_Database
would become iDatabase
which would then be translated in the autoloader to /database/interface.php
. Then, if you had deeper interfaces, iDatabase_Mysql_Query
could work as well (Which would map to /database/mysql/query/interface.php
.
As far as the abstract class is concerned, I wouldn't do that. The fact that a class is abstract shouldn't really have anything to do with its semantic meaning. The abstract nature is a coding construct and not a semantic one (the abstract class is used for nothing other than inheritance since you're using the interface for type-checking). Therefore I would not recommend including Abstract
in the class name. Just call it Database
and be done. It reads better semantically (IMHO) and conveys the same meaning.
I hope that helps and makes sense...