Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

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?

share|improve this question
    
did u had a chance to look at Traits ? –  Yusubov Aug 30 '13 at 13:22
1  
Well that's not what DRY is about, it is about not duplicating knowledge. You are taking it to literally mean any kind of duplication, like the duplication of letters in a sentence for isntance.. that is crazy –  Esailija Aug 30 '13 at 14:57
1  
Again, macros solve mistyping :P –  Esailija Aug 30 '13 at 15:17
1  
If you have too many classes, then templates/macros are the answer. If you have too many arguments to a single class' constructor, then it may be time to reconsider how you are creating instances of that class instead. –  Darien Aug 30 '13 at 17:05
1  
Concerning macros - it is not as simple as it sounds. The macro has to ask me for the property name, and then create several rows placed correctly at different lines in my code. So they would need to run a script analysing my code with regexes etc. Then I need macros to erase and change those entries. I just feel there must be a better way but I might be wrong. –  Dmitri Zaitsev Aug 31 '13 at 6:41
show 3 more comments

3 Answers

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.

share|improve this answer
    
Thanks, I've checked it but it is not clear to me how to use traits to make the above code more elegant. –  Dmitri Zaitsev Aug 30 '13 at 13:45
    
@DmitriZaitsev Build your boilerplate traits once, re-use them in every class you need them. Here's a set of simple container traits for you to play with: github.com/yrizos/bucket –  Yannis Rizos Aug 30 '13 at 15:37
    
@YannisRizos Looks interesting, but is it supported by PHP 5.3? The desription "PHP 5.3+ (5.4 for the tests, because I'm a moron)" is kind of confusing :) –  Dmitri Zaitsev Aug 31 '13 at 6:23
    
@DmitriZaitsev Ooops! Traits are 5.4+ only, forgot to update the description to the correct version, fixed now. Feel free to ping me in our chatroom here, if you want to go through the code. –  Yannis Rizos Aug 31 '13 at 9:59
add comment

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.

share|improve this answer
add comment

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.

share|improve this answer
    
If you are looking to build the automation yourself, you can use the tokenizer to do it a little more intelligently than regex. –  Adrian Schneider Oct 7 '13 at 23:08
    
Could you please give some details about how to use tokenizer? –  Dmitri Zaitsev Oct 11 '13 at 11:34
    
It's out of scope for a comment, but it splits code into the various syntax tokens (variable, whitespace, keyword, etc.). Based on that, you should be able to intelligently insert code at the correct locations to automate some of the repetition. –  Adrian Schneider Oct 11 '13 at 16:23
    
The PHP manual pages on tokenizer are very sketchy. Do you mean creating a list of tokens and running a PHP script to compile it to a code? –  Dmitri Zaitsev Oct 12 '13 at 12:02
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.