Improvisation is the name of the game, and we tend to do a lot of it with plugins and themes. In that process we tend to modify functions by adding more variables to incorporate changes in them. However, unlike most of the other languages, PHP allows users to set default values for variables passed to a method too.
As a developer when you start out coding, you have a certain number of things a function will require in order for it to work, some may be optional too, so you set out to create a method signature similar to the one below.
function do_something($var1, $var2, $var3, $var4 = false, $var5 = '') {
//process business logic here
}
Now, say you release your plugin or theme and get more feedback on features and other improvements. If the features or improvements suggested require you to change the method signature to incorporate new variables and you use default values, you are in a bit of a spot.
So what is the best way to avoid such situations? In my opinion, if you use a function which accepts variables, it could easily scale to accept more parameters without breaking anything by accepting an array as a single parameter. The array would have to be built up either internally in the code somewhere or externally through the user.
So you could rewrite the above logic as below:
function do_something($args = array()) {
$myvar = (array_key_exists('mykey', $args)) ? $args['mykey'] : get_default_value('mykey');
//process business logic here
}
Now, you would not expect a user to pass an array while using your non-widget based plugin in their themes, so you would have to provide users with an options page which will allow them to set the values they want to be passed to the function, and then build a Facade function internally which will then read all the option values and pass it on to the main function to be processed.
I hear people saying that they can fetch the options from WordPress inside the function itself and there is not need for this Facade, however, in my experience of over 11 years in the software industry, I have learnt one important thing, never mix anything with business logic.
If a function is supposed to perform a task, let it perform only that and nothing else, that way you can reuse the function elsewhere without having to constantly rewrite it to adapt to different things.
I have seen several plugins which make use of arrays and several which do not. I would definitely be interested to learn on how you approach this, the comments form is open.
Update: From the comments below, many users mistook me. I never said that users cannot use wp_parse_args. However, being an OOPS developer, I stick with my above post and say that you should keep business logic separate from processing logic, no matter whether it is WordPress or any other platform, that is the basic fundamental I learnt in OOPS, and I do believe OOPS is the best fundamental and way to go forward. I expect arguments on that.
I do it how WordPress does it, using wp_parse_args():
functiom my_template_tag($args = ”) {
$args = wp_parse_args($args, array(
‘foo’ => ‘default_value_1’,
‘bar’ => ‘some other default value’
);
// rest of the code
}
META:
Why are tags stripped?
Maybe use a plugin like WP-Syntax ?
I generally only use this approach for functions that need more than one or two vars.
When in WordPress, I use wp_parse_args.
When not in WordPress, I use
if (is_string($args)) {
parse_str($args, $newargs);
$args = $newargs;
}
This lets me deal with the query string style of arguments too, which is handy for messing with URL stuff.
Yeah scribu and Otto are doing it how I do it. wp_parse_args() in WordPress, and parse_str() anywhere else. Very easy. Might even be worth updating the article to mention wp_parse_args().
@scribu and @Otto I agree that wp_parse_args both make the parsing of defaults and passed values easier, but I still think it breaks the business logic.
Say you have three apps which use the same code how would you pass the default value to it? Comparing is the best way, but still my approach was a bit outside WordPress as well as to creating some OOPS in the way people code within WordPress too which is why I highlighted Facade in the first place.
Well, if you have 3 softwares that use the same code, default value should be inside that code…
I understand what’s you’re proposing here. WordPress is seen as a framework, and wp_parse_args is not available outside it.
If WordPress is not a requirement, then your idea is the best I know. But when a framework is available, let’s use what it offers to make our development easier and faster 😀
Well with WordPress to have you ever heard about creating a Misc class which do a single set of functions which can be reused?
Yes, it’s called HkTools and I’m just starting to add it to my plugins ATM 😀
I should have done it before, but I didn’t have enough tools and codes to justify it. Once I learned a way to automate admin page generations, I decided to do it right and move everything that was lost among my plugins and get everything together to centralize their maintenance.
Talking about it, do you have any idea on how to deal with the same class in more than 1 plugin, and manage different versions of it?
For avoiding conflicts I’m thinking on trying something based on class_exists(). But to force the newest version to be used I have no idea yet.
That’s interesting, because I just started into the same process, using Godley’s Redirection base class.
I’d like to make certain base class functions like deactivate process an array of callbacks, which are registered as interface implementations of the base class. Or something like that. I know how to do this in java, c, c++, still haven’t _quite_ come to grips with scope/syntax of php.
And of course, other stuff.
Like pulling in stateless controller functions with includes.
I’m sure I’m making a hash of it, but I tend to clean things up as I go, learn faster in the long run that way.
Yes, but this isn’t the same thing as a “Facade”, really. A Facade is a library simplifier, not merely a wrapper that defines default values.
Okay, sure, it *can* be that, but generally a Facade is so named because it combines several steps into one. For example, if I had a sockets library, then getting a webpage would be a matter of opening the socket, making the http request, getting the data, closing the socket, etc. A Facade would abstract those steps down into one function call.
wp_parse_args is really the best solution.
With it we can deal at once with a large amount of parameters, default values being merged with passed ones, and also parameters can be passed as string instead of array.
With it, small number of parameters don’t require creating an array to deal with them, and when we use the function we pass only what’s needed.
I agree with not mixing database access with application logic. I like to use a options.php where I define the structure of the options array, set default values and load it from database. This file is loaded as soon as possible from the plugin or theme and deal with everything, storing it on a global variable.
If options is found on database, it’s used, else default values are used. This structure is also used to build options page. Then, anywhere I need these options I just get the global variable and use it.
I’m still improving this design pattern, but I’m willing to use it on all my plugins, it’s very DRY and easy to use once it’s finished.
way beyond my scope of understanding. lol
I still don’t understand how to pass information from one PHP file to another. lol and OOP totally confuses me, I don’t understand the difference between classes and regular variable / arrays *shrugs* I know what variables are and I know what arrays are, but I don’t really understand how classes are different then just a regular array of memory variables.
probably why I’m not a plugin author. rofl
Everybody pass for this period during learning. OOP is something hard to didacticly learn, only with experience we’ll face situations where OOP is useful. And once we understand its usefulness, we’ll never want to develop without it anymore 😀
To have variables among different files, search for the global keyword.
In general, when engineering software, you want to be explicit regarding your interface design. The more specific you can be with your APIs, the better. Consumers of a given API need to have a clear understanding of what the essence of the data contract is, and part of that is having a fixed set of parameters to the black box that is a 3rd party code element.
I would only recommend replacing a fixed set of variables with an array for code which meets a very limited set of criteria, among them:
1. Code you don’t expect or want to share with anyone else.
2. Code where the array argument is being used to store variable-length information, e.g., logging or printing or formatting an arbitrary number of data elements into another format.
@Joe I totally agree with that but not entirely.
Nevertheless, I have to add one thing here, no matter whether you decide to pass variables or an array, whatever variables will be processed will be in the business logic, it does not matter whether you pass additional values through the array there as it will not be accounted for.
In the end if your business logic cares about certain values, it really does not matter how you pass those to it.
I’d add another situation, when you have a handful amount of variables being passed (exemple: tag clouds related functions), and most of them have a default value.
Remember their order is a headache, and if you wanna set a value in the end of the parameters list you’ll have to set default ones of all before it.
Another aggravant is that PHP doesn’t explicitly define data types. For Java, I’d better use DTO/bean design pattern, having objects storing data among the software. But PHP is much more simple than Java, and also PHP’s array lets us use strings to index arrays.
So an array is more readable and easy to deal than a bunch of separated variables, and beans doesn’t have much advantage over it if we don’t wanna protect some variable using getters and setters.
And if wp_parse_args is not available… just implement a simpler version of it, that receives 2 arrays, compares them and returns the result.
It’s more of a language discussion than a design pattern discussion. I’d never use PHP if I didn’t have a CMS below supporting me.
So much problems because PHP doesn’t support function/method overrides. Which is the reason the stupid default value in arguments is used in the first place. Its really stupid to have to set an argument to the default value just because you want to change the arguments that comes after it.
You don’t have to do it that way. PHP supports variable length argument lists. See http://www.php.net/manual/en/f.....t-args.php .
I really think this is depends on the programmer and the situation, I like to pass parameters as variables, however sometimes it is easier to do it with an array, both ways are correct and when used in the right situation are equally effective.
I have recently been using option arrays with Symfony (which has been really convenient) and have changed to do work on a legacy project which is passing values by parameters. Since switching to this legacy project I’ve come across several issues where I have had to define every parameter in a method call just so I can pass in the value of a new parameter.
In this case it has caused me a few headaches and would be much quicker and simpler if an option array had been used as I could simply have passed another option via the array rather than update every call to the method.
I agree that both methods are effective if used in the right situation but my personal preference is that if the method signature is to be more than a couple of parameters then I will tend to use an option array for simplicity. As long as the values for the options array as documented sufficiently then this is often just as easy to read (especially with IDE auto-complete) as method signatures with each parameter explicit defined.
I would say if you’re writing functions that require that many parameters, “you’re doing it wrong”, and you need to re-factor your code.