PHP: Prevent Adding Properties to Objects
We can prevent adding properties to instantiated objects in PHP to help enforce good coding practice; in this tutorial I show how this is accomplished.
By. Jacob
Edited: 2020-09-06 10:06
We can prevent adding new properties to PHP Objects by using the magic __set method; this method is only called when someone attempts to add a non-existent property to an instantiated object and therefor carries no performance penalty.
To use the __set magic method, just include it in an existing class, like this:
public function __set($name, $value) {
throw new \Exception("Adding new properties is not allowed on " . __CLASS__);
}
If you got a lot of classes, you can also create a trait that can be easily included in the classes where you want to prevent adding new properties:
trait no_set {
public function __set($name, $value) {
throw new \Exception("Adding new properties is not allowed on " . __CLASS__);
}
}
To include it in a class, we employ a use statement:
class some_class_name {
public some_method_name() {
// Whatever ....
}
use lib\class_traits\no_set;
}
Why prevent adding non-existent attributes to objects?
In an objected orientated context, it will typically be possible to add new properties to instantiated objects and thereby use them as a sort of "container" for data; doing this is of course a bad practice, and should be avoided.
You might argue that most developers will know not to do that, which is probably true; but why allow it when we can easily prevent it from happening?
Ideally, we might also want to declare all our object properties as private, and only allow modifying them with pre-defined setter and getter functions. Using magic methods for this purpose is probably bad in most cases; but, we can still use the __set magic method to prevent adding new, non-existing properties. This can be done by throwing an exception when someone attempts adding a variable to an instance of our object:
public function __set($name, $value) {
throw new \Exception("Adding new properties is not allowed on " . __CLASS__);
}
Of course, a developer might also be aware that we can do this, and therefor decide that it is not worth the risk to use our object as a "container" for their own purposes.
Why use a trait?
If you got a lot of classes that share this, and other "traits", then it makes sense to create a PHP trait, and include it in all the classes that share these characteristics; alternatively we could also use inheritance, but doing so, in this case, is probably not going to be a super effective use of inheritance.
Inheritance is generally going to make code less flexible and portable anyway, and it seems to me like it has few actual uses in the real world. Composition is better. I personally prefer instantiating dependencies in my composition root, and then pass them on through dependency injection to the classes that needs them; this allows me to easily use my classes in other projects, independent from other code that I do not need.
You might argue that a trait "hides" the magic method for the developer, but this is actually intentional, since this particular trait has nothing to do with implementation and more to do with changing a default behavior of PHP.
Tell us what you think: