When designing your classes, there is one golden rule: keep to real-world thinking. However, although that one rule sounds simple, it's quite nebulous - what exactly is real-world thinking? Fortunate there are a number of more simple rules you can follow that will help keep your code particularly readable:
Start or end local variables with a special character so that you are always clear about what variable is being set. The most common method is to start local variables with an underscore, e.g. _Name, _Age, etc.
To strictly follow OOP guidelines, nearly all of your variables should be either private or protected - they should not be accessible from outside of an object.
Write accessor functions to set and get private variables. These functions should be how you interface with the object. To get a variable called _Age, write a function Age(). To set a variable called _Age, write a function SetAge().
Always put variables and functions as low down in your inheritance as they can go without repetition - if you find one object has variables and functions it is not supposed to have, you have gone wrong somewhere. For example, while dolphins can swim, gorillas cannot, so do not put a swim() function into a mammal class "just to save time".
Always keep in mind Muir's law: "When we try to separate anything out by itself, we find it hitched to everything else in the universe". Get your classes distinct and separate from each other to begin with rather than try to hack them apart later on.
If you are wondering why it is that accessor functions should be used to read and write variables, it is because OOP practice dictates that objects should be self-contained - other parts of your program should be able to work with them using simple function calls. For example, imagine you are programming a strategy game where players can control multiple cities. Each city brings in various amount of food depending on how many workers are there. Now, if the player changes the number of workers in a city to 800, you could just effect the change with code like this:
$City->_Workers = 800;
However, how would that make any change to the amount of food coming in? It wouldn't, so you would need to make your code this:
$City->_Workers = 800; $City->_FoodSurplus = WORKER_SPEED * 800;
Now, what if a few weeks later you decide that people can upgrade their cities to build farms and processing facilities that increase the amount of food being made? You'd have to search through your code for all the times you change the _FoodSurplus variable, and make sure it takes that into account. Later, if you want to make more changes, you need to repeat the procedure again and again and again - the calling code needs to have explicit knowledge of how to handle changes to the number of workers in a city.
This is not how OOP works. In the OOP world, a city would be supposed to handle all these calculations itself, leaving the calling code looking like this:
The SetWorkers() function would contain all the other changes such as altering the _FoodSurplus level, but the key is that the calling code wouldn't need to know anything about that - any changes to the SetWorkers() calculation only needs to be made in one place.
Want to learn PHP 7?
Hacking with PHP has been fully updated for PHP 7, and is now available as a downloadable PDF. Get over 1200 pages of hands-on PHP learning today!
If this was helpful, please take a moment to tell others about Hacking with PHP by tweeting about it!
Next chapter: Basic inheritance >>
Previous chapter: Defining a class
Home: Table of Contents
Copyright ©2015 Paul Hudson. Follow me: @twostraws.