SitePoint Sponsor

User Tag List

Results 1 to 11 of 11
  1. #1
    SitePoint Addict
    Join Date
    Nov 2005
    Location
    Germany
    Posts
    235
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    __construct vs. setProperty()

    Hello,
    since I'm pretty new to OOP I'd like to have a few comments on these two approaches to a constructor. I have two class properties, which sort of belong together (IDs) and are pretty essential (I cannot imagine any circumstances where they don't need to be set), so I could put them in the parameter list of _construct() (see class BigConstructor). But that would make the parameter list long and ugly. To avoid this I could have a setId() method which would have to be called every time I instantiate the class (CompactConstructor). Not nice either.

    PHP Code:
    <?php
    class BigConstructor {
        
    // ugly ugly ugly parameter list
        
    public function __construct($objectId$catId, \
            & 
    $dbHandlerdbselect $dbAbstract) {
            
    $this->caseId $objectId;
            
    $this->catId $catId;
            
    // ... and some more
        
    }
    }

    class 
    CompactConstructor {
        
    // nice parameter list
        
    public function __construct(& $dbHandlerdbselect $dbAbstract) {
        
    // ...
        
    }
        public function 
    setIds($objectId$catId) {
            
    $this->caseId $objectId;
            
    $this->catId $catId;
        }
    }

    // ready to use!
    $bc = new BigConstructor(...);

    // two steps neccessary to use this!
    $cc = new CompactConstructor(...);
    $cc->setIds(1,1);

    ?>
    Generally: Do you prefer "big" constructors or would you try to keep the constructor's parameter list short by setting (important) properties manually?
    Please let me know how you usually handle this.

    Thanks in advance,
    Christoph

  2. #2
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    The general rule is that if the object can't exist without the properties, they should be injected through the constructor. However, when you have many parameters in the constructor it may be a sign that your object is doning too much, so you may want to refactor. It's not a definitive, and the problem is so complex that it has spawned solutions such as dependency-injection container and service-locator.

    In you particular case - without knowing exactly what the class is supposed to do - I would make a guess that dbHandler and dbselect needn't be injected. Wouldn't it make the class more flexible, if the methods, in which you need theese instances, took them as arguments ? That way, the same object could be used with more than one database.
    Alternatively, if the object is only created within another class, a heaveweight constructor isn't that bad at all. The problem is mostly there, if the user has to craete instances manually all the time.

  3. #3
    SitePoint Guru BerislavLopac's Avatar
    Join Date
    Sep 2004
    Location
    Zagreb, Croatia
    Posts
    830
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    If a single database connection is used throught your application (as is often the case), it might be wise to make it into either a Highlander or Borg (i.e. Singleton or Multistate -- I just love the Python names ).

  4. #4
    SitePoint Addict
    Join Date
    Nov 2005
    Location
    Germany
    Posts
    235
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hello,
    thanks for the input, it's very helpful.

    Quote Originally Posted by kyberfabrikken
    Alternatively, if the object is only created within another class, a heaveweight constructor isn't that bad at all. The problem is mostly there, if the user has to craete instances manually all the time.
    This is a very good point indeed, as it applies to the majority of classes.

    Quote Originally Posted by BerislavLopac
    If a single database connection is used throught your application (as is often the case), it might be wise to make it into either a Highlander or Borg (i.e. Singleton or Multistate -- I just love the Python names ).
    This seems to solve the problem. At least the example could be rewritten with a nice and short constructor parameter list AND easy creation.

    Thanks again,
    Christoph

  5. #5
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by FrlB
    This seems to solve the problem. At least the example could be rewritten with a nice and short constructor parameter list AND easy creation.
    Yes, but Singleton's are globals - Avoid them if possible.
    Don't get me wrong - sometimes it's much easier to simply create a singleton, but changing your design from passing variables (the proper path) to using singletons (the wrong path) is a weakening of your implementation. I often create singletons in the early drafts of my code, but end up refactoring them out again, as the code consolidates.

  6. #6
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    You do? I'm happy enough to use and retain the use of a Singleton, but in saying that I have only ever used it in one place, for creating one instance of a database connection, and no where else.

    Would knowing that now, still inpede the application and it's future development?

  7. #7
    SitePoint Zealot sleepeasy's Avatar
    Join Date
    Sep 2003
    Location
    Bristol, UK
    Posts
    145
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I have a rule that all methods I write have no more than two parameters. In some cases I allow an optional third parameter, but this is usually removed later after refactoring.

    If you find you have a method with a long list of parameters try to think about what those parameters are for, where they're coming from, etc.

    For instance, in my opinion - and I'm obviously going to have to make some wild assumptions about the responsibility of your class because the purpose of all your parameters isn't clearly stated - I would reduce the number of of parameters to 3.

    PHP Code:
    class RefactoredConstructor {
        public function 
    __construct($objectId$catIdStorage_Accessor $storage);
    }

    interface 
    Storage_Accessor {
        public 
    funciton __construct($dbname$dbConnection$dbAdaptor);
        public function 
    getById();
        public function 
    getByCatId();
        public function 
    store(...);

    With this approach you are reducing the complexity of your class. Instead of passing in a load of arguments so that you have to do all the work in your class you delegate some of the responsibility to another class, which you will interface with.

    Kindof Introduce Parameter Object & Preserve Whole Object

    HTH
    Always open to question or ridicule

  8. #8
    Umm. PHP Guru....Naaaah jaswinder_rana's Avatar
    Join Date
    Jul 2004
    Location
    canada
    Posts
    3,193
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    A Question arose from sleepeasy's post,

    I have a user class, which has a register function. Now, i have about 10 fields in register form.

    What is the best method to pass them to function??
    ---------------------------
    Errors = Improved Programming.
    My Site

  9. #9
    SitePoint Zealot sleepeasy's Avatar
    Join Date
    Sep 2003
    Location
    Bristol, UK
    Posts
    145
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I assume that the register() function you have is responsible for inserting a user's details into a database? And it might look something like:

    PHP Code:
    class User {
        
    register($username$email$dob$icq, ...);

    The approach I would take, the approach that makes most sense to me would be to move register() into a seperate class who's sole responsibility would be to retrive, insert or query users.

    Use the user class just to store user properties. Instantiate a user and then populate it's properties either directly or via "setter" methods.

    You would then pass this user object to your new class that would be responsible for inserting this new user into the database.

    PHP Code:
    class User_Store {
        public function 
    store(User $user) {
            
    // ...
        
    }
    }

    // just for illustration

    $newUser = new User();
    $newUser->setName($_POST['name']);
    $newUser->setEmail($_POST['email']);

    $userStore User_Store::getInstance();
    $userStore->insert($newUser); 
    If you're wondering why you should do this, then think about what would happen if you decided to change the registration details that you gather from new registrants - i.e. if you change what user details you store. You would have to change the method signature of your register() function.

    This may not seem like a big deal but when you start dealing with optional parameters things start to get messy. Forms often contain data that is optional.

    The worse case scenario is that you add an optional parameter, and then decide to add another parameter which is not optional which will alter the order of the parameters, requiring all code to adapt to these changes.

    You would also need to modify the body of the register() function.

    Using my approach (in PHP5) you would only need to modify the body of the User_Store::store() method.

    However, what I forgot to mention in my previous post is that a lot of this comes down to how you feel about functions with lots of parameters.

    HTH
    Always open to question or ridicule

  10. #10
    Umm. PHP Guru....Naaaah jaswinder_rana's Avatar
    Join Date
    Jul 2004
    Location
    canada
    Posts
    3,193
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks, that answers many question.

    the technique when i couldn't think of anything, i used, was

    i just passed ($_POST) to a validate function in register class. and it would return 1 or 0 on validatation (checking required filed), and then if one, then pass then call the register function.
    i dint pass anything to register function, because while using that validate class, it sets class variables, and register class uses those values.

    But, your method makes more sense.

    thanks
    ---------------------------
    Errors = Improved Programming.
    My Site

  11. #11
    SitePoint Addict
    Join Date
    Nov 2005
    Location
    Germany
    Posts
    235
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by sleepeasy
    I have a rule that all methods I write have no more than two parameters. In some cases I allow an optional third parameter, but this is usually removed later after refactoring.
    This is what I had in mind, when I wrote about a long parameter list as "ugly". I usually try to keep it that way, but still kyberfabrikken has a point saying
    Quote Originally Posted by kyberfabrikken
    [...] if the object is only created within another class, a heaveweight constructor isn't that bad at all.
    Quote Originally Posted by sleepeasy
    For instance, in my opinion - and I'm obviously going to have to make some wild assumptions about the responsibility of your class because the purpose of all your parameters isn't clearly stated - I would reduce the number of of parameters to 3.
    Your assumptions however wild they might be lead to another pretty nice solution. I will think about my class structure and how they share jobs.

    Anyway, as a newbie in this forum I really appreciate all your ideas,
    Christoph


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •