in my opinion it's better to create a file for every class, where the file is named after the class. i use a slightly different notation than chad birch, namely a Classname.class.php
. class autoloading is a nice feature, but i don't use it very often (only under certain circumstances, like MVC, where classes of the same type are added or removed often).
regarding object modelling: start creating classes for nouns. identify the actors in your application. a method of doing this is to write down what your application is supposed to do, then scan it for nouns and modelling your classes after those. Because a class represents a single object, class namens are singular most of the time. If there are multiple objects, you should name it ObjectCollection or something like this (e.g. "BookCollection").
Lets try it:
I want to create a little book library app to keep track of my book collection. It should track the books i own, the genre, the author(s) and the friends i lent them to. Additionally, for every friend the phone number should be stored, so i can call him. All the information is stored in a database.
- Book: represents a book ("The godfather", "Cryptonomicon")
- Library: represents a collection of Books
- Collection: already covered by Library
- Genre ("Sci-fi", "Thriller", ...)
- Author ("Neal Stephenson", "Mario Puzo")
- Friend ("Joe", "Jill", "Jack")
- PhoneNumber (an property of a friend)
- Database (duh)
then you build the hierarchy. which objects contain other objects, how does the relation between them look like?
- Library contains 0, 1 or more Books
- A Book belongs to exactly one Genre
- A Book is written by 1 or more Authors
- I can lend a book to 0 or 1 Friend and only to one Friend at a time
- A Friend has a phone number
(this will also tell you a thing or two about how your database should look like)
not everything is obvious. do you really need a phone number class? it's only a string. in this case, you should make it a property. Additionally phone numbers are not really shared between Friend objects (it would make sense if several friends living together having the same number and it often changes, but for now that would be a bit overkill). if the noun can be represent by a scalar value (a string, integer, float) and there are no other values connected to them, it may be overkill to make classes.
so, over time you extend your application. you decided to store not only the phone number, but also the address. address and phone number are quite similar types of information, so you add other variables for street, city, post code and so on. at a certain point you'll get frustrated because the Friend class grew huge, with lots of properties, getters- and setters-methods, some of whom are prefixed to group them together (Friend->addressStreet, Friend>addressPostCode and so on). so you might decide to relocate those to an own class, called Address (if you leave the phone number to Friend) or Contact, just to keep the code clean (nothing wrong with that, but be careful).
what about class hierarchy and object hierarchy? don't confuse them, they are entirely different things! a class hierarchy arises if similar classes share some properties but are different in others. so you create one class with the properties and methods they share and child classes which inherit the properties and methods of the parent and also add their own to handle the differences.
in our library example, what could that be? to be honest, i can't think of anything besides one thing thats a bit nonsensical, but let's go for it ...
Friends and Authors are both Persons! both have names, phone numbers and an address. but they also differ, because authors write books and friends don't (and authors normally don't borrow your books). so you might define the name and Address-object in the Person class, but "getUnreturnedBooks()" clearly belongs to Friend while "getBooksWritten()" belongs to Author.
it doesn't really make sense because you're never going to process Authors and Friends in the same run. but lets say you needed a list of all the adresses stored in your library, you could loop over your collection of Persons and call getAddress(). To be honest, even PHP is a bad example for this, because you can store whatever types you want together in an array and access them in every way you want, but in stronly typed languages that's not possible. in java you have to define a datatype for an array, and it's possible to store different types if they have a common inheritance (but you're restricted to the methods the original class had). enough of that class inheritance voodoo.
an object hierarchy simply states which objects should contain other objects. a library contains book objects. a book contains an author object.
some additional pointers:
try to be descriptive. don't use names like "Library->retrieveValues()", name it "Library->getBooks()" instead, because Book objects is what you get.
sometimes it's a good idea to name methods after the data type they're going to return. it's common if they return booleans. good naming conventions may be "has" or "is" as in "Friend->hasBook($book)" or "Book->isInLibraryCurrently()"
values that are always the same for all objects of a certain class may be class constants. lets say, if a Person can be male or female and you're storing that as "m" or "f" in the database, it makes sense define the class constants Person::GENDER_MALE = 'm' and Person::GENDER_FEMALE = 'f', so you don't have "m"s and "f"s scattered in your sql-queries all over the place.
Classes that only generate a single instance could be modelled as Singletons. a good example for this may be the Database class - it's highly unlikley you ever need to open more than one transaction at once. read more about singletons at wikipedia (http://en.wikipedia.org/wiki/Singleton_pattern), but it may be a bit early for that.
update: some people think Singletons are a bad idea, because they're more or less "carved in stone" once you implement them this way. so if you model your Database class as a singleton, but later decide you need more than one database connection (unlikley, but possible), you have a problem. if you take the risk, singletons may be convenient.