Friday, February 13, 2009

Friday the 13th: Protected variables can be evil.

The following post on Nabble this week brought up an important 'issue':

Read the post

Remember, private variables and functions are visible only to the actual class you're in, protected will be visible also to its descendants. The use of protected variables isn't evil in itself. It can be good. It's good if it's usage is well documented and has a real reason to exist.

When you make a class that is meant to be derived, you are in fact providing other programmers a base class that can be used by other programmers to do the things they need. You are providing a service, and it is your duty to make sure the service you are providing works well. When you create a protected variable, programmers that use your base class will be able to use this variable. If you then decide to change the functionality/content of this protected variable, you can actually break the code of your descendant. This is unacceptable in real-world applications.

What can you do? There are two possibilities. You can use a protected variable and document it and tell the users of your class they can safely use it, and *never* change the functionality of this varilable. It *is* possible! Look at Zend_Db_Table_Abstract. It contains a protected variable called $_metadata. This variable is *meant* to be used, as stated in the Zend Framework documentation.
To take metadata caching a step further, you can also choose to hardcode metadata.
They then go on with an example on how to setup the variable with metadata information. This is a good example of a protected variable used the right way.

Now let's take a look at the $_cols protected variable. There is also a $_getCols() method. Why? Why is $_cols protected, and not private? There is a protected getter here, why make $_cols also protected? Here, programmers might start using $_cols directly, and when it's functionality changes, it will break their code. If you force the programmers to use $_getCols(), you can hide the internal functionality of the $_cols variable and provide a return value for $_getCols() any way you want.

Bottom line, create protected variables only when it makes sense, if not, make your variable private, and provide protected getters and setters so that your descendants can access the variable in a safer way.

Don't forget, you can't blame your class users for using a variable that was not meant to be used. It's your duty to make it private if you don't want them to use it. Imagine if you had a new TV with a big, red button, with no sign around it, that destroys your TV when you press it. Do you think the TV maker could blame *you* in court for pushing a button that was not documented in the manual? I don't think so. It's the same with OOP. Design well, and don't blame your class users for your own mistakes.

No comments:

Post a Comment