Had a bit of spare time to learn some OOP in PHP this evening and hit a brick wall. I am creating a little book library app to keep track of my book collection and thought I would use OOP for practice.
I have a main php file called library.php that contains 2 main classes so far.
// Connect to Host & DB
$database = new database();
$database->mysqlConnect('localhost', 'root', '');
// Retrieve Values
$book = new books();
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 names 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)
Then you build the hierarchy. Which objects contain other objects, how does the relation between them look like?
Librarycontains 0, 1 or more
Bookbelongs to exactly one
Bookis written by 1 or more
Bookto 0 or 1
Friendand only to one
Friendat a time
(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>addressPostCode and so on). So you might decide to relocate those to an own class, called
Address (if you leave the phone number to
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 that's a bit nonsensical, but let's go for it ...
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
Address-object in the
Person class, but
getUnreturnedBooks() clearly belongs to
getBooksWritten() belongs to
It doesn't really make sense because you're never going to process
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 strongly 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
book objects. A
book contains an
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
is as in
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 unlikely 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 (unlikely, but possible), you have a problem. if you take the risk, singletons may be convenient.