btherl Posted November 9, 2006 Share Posted November 9, 2006 I often write my functions like this:[code]function foo($args) { if (array_key_exists('dbh', $args)) $dbh = $args['dbh']; if (array_key_exists('result', $args)) $result = &$args['result']; # pass by reference}[/code]Does anyone else do this? It's great for optional arguments. But it's a little annoying having all that code at the top of every function just to process the arguments. Then again, any decent function will be validating its arguments anyway.But the benefits when you call such a function are clear, especially when it has many optional arguments. No more filling in dummy arguments and trying to remember what order they should be in. Quote Link to comment https://forums.phpfreaks.com/topic/26650-associative-arrays-for-named-arguments/ Share on other sites More sharing options...
SoccerGloves Posted November 25, 2009 Share Posted November 25, 2009 Yes! I do do this, but I don't know if it is a good practice, either. I just started it for a few of my projects, and it seems to be working well, and I love the flexibility and the opportunity to make changes later without re-writing all of your calls to that function, but I don't know if there is something I am missing? I'd like to know what other people think. Quote Link to comment https://forums.phpfreaks.com/topic/26650-associative-arrays-for-named-arguments/#findComment-965486 Share on other sites More sharing options...
SoccerGloves Posted November 25, 2009 Share Posted November 25, 2009 It looks like this post has some good thoughts: http://www.phpfreaks.com/forums/index.php/topic,193227.0.html Anyone else have any cautions or misgivings about using this method? From these two threads, it seems like an alright idea to me. Quote Link to comment https://forums.phpfreaks.com/topic/26650-associative-arrays-for-named-arguments/#findComment-965492 Share on other sites More sharing options...
btherl Posted November 26, 2009 Author Share Posted November 26, 2009 Having used it for a few years now (that original post was from 2006), I think it's great The same idea is very popular in perl too, and perl's syntax is even nicer for it. Thanks for pointing out that other thread. What I do these days is I start functions with simple arguments, and then I switch them to named arguments as needed. Functions that benefit from named arguments typically aren't called in many places, so this works well. If there's a function that IS called from many other places, then I can always add a named argument wrapper for it rather than changing all the places where it's called from. I had to do that once only (and actually that was in Perl, but the same principle applies). Quote Link to comment https://forums.phpfreaks.com/topic/26650-associative-arrays-for-named-arguments/#findComment-965773 Share on other sites More sharing options...
btherl Posted November 26, 2009 Author Share Posted November 26, 2009 As a possible caution, you'll need to make sure whoever is maintaining your code understands how it works, since it's not as standard in php as it is in perl. Quote Link to comment https://forums.phpfreaks.com/topic/26650-associative-arrays-for-named-arguments/#findComment-965776 Share on other sites More sharing options...
SoccerGloves Posted November 27, 2009 Share Posted November 27, 2009 Cool, thanks! I just showed my boss the idea on Tuesday, and he understands it, so I think I will keep using it. Quote Link to comment https://forums.phpfreaks.com/topic/26650-associative-arrays-for-named-arguments/#findComment-966591 Share on other sites More sharing options...
Daniel0 Posted November 27, 2009 Share Posted November 27, 2009 To be honest, I think it's a horrible idea. If you need this to "easily make changes in the future" it's likely because your application isn't very well designed. You should take a look at that instead of trying to circumvent the way the language works. Quote Link to comment https://forums.phpfreaks.com/topic/26650-associative-arrays-for-named-arguments/#findComment-966673 Share on other sites More sharing options...
btherl Posted December 2, 2009 Author Share Posted December 2, 2009 Really? This is pretty standard in perl. Not just because it allows painless addition of new arguments, but because it allows painless passing of just a few from a large selection of possible arguments. DateTime for example. Can you imagine doing that with traditional PHP style arguments? As for the idea of designing the system in its totality before starting the coding, that's just not possible in the business I work. We build the application to spec and then our boss says "Why is it doing X? It should be doing Y instead". So we modify it. Then he says "It shouldn't be doing Y, it should be doing Z". It's a constant cycle of modification that continues until the end of the application's life. We can't blame our boss either, as a lot of these change requests come from customers wanting features Y and Z, not because he gave us the wrong spec. Quote Link to comment https://forums.phpfreaks.com/topic/26650-associative-arrays-for-named-arguments/#findComment-969572 Share on other sites More sharing options...
Wardrop Posted December 2, 2009 Share Posted December 2, 2009 I can't see the benefits of this, all I see is a hindrance. The positives, as you mentioned already, is the emulation of named arguments, but here are some of the negatives to consider... Introduces a non-standard coding practise which will increase the learning curve associated with your code, as well as annoy a reasonably number of people. Emulates something that has been excluded from PHP for a reason (it doesn't follow KISS). Makes it more cumbersome to set default values for parameters. Required parameters have to be enforced by the developer instead of by the Zend engine, which is just further overhead in terms of both performance and coding. Unfortunately, PHP doesn't support a shorthand array syntax like ['value1', 'value2'], so having to use array() for every arguments decreases readability. Doesn't allow for type-hinting of objects and arrays, instead, the developer is required to implement this. That's by no means a complete list either. I only ever use arrays for function arguments when I have a large number of optional parameters, where... testFunc('value1', null, null, null, null, null, true, null, false); ...is just not practical. I always dislike using them even in such scenarios, as it forces me to do a whole lot more in-code checks. Quote Link to comment https://forums.phpfreaks.com/topic/26650-associative-arrays-for-named-arguments/#findComment-969596 Share on other sites More sharing options...
Daniel0 Posted December 2, 2009 Share Posted December 2, 2009 There is also a documentation issue. Quote Link to comment https://forums.phpfreaks.com/topic/26650-associative-arrays-for-named-arguments/#findComment-969613 Share on other sites More sharing options...
Wardrop Posted December 2, 2009 Share Posted December 2, 2009 Yes, documentation can become a problem, especially if there's nothing to document BESIDES all the available array parameters. Quote Link to comment https://forums.phpfreaks.com/topic/26650-associative-arrays-for-named-arguments/#findComment-969633 Share on other sites More sharing options...
btherl Posted December 3, 2009 Author Share Posted December 3, 2009 I only ever use arrays for function arguments when I have a large number of optional parameters, where... So do I. As I mentioned earlier, I start with simple function arguments, and convert to named arguments as needed. What's the documentation issue? Both functions with and without named arguments require documentation. If you were relying on the argument list itself for documentation, then you've already got documentation issues! Now, on to those criticisms: Introduces a non-standard coding practise which will increase the learning curve associated with your code, as well as annoy a reasonably number of people. Yes, this a disadvantage Emulates something that has been excluded from PHP for a reason (it doesn't follow KISS). In the right situation, it does simplify things. The right situation is functions with large number of optional arguments, where the "simple" argument passing method becomes cumbersome Makes it more cumbersome to set default values for parameters. I believe it is simpler to set default values with named argument style in the right situation. Traditional argument passing can be problematic here, as all default values must be to the right of the last required value, giving an artificial constraint on argument ordering. Not to mention that the developer must handle dummy argument values, and the caller must pass the correct dummy value. Required parameters have to be enforced by the developer instead of by the Zend engine, which is just further overhead in terms of both performance and coding. Not an issue in the right situation. A function with many optional arguments will rarely have its performance dominated by argument parsing time. If it does, you can simply use traditional arguments and put up with the inconvenience. Unfortunately, PHP doesn't support a shorthand array syntax like ['value1', 'value2'], so having to use array() for every arguments decreases readability. Yes, this is a disadvantage. An unfortunate design decision for PHP, I would say Perl got this right. Doesn't allow for type-hinting of objects and arrays, instead, the developer is required to implement this. I'm not sure what you mean here My claim: Named arguments are superior to traditional argument passing for some functions, in particular those with more than one or two optional arguments. Quote Link to comment https://forums.phpfreaks.com/topic/26650-associative-arrays-for-named-arguments/#findComment-970188 Share on other sites More sharing options...
trq Posted December 3, 2009 Share Posted December 3, 2009 Doesn't allow for type-hinting of objects and arrays, instead, the developer is required to implement this. I'm not sure what you mean here In php you can define function arguments to be of a certain type. You'll generate exceptions if argument then passed to these functions aren't the correct type. eg; function foo(array $arg) {} Quote Link to comment https://forums.phpfreaks.com/topic/26650-associative-arrays-for-named-arguments/#findComment-970205 Share on other sites More sharing options...
Alex Posted December 3, 2009 Share Posted December 3, 2009 Doesn't allow for type-hinting of objects and arrays, instead, the developer is required to implement this. I'm not sure what you mean here In php you can define function arguments to be of a certain type. You'll generate exceptions if argument then passed to these functions aren't the correct type. eg; function foo(array $arg) {} To be clear this only tests for object types, not for all data types. This works for arrays because well.. arrays are objects of type array. But if you try to do something like: function func(int $arg) { ... } it won't work as you might expect because it's looking for an object of type int, and not the data-type int. Quote Link to comment https://forums.phpfreaks.com/topic/26650-associative-arrays-for-named-arguments/#findComment-970244 Share on other sites More sharing options...
448191 Posted December 3, 2009 Share Posted December 3, 2009 Doesn't allow for type-hinting of objects and arrays, instead, the developer is required to implement this. I'm not sure what you mean here In php you can define function arguments to be of a certain type. You'll generate exceptions if argument then passed to these functions aren't the correct type. eg; function foo(array $arg) {} public function __construct(array $args) { foreach($args as $key => $value) { if(!method_exists($this, '_set' . $key)) { throw new InvalidArgumentException("Unkown attribute '$key'"); } $this->{'set' . $key}($value); } } private function _setBar(Bar $value) { $this->_bar = $value; } As long as you can trust yourself not to set state directly in the constructor.. Could mean more boilerplate code though.. Quote Link to comment https://forums.phpfreaks.com/topic/26650-associative-arrays-for-named-arguments/#findComment-970441 Share on other sites More sharing options...
448191 Posted December 3, 2009 Share Posted December 3, 2009 Btw: http://framework.zend.com/wiki/display/ZFDEV2/Zend+Framework+2.0+Roadmap Quote Link to comment https://forums.phpfreaks.com/topic/26650-associative-arrays-for-named-arguments/#findComment-970443 Share on other sites More sharing options...
Wardrop Posted December 3, 2009 Share Posted December 3, 2009 So do I. As I mentioned earlier, I start with simple function arguments, and convert to named arguments as needed. I was under the impression you used it regularly for a majority of functions. What's the documentation issue? Both functions with and without named arguments require documentation. If you were relying on the argument list itself for documentation, then you've already got documentation issues! Well, there's two reason I can think of. The first is that documentation becomes an absolute requirement as it's not obvious without going through the actual code, which parameters are available to us. In addition to that, the second issue is that PHPDoc doesn't support this practice, hence you have to dump the list of options in the description portion of the PHPDoc block. As a result of all of this, code hinting in IDE's also becomes less effective. I believe it is simpler to set default values with named argument style in the right situation. Traditional argument passing can be problematic here, as all default values must be to the right of the last required value, giving an artificial constraint on argument ordering. Not to mention that the developer must handle dummy argument values, and the caller must pass the correct dummy value. In the right situation, you sometimes don't have a choice, but I always consider all available options before resorting to arrays for optional named arguments. Handling dummy values is less of a problem with traditional arguments, than with arrays. If I'm using your framework, and only want to set one of possibly 10 more available options, then you, in your code, will have to set a default value on the 10 options I didn't set. I usually use NULL as the default value for optional arguments (setting an optional argument to NULL in PHP, is essentially the same as skipping it). I can then easily use isset() to determine whether the argument has been set or not, and if not, then set a default value. With boolean arguments however, I will usually set a default value in the function declaration just to make it a little clearer. Not an issue in the right situation. A function with many optional arguments will rarely have its performance dominated by argument parsing time. If it does, you can simply use traditional arguments and put up with the inconvenience. Performance isn't the main issue here, but rather the coding overhead. Plus, it's always best to use as many of the native language and parser features whenever you can. In summary, yes, there are situations where it makes sense, but it shouldn't be something you implement just so you can have named arguments in PHP. I normally use arrays for optional arguments when my argument list is already 3 or more arguments long - in other words, when readability is affected. Quote Link to comment https://forums.phpfreaks.com/topic/26650-associative-arrays-for-named-arguments/#findComment-970811 Share on other sites More sharing options...
btherl Posted December 4, 2009 Author Share Posted December 4, 2009 I was under the impression you used it regularly for a majority of functions. No worries, I kinda realized that after writing the post. I agree it's silly to use it on most functions. A lot of code for no benefit. Well, there's two reason I can think of. The first is that documentation becomes an absolute requirement as it's not obvious without going through the actual code, which parameters are available to us. In addition to that, the second issue is that PHPDoc doesn't support this practice, hence you have to dump the list of options in the description portion of the PHPDoc block. As a result of all of this, code hinting in IDE's also becomes less effective. That's a good point. My workplace has never used automated documentation generation methods, so it's not something I'd considered. I also don't use an IDE Unless you consider vim with all the code writing add-ons an IDE. In the right situation, you sometimes don't have a choice, but I always consider all available options before resorting to arrays for optional named arguments. Handling dummy values is less of a problem with traditional arguments, than with arrays. If I'm using your framework, and only want to set one of possibly 10 more available options, then you, in your code, will have to set a default value on the 10 options I didn't set. I usually use NULL as the default value for optional arguments (setting an optional argument to NULL in PHP, is essentially the same as skipping it). I can then easily use isset() to determine whether the argument has been set or not, and if not, then set a default value. With boolean arguments however, I will usually set a default value in the function declaration just to make it a little clearer. Do you mean you have to set default values in the called function for unused arguments? I'm not sure what you mean there. Here is how I see it, where named arguments mean less mess when calling with only some optional arguments set (though more code in the called function): function annoying($userid, $casefold = false, $include_admins = false, $start = 0, $limit = null, $generate_paging_data = false, $glob_globules = false) { # Here goes type checks, range checks, etc etc ... } annoying(123, null, null, null, null, null, true); # We only want to glob the globules. Defaults for other arguments. function nice($args) { $userid = $args['userid']; $limit = $args['limit']; # Allow null as default value ... $glob_globules = isset($args['casefold']) ? true : false; # Convert to boolean. Or we can type check our argument with is_bool() and take action if it isn't # Here goes any further range and type checks not done above. } nice(array( userid => 123, glob_globules => true, )); } Calling nice() looks better than calling annoying() to me, even with the funny looking array() syntax. On the last point, I agree the extra coding is annoying. You can't get around that in perl either, all you've got is slightly nicer calling syntax. Quote Link to comment https://forums.phpfreaks.com/topic/26650-associative-arrays-for-named-arguments/#findComment-970983 Share on other sites More sharing options...
trq Posted December 4, 2009 Share Posted December 4, 2009 Surely though, if a function requires more than two or three arguments that are not optional the function needs to be redesigned? Quote Link to comment https://forums.phpfreaks.com/topic/26650-associative-arrays-for-named-arguments/#findComment-970995 Share on other sites More sharing options...
448191 Posted December 4, 2009 Share Posted December 4, 2009 Agreed, to an extend. Something like a Service Layer may take a lot of arguments, but arguably a specialized configuration object is in order then. <?php abstract class Options { public function __contruct(array $args) { foreach($args as $key => $value) { if(!method_exists($this, 'set' . $key)) { throw new InvalidArgumentException("Unkown attribute '$key'"); } $this->{'_set' . $key}($value); } } } class NiceOptions extends Options { private $_bar; protected function _setBar(Bar $value) { $this->_bar = $value; } public function getBar() { return $this->_bar; } } class Service { public function nice(NiceOptions $config) { //Do stuff } } Quote Link to comment https://forums.phpfreaks.com/topic/26650-associative-arrays-for-named-arguments/#findComment-971073 Share on other sites More sharing options...
trq Posted December 4, 2009 Share Posted December 4, 2009 Agreed, to an extend. Something like a Service Layer may take a lot of arguments, but arguably a specialized configuration object is in order then. Yeah, but I think this topic is based around simple functions. Which obviously, should be just that, simple functions. If your functions really need to operate on that much data that they require more than a handful of arguments they should likely be object os some type instead. Quote Link to comment https://forums.phpfreaks.com/topic/26650-associative-arrays-for-named-arguments/#findComment-971124 Share on other sites More sharing options...
448191 Posted December 4, 2009 Share Posted December 4, 2009 Agreed. It would be cool if PHP supported named arguments as in Python and Smalltalk, but lack thereof is really not large enough an issue with simple interfaces to warrant introducing a lot of pointerplate code. On the other hand, passing arguments as a composite structure to facilitate dependency injection (using a unified constructor) is a good enough reason regardless of the number of arguments. Although arguable not really required for solely that purpose. Quote Link to comment https://forums.phpfreaks.com/topic/26650-associative-arrays-for-named-arguments/#findComment-971148 Share on other sites More sharing options...
448191 Posted December 12, 2009 Share Posted December 12, 2009 I'm preparing for my first 5.3 project, thought I'd share my own little 5.3 options supertype.. <?php namespace kwd\pfnotify\options; use kwd\pfnotify\exceptions; abstract class Options { public function __construct(array $args) { foreach($args as $key => $value) { if(!method_exists($this, 'set' . $key)) { if(!property_exists($this, "_$key")) { throw new exceptions\InvalidArgumentException(exceptions\InvalidArgumentException::INVALID_KEY, $key); } $this->{"_$key"} = $value; continue; } $this->{'set' . $key}($value); } array_walk(get_object_vars($this), function($item, $key) use ($args){ if(!isset($args[substr($key, 1)])) { throw new exceptions\InvalidArgumentException(exceptions\InvalidArgumentException::MISSING_KEY, $key); } }); } public function __call($method, $arguments) { if(!strpos($method, 'get') === 0) { throw new \BadMethodCallException("Method '$method' does not exist"); } $ucProp = substr($method, 3); $property = '_' . strtolower(substr($ucProp, 0, 1)) . substr($ucProp, 1); if(!property_exists($this, $property)) { throw new exceptions\InvalidArgumentException(exceptions\InvalidArgumentException::INVALID_KEY, $property); } return $this->$property; } } You can extend this, define some private props and implement some getters (or not, it'll fetch them anyway). Found my first use for closures as well, albeit a little forced EDIT: btw I notice the post above says pointerplate. That's bogus of course. I meant boilerplate. Quote Link to comment https://forums.phpfreaks.com/topic/26650-associative-arrays-for-named-arguments/#findComment-975993 Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.