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'm evaluating my current PHP practices in an effort to write more testable code. Generally speaking, I'm fishing for opinions on what types of actions belong in the constructor. Should I limit things to dependency injection? If I do have some data to populate, should that happen via a factory rather than as constructor arguments? (Here, I'm thinking about my User class that takes a user ID and populates user data from the database during construction, which obviously needs to change in some way.)

I've heard it said that "initialization" methods are bad, but I'm sure that depends on what exactly is being done during initialization.

At the risk of getting too specific, I'll also piggyback a more detailed example onto my question.

For a previous project, I built a FormField class (which handled field value setting, validation, and output as HTML) and a Model class to contain these fields and do a bit of magic to ease working with fields. FormField had some prebuilt subclasses, e.g. FormText (<input type="text">) and FormSelect (<select>). Model would be subclassed so that a specific implementation (say, a Widget) had its own fields, such as a name and date of manufacture:

class Widget extends Model {
    public function __construct( $data = null ) {
        $this->name = new FormField('length=20&label=Name:');
        $this->manufactured = new FormDate;

        parent::__construct( $data ); // set above fields using incoming array
    }
}

Now, this does violate some rules that I have read, such as "avoid new in the constructor," but to my eyes this does not seem untestable. These are properties of the object, not some black box data generator reading from an external source. Unit tests would progressively build up to any test of Widget-specific functionality, so I could be confident that the underlying FormFields were working correctly during the Widget test.

In theory I could provide the Model with a FieldFactory() which could supply custom field objects, but I don't believe I would gain anything from this approach. Is this a poor assumption?

share|improve this question

1 Answer 1

Several of the 'rules' you're hearing about using Factories are to assist in making the code more easily modified in the future, not about making it testable now. Take a look at the parameters that you are sending to the FormField constructor: 'length=20&label=Name:'.

That argument is now effectively 'hard-coded', & 'client-side'.

This means that if you have 10 other widgets, each of those 10 would duplicate that 'new'. If you later decide that you want to change the label from 'Name' to something else, or to increase the length to 25, you have to go back and change the code in 10 places, miss 1 and you have a bug which could show up as a weird layout issue.

Using a factory to call that new, allows those 10 calls to all call one factory method, and in the case I just described only the factory method would need to change.

share|improve this answer
    
Doesn't seem to fit that example exactly (Widget may have a 25 character name, other names may be a different length) but I can see how factories would apply to other objects. Maybe the User class would accept other objects as part of DI, with a User::get_by_id() factory that would automate injecting the database interface, perform $user->load() with the passed id, and return the generated object. –  Annika Backstrom Jan 1 '11 at 21:24
    
I was going to make the answer more complicated with a domain example, and decided against it, but seeing as you comment went down that road, here ya go: MVC separation has been best practice for quite a while, and this is an area where they mix (which is bad). When defining Widget, it's better to use a domain specific class (model), and let it call into a presentation specific class in the factory (view). To do that, you abstract the notion of the different 'kind' of boxes without trying them directly to implementations, so you might have the User Widget ask for a User Textbox. –  Neal Tibrewala Jan 2 '11 at 10:31
    
The Factory call then would be to a specific type of box (either UserTextboxFactory, or TextBoxFactory(UserTextBox). This allows the box construction int the presentation layer to be just as OOP and sharing as the User widget in the model, but still separate out how it looks from how it 'works' (like field validation, callback event, etc.) –  Neal Tibrewala Jan 2 '11 at 10:34

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.