I’ve decided to start a not-so-regular string of blog posts that explore PHP programming techniques that you may or may not know of. I am in no means a perfect PHP programmer, and I’m sure there are heaps of people that are, but this is I guess my way of contributing back to the community.
I’m going to start this not-so-regular string of PHP programming posts by commenting on a technique that is relatively new to me (I’ve known it for a couple of years now, but to be honest the opportunities to use this haven’t been that numerous), but improves programmer usability ie. it makes your life as a PHP programmer just that little bit easier. I call it ‘array parameters’ for lack of a better term.
Basically, it’s just using an array for your parameters in your custom functions, rather than declaring the order of values for your parameter in your function declaration. It’s also handy when trying to do nifty little things like default values for parameters, in which PHP has some shortcomings in.
It’s best to show this by example. Let’s say we have a function that sends an email out to a specific address.
1 2 3 4 5 | function sendMail($toAddress, $fromAddress, $emailMessage, $emailSubject) { // let's just imagine that all inputs have already been sanitized and are safe to use $emailHeaders = "From: " . $fromAddress; return mail($toAddress, $emailSubject, $emailMessage, $emailHeaders); } |
This function can be called via the following simple one-liner:
1 | $sendResult = mail('to@example.com', 'from@example.com', 'This is a test email', 'Test email'); |
Pretty simple, right? We have four parameters, all in a specific order. We can go one step further and specify some defaults:
1 2 3 4 5 | function sendMail($toAddress, $fromAddress, $emailMessage, $emailSubject = "This is the default subject") { // let's just imagine that all inputs have already been sanitized and are safe to use $emailHeaders = "From: " . $fromAddress; return mail($toAddress, $emailSubject, $emailMessage, $emailHeaders); } |
That way, we can do something like the following:
1 | $sendResult = mail('to@example.com', 'from@example.com', 'This is a test email'); // omitted the $emailSubject parameter |
… which will fire off an email with the subject line “This is a default subject”.
This is all well and good, and heaps of PHP code out there in the wild (and behind locked doors) are written in this way. So what’s the big deal?
Let’s imagine that there is a group of PHP developers working on a project. There is a central repository of some shared libraries, and developrs are free to create new functions and add them to the library. One developer has contributed the above sendMail function (let’s say that this developer had embellished a little and turned it into an easy to use HTML email function) and ordered the parameters the way that made most sense to them, but some other people don’t agree and figure that it should follow more closely the order of parameters that the built in PHP mail() function has.
A political shitfight occurs, some sort of consensus has been achieved and the guys that thought differently to the original programmer won; the parameter order gets changed to make life easier. But by that stage, there’s already a whole heap of code that uses the “old” version. So they figure they should make another function instead, called sendMail2()… can you see where I’m getting at here? Some more lateral thought is needed.
Not everyone has the capability of seeing 3 steps ahead, and many times people come back to functions that they have written in the past and adjust them. Add a new feature or two, or try to make things more “usable” when it comes to programming, breaking old code in the process.
Wouldn’t it be great if you could just write a function that takes some sort of special variable, where the order doesn’t matter? That if new functionality is added to the function, it can be done so easily, and without breaking old code?
That’s where array parameters comes in.
Let’s refactor our sendMail() function and use a keyed array as our sole parameter input, as so:
1 2 3 4 5 6 7 8 9 10 11 12 | function sendMail($options) { $emailHeaders = "From: " . $options['fromAddress']; return mail($options['toAddress'], $options['emailSubject'], $options['emailMessage'], $emailHeaders); } // when we call our function, we can do it as so: $sendResult = sendMail(array( 'toAddress' => 'to@example.com', 'fromAddress' => 'from@example.com', 'emailSubject' => 'This is a test email', 'emailMessage' => 'This is the test email content right here' )); |
You can jumble around whatever keyed array elements you like, it doesn’t matter. You don’t need to remember which parameter comes first, as long as it’s in the array, it’ll get picked up.
What if some parameters are missing though? You should have some sort of default values for parameters (read array keys) that might not be in the parameter array when called.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | function sendMail($options) { // we can set the defaults here $defaults = array( 'toAddress' => null, 'fromAddress' => 'default_from@example.com', 'emailSubject' => 'No subject was defined, so here is a default one' ); $options = array_merge($defaults, $options); // copy the $options array over the $defaults $emailHeaders = "From: " . $options['fromAddress']; return mail($options['toAddress'], $options['emailSubject'], $options['emailMessage'], $emailHeaders); } // You can now call sendMail() as such, if you like: $sendResult = sendMail(array( 'toAddress' => 'to@example.com', 'emailMessage' => 'Here is a test email with some default parameters applied' )); |
The array_merge() function will overwrite the $defaults array with whatever has been input. You don’t need to declare everything as an input (I put the ‘toAddress’ key in the defaults and set it to null to demonstrate that you can do this too if you feel more comfortable). The key ’emailMessage’ isn’t declared in the $defaults array, but it is appended to $options when it is merged with it. It works the other way too; if you add functionality to this function and require more parameters, you can add them to the $defaults array and use them as above, without breaking any old code.
So I hope some of you out there have found this PHP coding technique useful. By no means have I discovered or invented this myself; it’s used liberally throughout the CakePHP framework and I have been pretty exposed to that over the past few years. I’m sure many other projects out there use something similar, if not the same. It won’t fix old code that still relies on the old process of itemising each parameter in a function, but if you start right now with this technique, your team (and yourself) will thank you later for it.
I’d be glad to hear your thoughts, and yes I know the code snippets above aren’t styled properly, but I’ll leave that for another day.
Phil Brown says:
This idea has been put forward for all constructors in Zend Framework v2, though I think they use a combination of public setters and `method_exists` based on the array keys.
Still, makes for flexible function / method signatures
December 22, 2010 — 10:16 pm