SitePoint Sponsor

User Tag List

Results 1 to 14 of 14
  1. #1
    SitePoint Enthusiast
    Join Date
    Aug 2003
    Location
    Watford, UK
    Posts
    62
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Arrays as parameters == bad smell. Discuss.

    Hi all,

    A couple of caveats:
    1. my first post, be gentle etc. etc.
    2. I'm fairly new to OOP stuff in general, so please excuse my ignorance

    Recently I've started getting into passing assoc. arrays as parameters to methods - the upside being that it's easy to add new parameters without breaking the interface.

    However, given that this is essentially a method for sneaking in these parameters is it a bad habit to be getting into? I'm rationalising it to myself as 'surely passing arrays isn't that different from passing in objects, and it saves me a bit of overhead as I don't have to create all these extra wrapper classes'.

    But, I don't want to end up finding out why this is a really, really bad idea at a later stage (i.e. when I have to work on the same thing a few months down the line).

    And But, (my english teacher would be horrified) I don't want to overcomplicate things by using OO where it is just extra overhead - after all PHP has all of its nice array functions.

    I appreciate this is a really open-ended question, but I'd be grateful for any advice/insights.

    Thanks, and have a good weekend everyone!

    Cheers,

    Jon

  2. #2
    Thinking about Visual Thinking
    Join Date
    May 2003
    Location
    back in South Africa
    Posts
    378
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Well, ... I'm still learning the ropes too. Nevertheless, imo (as always in life) the decision how to pass arguments to a function/method depends on the design of the application you are coding.

    Quote Originally Posted by JonR
    Recently I've started getting into passing assoc. arrays as parameters to methods - the upside being that it's easy to add new parameters without breaking the interface.
    If you don't mind my question: Isn't that a design flaw? I think that you should try to avoid building a 'god-method' which can handle a lot of situations ... I would rather opt for splitting the 'one' into 'many' dedicated methods, each one doing one thing and doing it well, nothing more and nothing less - high cohesion, which btw can increase the number of methods in a class.

    One situation - where an array is helpful - that I can think of now is, if you have parameters with default values:
    PHP Code:
    function makeACupOfEspresso($cupSize 'single'$amountOfSuger 0$amountOfMilk 0) {
       
       
    // code ...

    If a customer now would like to have a single Espresso with two units of milk, than abviously you must call this function as follows:
    PHP Code:
    $espresso makeACupOfEspresso('single'02); 
    Changing the a.m. function, simplifies the usage:
    PHP Code:
    function makeACupOfEspresso($param = array()) {
       
       
    is_array($param) or die('please check the way you called the function');
       
       isset(
    $param['cupSize']) or $param['cupSize'] = 'single';
       isset(
    $param['amountOfSugar']) or $param['amountOfSugar'] = 0;
       isset(
    $param['amountOfMilk']) or $param['amountOfMilk'] = 0;
       
       if (
    $param['amountOfSugar']) {
          
    $param['amountOfSugar'] = 0;
       } else if (
    $param['amountOfMilk']) {
          
    $param['amountOfMilk'] = 0;
       }
       
       
    // code ...
    }

    $espresso makeACupOfEspresso(array('amountOfMilk' => 2)); 
    Having said this, I would like to stress the point that this way of passing arguments should never be exploited to change the 'interface' of the method - what in fact and imo you are achieving with adding 'new parameters'. The outside appearance remains the same, but the functionality changes (evtl. drammatically) and with it the public API.

    The guideline I follow is: Balance maximizing method cohesion with keeping the number of methods in a class to a manageable level.

    Cheers, Stefano

  3. #3
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Umm.... You are concerned about OO overhead huh ? To be honest there really isn't all that much overhead today with PHP4.2 and above IMO and I know a lot of other member's would proberly agree on this point.

    I would suggest you instead of creating a lot of functions and using arrays to hold various amounts of parameters that you instead put more time towards OO ?

    That way you'll find that passing object references is a lot easier, simpler and more effiecent ?

    That, and you'll add another very important skill to your PHP scripting ability

  4. #4
    Thinking about Visual Thinking
    Join Date
    May 2003
    Location
    back in South Africa
    Posts
    378
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    [quote='Dr Livingston]I would suggest you instead of creating a lot of functions and using arrays to hold various amounts of parameters that you instead put more time towards OO ?

    That way you'll find that passing object references is a lot easier, simpler and more effiecent ?[/quote]

    Yeah ... however, what about the class' methods? If you have some of them accepting (several) arguments (evtl. with default values), would you always convert them into objects or create a separate class for incorporating them into one object? ... [color='red']devil's advocate postion[/color] ... at a certain stage you will have to handle built-in types.

    BTW, I liked the mini rules of lastcraft in OOP Method, good for beginners.

  5. #5
    SitePoint Enthusiast
    Join Date
    Aug 2003
    Location
    Watford, UK
    Posts
    62
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hi Stefano, and Dr Livingston,

    Stefano:

    To answer your question, yes, I agree that this is a design flaw, you got me . It just made it easier to recover from it!
    I guess it'll take a little while longer (maybe the end of next week? ) before my new OO design skills are up to scratch.

    One thing that worries me slightly about the high-cohesion, lots of methods angle is the potential for duplicating code. But then maybe this is just because my methods are too long! I'm going to have to get a refactoring book.

    The other thing, as you already pointed out, if the number of methods in a class is too high this is going to be just as bad as having a lot of GOTOs. Oh, right, so this one calls that one, which calls that one...

    Your espresso example where using an array simplifies usage is a good one. I've been going wrong by extending this and using the presence or not of array values as conditionals in my methods. My muddy original post implied that I could maybe just swap the arrays for new objects but I guess this is just going to lead to the same set of problems in slightly different context (Note to self: must not consider OO some sort of magic bullet).

    Another valid use(?): when you can't know in advance how many parameters you are going to receive, e.g. when your method does some sort of general form processing.

    Thanks for your views - I think it will do me well to bear your guideline in mind, and you've helped clear my foggy notions a bit.

    Dr Livingston:

    Thanks for the reassurance. I'm always attempting to improve my skills!

    Cheers,

    Jon

  6. #6
    SitePoint Guru
    Join Date
    Nov 2002
    Posts
    841
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Stefano F.

    PHP Code:
    $espresso makeACupOfEspresso('single'02); 
    Changing the a.m. function, simplifies the usage:

    PHP Code:
    $espresso makeACupOfEspresso(array('amountOfMilk' => 2)); 
    I don't see the second usage as simpler.

  7. #7
    Thinking about Visual Thinking
    Join Date
    May 2003
    Location
    back in South Africa
    Posts
    378
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Selkirk
    I don't see the second usage as simpler.
    I agree to the fact that it's more typing. On the other hand consider the following:
    • with the first version you must be aware of the parameters, i.e was the second argument the amount of milk or sugar? ... admitted, a very simple example, but it gets down to the point
    • with the second version you must exactly know what parameters are available, but the function call is very descriptive and flexible (default values implyed)


    At the end of the day it always boils down to the same conclusion: a matter of personal taste.
    Last edited by Stefano F.; Sep 5, 2003 at 10:20.

  8. #8
    Thinking about Visual Thinking
    Join Date
    May 2003
    Location
    back in South Africa
    Posts
    378
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by JonR
    Another valid use(?): when you can't know in advance how many parameters you are going to receive, e.g. when your method does some sort of general form processing.
    My feeling in this respect is that if - in a normal situation - you don't know how many parameters the method will receive, 'something' is not well designed. Just a feeling.

    Quote Originally Posted by JonR
    I'm going to have to get a refactoring book.
    That's what I must definitively do too!

    Quote Originally Posted by JonR
    Thanks for your views - I think it will do me well to bear your guideline in mind, and you've helped clear my foggy notions a bit.
    Glad to hear that, it was a pleasure.

  9. #9
    Thinking about Visual Thinking
    Join Date
    May 2003
    Location
    back in South Africa
    Posts
    378
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Just remembered that I have seen a draft re Refactoring To Patterns. Perhaps a good start? Will read that as first ...

  10. #10
    SitePoint Guru
    Join Date
    Nov 2002
    Posts
    841
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Stefano F.
    I agree to the fact that it's more typing. On the other hand consider twith the second version you must exactly know what parameters are available, but the function call is very descriptive and flexible (default values implyed)
    I think that people coming from a Perl background are prone to this usage. I don't care for it in PHP because it doesn't really match the "standard" style of handling parameters. Other languages, such as Objective C and Smalltalk support this as part of the language. Here is an example objective C call:

    Code:
    [myRect setWidth:10.0 height:15.0];
    PHP Equivelent:
    PHP Code:
    $myRect->SetWidthAndHeight(1015); 
    In the PHP example, the method name is SetWidthAndHeight. In the Objective C example, the method name (selector) is setWidth:height: (The colons are a part of the method name).



    When a method does two different things depending on the value of a parameter, sometimes it indicates that it should really be two different methods.

    Also, NEVER NEVER require boolean parameters.

    Bad:
    PHP Code:
    function import($valuelist$append=FALSE) {
        if (
    $append) {
            
    $this->vars += $valuelist;
        } else {
            
    $this->vars $valuelist;          
        }
    }
    ...
    $obj->import($valuesTRUE); // Too hard to figure out what TRUE means 
    Better:
    PHP Code:
    define('REPLACE'1);
    define('APPEND'2);

    function 
    import($valuelist$mode=REPLACE) {
        if (
    $mode == APPEND) {
            
    $this->vars += $valuelist;
        } else {
            
    $this->vars $valuelist;          
        }
    }
    ...
    $obj->import($valuesAPPEND); 
    Best:

    PHP Code:
    function replace($valuelist) {
        
    $this->vars $valuelist;
    }

    function 
    append($valuelist) {
        
    $this->vars += $valuelist;
    }
    ...
    $obj->append($values); 
    Its a good idea to always use defined constants instead of boolean parameters. Then its sometimes a good idea to see if you can fold the constant parameters into the method name and break up the method.

    Regarding multiple parameters with defaults, I try to structure the method so that only the last parameter needs a default. If you have a horde of parameters with defaults, then perhaps that indicates the method does too much. A method should do one thing and one thing only.

    PHP 4 provides functions for dealing with methods with variable numbers of parameters without using arrays.

    One problem with arrays is that it is less efficient to bundle the values into arrays and then unpackaged them inside the function -- Uses extra memory and causes extra array dereferencing.

    If you have to have alot of parameters to your function, instead of passing them as an array, define an object to hold your parameters and pass it.

    Bad smells in parameter passing:


    I would also recommend reading the refactoring book before reading refactoring to patterns (which builds upon the other book and is unfinished)

  11. #11
    SitePoint Enthusiast
    Join Date
    Aug 2003
    Location
    Watford, UK
    Posts
    62
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks for the link. I'll have a read once I get through the sequoia equivalent that's currently lined up

  12. #12
    SitePoint Enthusiast
    Join Date
    Aug 2003
    Location
    Watford, UK
    Posts
    62
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Ahem, cross-posting.

    Thanks for this. I'm going to need to take some time to grok it in its fullness, but it all seems to make much sense on a first reading. I've got a lot of boolean parameters to think about...

    I can see that my Fowler haunting is going to be following me around for a while yet.

    Mind you, I'm still thinking that there are legitimate uses for arrays as parameters - I've just been working on a searching class that can't know what parameters it will receive w/o a big typing exercise (and hence changes in lots of places if one change)...

  13. #13
    SitePoint Zealot
    Join Date
    Aug 2003
    Location
    Brisbane, QLD
    Posts
    101
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    have you looked at func_get_args()? it allows you to have some sort of method overloading by figuring out how many variables were passed, and is probably prefarable to passing a assoc. array?

  14. #14
    Thinking about Visual Thinking
    Join Date
    May 2003
    Location
    back in South Africa
    Posts
    378
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Selkirk
    I would also recommend reading the refactoring book before reading refactoring to patterns (which builds upon the other book and is unfinished)
    As I said, a draft.

    Thanks for the
    Quote Originally Posted by Selkirk
    Bad smells in parameter passing
    listing ... [time constraint : there's so much to read]

    Quote Originally Posted by Selkirk
    When a method does two different things depending on the value of a parameter, sometimes it indicates that it should really be two different methods.
    I fully agree with you.


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
  •