I am working on a PHP code and as it grows getting more and more tired of repeating the same standard pattern again and again and again:
class BolerPlate
{
protected $property1;
protected $property2;
...
public function __construct ($property1, $property2, ...)
{
$this->property1 = $property1;
$this->property2 = $property2;
...
}
}
So I am re-typing here each property name 4 (!) times just to get the standard setup! In each class! It doesn’t look elegant nor DRY to me. And re-typing the same names creates more bug opportunities.
I wonder if there is any more elegant way or best practices to get the same setup with a code easier on the eyes 🙂
EDIT. What I have in mind is some sort of factory method where I can supply the list of properties only once each. Or using variable variables and iterate over all properties?
8
In short: Traits might be the feature that you look for.
A trait is PHP 5.4’s solution to the lack of multiple inheritance in the language and a way to avoid hierarchical inheritance chains. Another way to think of it is that including traits in your classes is a clean way to keep your code dry without breaking good design principles.
An even more simple way to think about it is: Hey, all that boiler plate code that you copied and pasted everywhere but now you want to change something? well replace it with a trait and call it a day.
Here you are examples and good post on this topic.
4
Here is some possible solution to my question inspired by this answer. In its laziest form it looks so:
public function __construct ($propertyArray) {
foreach ($propertyArray as $property) {
$this->$property = $property;
}
}
So you pass all arguments as array and then the code becomes uniform and can be inherited from. You still have to write the list of protected variables manually since the following (sadly) doesn’t work:
foreach ($propertyArray as $property) {
protected $property; // or private $this->property
}
and there seem to be no easy way around :(.
The real problem here, far worse then just few extra lines to type, is the consequence of misprints, that can lead to creation of wrong private properties, whereas correct properties from the array become public against dev’s intention.
The same problem actually affects the original traditional way just as much.
A partial solution is to use the trick inspired by the mentioned answer:
public function __construct ($propertyArray) {
foreach ($propertyArray as $property) {
$prefixedProperty = 'prefix' . ucfirst(strtolower($property));
$this->$prefixedProperty = $property;
}
}
So you hide the property by adding 'prefix'
to its name, so-called security by obscurity :). Now the property is still public in case of misprint but you hope not to hit it so easily. Still not 100% bullet-proof.
Now here is the best solution I came up with:
class BulletProof {
protected $myProperty = '';
public function __construct ($propertyArray) {
foreach ($propertyArray as $property) {
if (! isset($this->$property) ) {
throw new exception("Careful, buddy! You either forgot or mistyped your declaration of $property!";
}
$this->$property = $property;
}
}
}
So if you mistyped or forgot to declare the variable, compiler warns you with exception! To make it work, you have to initialize all your variables with something different from null
, which is not too much of a burden, since they got overwritten by the constructor.
If anyone knows a more elegant way, I’d be happy to learn.
On another note I am grateful to Yannis Rizos for his suggestions in private chat, which involve using magic methods __set
and __get
, still with the consequence that properties become public.
First off, I understand your pain. If you use namespaces, add a use statement and type hint for any class dependency bringing the total to six.
Variable variables or any other hackery may save you some bulk now, but it’s going to hurt you in the long run. Traits assume you are re-using code, which probably isn’t the case, or at least it won’t be every time.
The best thing you can do is minimize dependencies per class and try to keep things from getting out of hand. You can use macros, templates or whatever you want to call them to only type it once per dependency. This helps with keystrokes, but the resulting code will still be repetitive.
Sorry, this is the current state of PHP.
4