What strategies are available to creating accessors and mutators for a PHP class' private members? Is this suggestion good: http://cormacscode.wordpress.com/2009/01/22/read-only-object-variables-in-php-using-magic-methods/
<?php
class classWithReadOnlyVar
{
private $readOnlyVar;
public function __get($varName)
{
return $this->$varName;
}
public function __set($varName,$varValue)
{
}
}
What if some members needed a private, public, or protected property method?
Having a
__set
method that does nothing is nonsense. It gives the false impression that properties exist and are accessible when they really are not. Just leave out the empty method and PHP will properly throw errors when you try to modify non-modifiable properties.Also, any accessor methods can only be
public
, anything else doesn't make sense.protected
andprivate
accessor methods don't make sense, since the only entity able to access them could also access the properties directly.Summary of the discussion in the comments below:
It is not a good idea to use magic methods as
__get()
and__set()
. The first reason being that the code doesn’t communicate its intend clearly. Secondly, a client will have to know about which fields are available to be able to use the magic methods. This violates the Law of Demeter that says a module shouldn’t know about the innards of the objects it manipulates.Accessors, mutators and predicates should be named for their value and prefixed with
get
,set
, andis
.For example:
You should by all means try to avoid creating public mutators, as it is tempting for external functions to use them the way a procedural program would use a data structure and thereby manipulate the internal state of the object, known as Feature Envy.
The methods of a class should only be interested in the fields and methods of the class they belong to, and not the fields and methods of other classes. When a method uses accessors and mutators of another object to manipulate the data within that object, then it envies the scope of that object. So we want to eliminate Feature Envy because it exposes the internals of one class to another. Sometimes, however, Feature Envy is a necessary evil, e.g., in the case where one object’s method requires the another object’s data to act upon, and moving that object’s method into the object holding the data would violate principles of object oriented design.
Why then should we have accessors and mutators if other classes shouldn’t use them? Well, making accessors and mutators protected allows for derived classes to access the parent’s private fields, yet still shielding the objects internal state from external peeking and poking.
But couldn’t we then just set the field to protected and thereby eliminating excess methods of the class? We surely could, but then you don’t have the possibility to shield the field from being set by a subclass.
In PHP, we could even argue that it makes sense for a class to use private mutators, so we have the opportunity to type check the value before it is set on the field.
For example:
Here an exception is thrown if
$myField
is not an integer ornull
. However, it could also be argued that such code is a sign of mistrust to own coding. Regardless, having a private mutator can easily be changed to protected to allow for subclass manipulation of the field, and the accessor method could be set to private or removed to prevent subclasses reading the field.First of all,
__get
,__set
, etc. are definedpublic
and you cannot have them otherwise. Magic methods should be used wisely as it takes about three times as long to make a call to a magic method than simply calling a class method.Usually (normally, preferably), you will have your class members
private
orprotected
(neverpublic
) and have accessors and mutators to encapsulate them. Those accessors and mutator may be of any visibility, depending on what the user can do with the members. You may also have immutable classes by declaring only accessors for your members, which are initialized in the constructor only.So, your sample class should read
and should not use the magic methods.
There may be many reasons to avoid using magic methods at all :
protected
magic methodClass members
Their visibility should be
private
orprotected
, it all depends if you want them accessible by inheritence. They should never bepublic
as this breaks the OO paradigm.Example of a protected member:
(without
$_name
beingprotected
, this would not be possible, and no need to redefine the accessor)Accessors
They should be
protected
orpublic
. Having aprivate
accessor makes no sense; a class should access it's member directly. If the member needs processing, the class will know regardless when to call the accessor or not.Mutators
They should be
protected
orpublic
. As for the accessors, it makes no sense to have aprivate
mutator... unless a very rare case when processing needs to be done internally. If a class member has no accessor, it should not have a mutator. It also makes no sense to have a mean to set a value without being able to get the value back somehow.