Should my PHP functions accept an array of arguments or should I explicitly request arguments?
In a PHP web application I'm working on, I see functions defined in two possible ways.
Approach 1:
function myfunc($arg1, $arg2, $arg3)
Approach 2:
// where $array_params has the structure array('arg1'=>$val1, 'arg2'=>$val2, 'arg3'=>$val3)
function myfunc($ar开发者_运维百科ray_params)
When should I use one approach over another? It seems that if system requirements keep changing, and therefore the number of arguments for myfunc keep changing, approach 1 may require a lot of maintenance.
If the system is changing so often that using an indexed array is the best solution, I'd say this is the least of your worries. :-)
In general functions/methods shouldn't take too many arguments (5 plus or minus 2 being the maximum) and I'd say that you should stick to using named (and ideally type hinted) arguments. (An indexed array of arguments only really makes sense if there's a large quantity of optional data - a good example being configuration information.)
As @Pekka says, passing an array of arguments is also liable to be a pain to document and therefore for other people/yourself in 'n' months to maintain.
Update-ette...
Incidentally, the oft mentioned book Code Complete examines such issues in quite a bit of detail - it's a great tome which I'd highly recommend.
Using a params array (a surrogate for what is called "named arguments" in other languages") is great - I like to use it myself - but it has a pretty big downside: Arguments are not documentable using standard phpDoc notation that way, and consequently, your IDE won't be able to give you hints when you type in the name of a function or method.
I find using an optional array of arguments to be useful when I want to override a set of defaults in the function. It might be useful when constructing an object that has a lot of different configuration options or is just a dumb container for information. This is something I picked up mostly from the Ruby world.
An example might be if I want to configure a container for a video in my web page:
function buildVideoPlayer($file, $options = array())
{
$defaults = array(
'showAds' => true,
'allowFullScreen' = true,
'showPlaybar' = true
);
$config = array_merge($defaults, $options);
if ($config['showAds']) { .. }
}
$this->buildVideoPlayer($url, array('showAds' => false));
Notice that the initial value of $options is an empty array, so providing it at all is optional.
Also, with this method we know that $options will always be an array, and we know those keys have defaults so we don't constantly need to check is_array()
or isset()
when referencing the argument.
with the first approach you are forcing the users of your function to provide all the parameters needed. the second way you cannot be sure that you got all you need. I would prefer the first approach.
If the parameters you're passing in can be grouped together logically you could think about using a parameter object (Refactoring, Martin Fowler, p295), that way if you need to add more parameters you can just add more fields to your parameter class and it won't break existing methods.
There are pros and cons to each way.
If it's a simple function that is unlikely to change, and only has a few arguments, then I would state them explicitly.
If the function has a large number of arguments, or is likely to change a lot in the future, then I would pass an array of arguments with keys, and use that. This also becomes helpful if you have function where you only need to pass some of the arguments often.
An example of when I would choose an array over arguments, for an example, would be if I had a function that created a form field. possible arguments I may want:
- Type
- Value
- class
- ID
- style
- options
- is_required
and I may only need to pass a few of these. for example, if a field is type = text, I don't need options. I may not always need a class or a default value. This way It is easier to pass in several combinations of arguments, without having a function signature with a ton arguments and passing null all the time. Also, when HTML 5 becomes standard many many years from now, I may want to add additional possible arguments, such as turning auto-complete on or off.
I know this is an old post, but I want to share my approach. If the variables are logically connected in a type, you can group them in a class, and pass an object of them to the function. for example:
class user{
public $id;
public $name;
public $address;
...
}
and call:
$user = new user();
$user->id = ...
...
callFunctions($user);
If a new parameter is needed you can just add it in the class and the the function signature doesn't need to change.
精彩评论