Parameter Object vs. Parameter Array vs. Parameter Functions

Not for 'how-to' coding questions but PHP theory instead, this forum is here for those of us who wish to learn about design aspects of programming with PHP.

Moderator: General Moderators

Post Reply
User avatar
Ambush Commander
DevNet Master
Posts: 3698
Joined: Mon Oct 25, 2004 9:29 pm
Location: New Jersey, US

Parameter Object vs. Parameter Array vs. Parameter Functions

Post by Ambush Commander »

A well known design smell is when you've got too many parameters in a function. The usual solution is to put the parameters in a parameter object and pass them to the function. You can also defer setting parameters to later function calls.

Well... I'm using the latter case and it doesn't look very pretty to me. Example:

Code: Select all

HTMLPurifier_ConfigDef::define(
    'Core', 'Encoding', 'UTF-8',
    'Defines the input and output character encodings to use. HTMLPurifier '.
    'internally uses UTF-8, making that the painless default choice. Note '.
    'certain implementations of HTMLPurifier_Lexer are intelligent enough '.
    'automatically detect encoding, however, output format will always be '.
    'this value.  Currently supported values are UTF-8 and '.
    'ISO-8859-1 (ISO8859-1). Encoding names are case sensitive.'
);
HTMLPurifier_ConfigDef::defineAllowedValues(
    'Core', 'Encoding', array('UTF-8', 'ISO-8859-1')
);
HTMLPurifier_ConfigDef::defineValueAlias(
    'Core', 'Encoding', 'ISO8859-1', 'ISO-8859-1');
Those extra parameters, however, are optional and aren't used all the time. What do you think would be a nicer/prettier way to do this sort of thing?
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Re: Parameter Object vs. Parameter Array vs. Parameter Funct

Post by Christopher »

Ambush Commander wrote:A well known design smell is when you've got too many parameters in a function. The usual solution is to put the parameters in a parameter object and pass them to the function. You can also defer setting parameters to later function calls.
The usual solution is to first see if having many parameters is actually a problem. It it actually is a problem there are a number of things you would probably do before resorting to a Parameter Object -- which is more for parameters that you don't have a home for. I would suggest for reducing the parameters to only those actually needed adn/or replacing a parameter with a method as first steps.
(#10850)
User avatar
Ollie Saunders
DevNet Master
Posts: 3179
Joined: Tue May 24, 2005 6:01 pm
Location: UK

Post by Ollie Saunders »

4 is not too many parameters.
User avatar
Ambush Commander
DevNet Master
Posts: 3698
Joined: Mon Oct 25, 2004 9:29 pm
Location: New Jersey, US

Post by Ambush Commander »

4 is not too many parameters.
As of right now, having too many parameters is not too much trouble. The difficulties arise when I start adding more constraints: besides allowed values and value aliases, there could also be allowed types, case sensitivity, allowed setters, etc etc. But then again, eight still isn't that much...
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

I believe these parameters arise from configuration directives in your library? In which case using a parameter object seems like a good idea to me.

I've done similar things myself, though where things may have been intended to be ignored or used in different ways (like your array() to group directives) I may have had simple sub-objects whereby "instanceof" could be used to figure out what do do with the values. I was just making it up as I went along however.

So like:

Code: Select all

HTMLPurifier_ConfigDef::defineAllowedValues(
    'Core', 'Encoding', new DefGroup('UTF-8', 'ISO-8859-1')
);
Hmm... probably getting even messier. You could make factory functions to make that more readable:

Code: Select all

HTMLPurifier_ConfigDef::defineAllowedValues(
    'Core', 'Encoding', DefGroup('UTF-8', 'ISO-8859-1'),
    Comment('This is an instance of "new Comment()" so it can just be ignored.')
);
I understand why you are wanting to use such objects though. How will you be retreiving values from the object? Do you have a helper object to do this or have you built methods into the parameter object class anyway?
User avatar
Ambush Commander
DevNet Master
Posts: 3698
Joined: Mon Oct 25, 2004 9:29 pm
Location: New Jersey, US

Post by Ambush Commander »

The trouble is that I must maintain namespacing, meaning all the parameter objects must have HTMLPurifier_ prefixed. :-P
How will you be retreiving values from the object?
When you create a configuration object, it must be passed a definition object. It then references the values in there to determine whether or not config options are okay.
Do you have a helper object to do this or have you built methods into the parameter object class anyway?
Their built into the object.
User avatar
Ollie Saunders
DevNet Master
Posts: 3179
Joined: Tue May 24, 2005 6:01 pm
Location: UK

Post by Ollie Saunders »

Ambush Commander wrote:The difficulties arise when I start adding more constraints: besides allowed values and value aliases, there could also be allowed types, case sensitivity, allowed setters, etc etc. But then again, eight still isn't that much...
If you are going to have a lot of constraints it makes sense that you will need a lot of code to declare them all and its not duplication so its not really a problem.

What you are doing here seems really cool to me, a very elegant solution, I don't really understand what you are concerned about.
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

ole wrote:What you are doing here seems really cool to me, a very elegant solution, I don't really understand what you are concerned about.
I think it's mostly a combination of aesthetics and user-friendliness. With the level of flexibility to you're aiming at through, I agree that this is an elegant solution.
alex.barylski
DevNet Evangelist
Posts: 6267
Joined: Tue Dec 21, 2004 5:00 pm
Location: Winnipeg

Post by alex.barylski »

d11wtq wrote:
ole wrote:What you are doing here seems really cool to me, a very elegant solution, I don't really understand what you are concerned about.
I think it's mostly a combination of aesthetics and user-friendliness. With the level of flexibility to you're aiming at through, I agree that this is an elegant solution.
Again...this is an example of when computer science becomes a computer art :P

What an interesting field we all work in :)
User avatar
Ambush Commander
DevNet Master
Posts: 3698
Joined: Mon Oct 25, 2004 9:29 pm
Location: New Jersey, US

Post by Ambush Commander »

Well, if anyone's interested in how things turned out, I ended up not changing the external interface.. too much.

Code: Select all

HTMLPurifier_ConfigDef::define(
    'Core', 'Encoding', 'utf-8', 'istring',
    'Defines the input and output character encodings to use. HTMLPurifier '.
    'internally uses UTF-8, making that the painless default choice. Note '.
    'certain implementations of HTMLPurifier_Lexer are intelligent enough '.
    'automatically detect encoding, however, output format will always be '.
    'this value.'
);
HTMLPurifier_ConfigDef::defineAllowedValues(
    'Core', 'Encoding', array(
        'utf-8',
        'iso-8859-1'
    )
);
HTMLPurifier_ConfigDef::defineValueAliases(
    'Core', 'Encoding', array(
        'iso8859-1' => 'iso-8859-1'
    )
);
We've got an extra type variable, in this case it's istring, or case-insensitive string.

The internals, however, were totally revamped.

The code is here:
http://hp.jpsband.org/svnroot/htmlpurif ... figDef.php
http://hp.jpsband.org/svnroot/htmlpurif ... Config.php

Still don't have documentation generating code yet, going to work on that next.
Post Reply