I was talking about Object Oriented Design with someone the other day and the topic of making an object’s member variable read only came up. This is normally a simple task, simply define the member variable as protected or private within the class definition. That essentially makes it inaccessible to any code outside of the class it is a member of. One would then typically define an access function that allows outside code to read the variable. Here is an example:
class readOnly
{
private $readOnlyVar;
public function __construct()
{
$this->readOnlyVar = 'This is read only';
}
public function getReadOnlyVar()
{
return $this->readOnlyVar;
}
}
$readOnly = new readOnly();
echo $readOnly->getReadOnlyVar();
$readOnly->readOnlyVar = 'Trying to change this';
Running that code would produce the following output:
This is read only
Fatal error: Cannot access private property readOnly::$readOnlyVar
Perfect! The issue is solved. You now have a variable that outsiders can get the contents of but not change it. One annoying problem can arise though. What if you have a large number of member variables inside of one class that you need to make read only? Do you really want to go and write an access function for every single variable? What if there are hundreds? An even worse situation can arise when utilizing more advanced schemes with a dynamic set of member variables that you may not know at the time of writing the code.
We want to come up with a scheme that would allow us to write code like below to access the readOnlyVar in our readOnly class:
echo $readOnly->readOnlyVar;
With our readOnly class as it is now, the above line of code would produce a fatal error complaining that the readOnly::$readOnlyVar is a private property. So how can we accomplish the above line of code without errors? Let magic functions in PHP 5 come to the rescue. There are several ways to use magic functions to accomplish our goal but we will utilize the __get magic function.
The __get magic function is called anytime that a non-existent member variable is referenced on an object. It just so turns out that it is also called when external code tries to access private or protected member variables, since they are technically non-existent to the outside world. The name of the member variable attempting to be accessed is passed in to the __get magic function and we will utilize this to retrieve the value of our read only variable.
class readOnly
{
private $readOnlyVar = "This is read only";
private $readOnlyVar2 = 3;
public function __construct()
{
//Standard initialization statements
}
public function __get($varName)
{
return $this->$varName;
}
}
$readOnly = new readOnly();
echo $readOnly->readOnlyVar;
echo $readOnly->readOnlyVar2;
//try to change the variables though
$readOnly->readOnlyVar2 = 5;
Here is our new output:
This is read only
3
Fatal error: Cannot access private property readOnly::$readOnlyVar2
As you can see, we can easily get the contents of any of the private member variables without writing a new access function for each one. We still get an error when trying to change the read only member variables also. There is one catch to consider and it lies in the first sentence of this paragraph. The scheme will expose ALL of your private or protected member variables as read only. There will most likely be cases where some member variables you want to be visible but others you want to be truly private. I would recommend in this situation to setup a naming convention for truly private member variables. I usually prefix any inaccessible member variable with an underscore. You could then modify your __get magic function to first check if the variable starts with an underscore before returning its contents.
There are various upsides and downsides to this approach. Some positives are less code to write, faster development and cleaner more concise code that uses the object. Some negatives are that it can be a little cryptic to other programmers that a variable is read only and you may accidentally expose a private member variable that you do not wish to. In the end though, I believe it is a great approach to quickly develop a class with many read only member variables.
Related Entries
- 01.04.08: California, BarcampOrlando and OrlandoPHP 1 comments
- 23.09.07: First Annual Barcamp Orlando 0 comments
Derek is a software and web developer in Orlando, FL. Check back often for updates on Orlando and Technology.
mezei Says:
June 1st, 2008 at 5:20 am
Nice, thanks.