April 7, 2012

How can I decouple $_POST/$_GET handling code from html forms/urls? (PHP-OOP)

Question by Jonathan

In a class I have a handling method which performs actions based on what post/get variables are available. Here is a simplified example:

public function handleAll(array $vars) {
    if (isset($vars['var1'])) {
        $this->doThisAction($vars['var1']);
    } else if (isset($vars['var2'])) {
        $this->doAnotherAction($vars['var2']);
    }
}

So at runtime the method could be called like this $handler->handleAll($_POST).
The problem is that the variables stored in the $vars array must be named “var1” & “var2” etc. This means that the handling code is coupled with the names of html form elements or get variables in urls (or indeed the keys of any array passed in).

Allowing an array of any variables to be injected makes the method flexible which is necessary as it is also polymorphic. Classes inherit this method and use it to call it’s own actions. A result of this is that it is not obvious from the outside what the handling method requires for it to function. This means that the implementation must be examined to find out what it does (unless I copy the code into the phpdoc which would be silly).

I’m not sure how to get around this. Having enormous if/case statements all exposed on index pages (from multiple classes like these) makes for extremely messy code so it is preferable to have all this encapsulated within a method. Also, it makes sense to have it as a method of the class responsible for calling the actions that manipulate it’s own state (responsibility driven design). I thought about having each variable as a parameter for the method but for some classes the parameter list would be quite large. Also it would mean that many handleAll() methods of different classes cannot be called automatically as all parameters would need to be explicitly injected for each call, removing the polymorphic aspect.

To sum up I need to keep the method polymorphic but I need some way of decoupling the handling code from user input from html forms or urls. In doing this perhaps there is a way of separating the interface from the implementation too. I’m surprised I can’t find any solutions to this already, it seems like it would be a common problem.

Answer by Jani Hartikainen

I’m not sure if what you describe can even be avoided.

If you have code which requires specific arguments to it – be it in the form of an array containing certain values or whatever else – that function will always depend on the arguments being populated correctly.

If I have function foo($a, $b, $c), I will always have to fill the parameters. If they come from POST, then I would need to take them from POST. The same goes even if the function took an array('a' => ..., 'b' => ..., 'c' => ...) instead.

However, if you wanted to decouple your forms from the parameter list, you could use a simple function to transform the POST array into the format expected by one of your handler functions. I do not really see any reason for this though, since why add the extra complexity if you don’t have to?

If you wish to better define what kind of array your handler requires, you could consider having it require an object instead. This approach is sometimes called a parameter object.

The benefits of using a parameter object is that you can easily set up required parameters in the constructor, and use setters for optional ones. Anyone who uses your code can just look at your object’s interface to see what values are required.

If the values your handlers use are actually related to each other, I would consider creating an actual business logic type object. Create it using the data from POST, and move the code which processes the values into a method in the object.

Answer by Starx

Decoupling and automating handling methods, can be painful methods to narrow down too. But there is not so many options, other than, create handlers for eveything. However, I would you like add something. Allow defaults and support variation

function handlePOST() {    }
function handleGET()  {    }
function handleArr()  {    }

Now, these function can hold the variations of the function on their behalf.

Inside however, they is not better way other than to code all the handlers. But switch is shorten them and use separate function for the handling.

switch($_POST['var1']) {
    case "value1": callPostValue1(); break;
    default: callPostDefaultHandler(); break;
}

Author: Nabin Nepal (Starx)

Hello, I am Nabin Nepal and you can call me Starx. This is my blog where write about my life and my involvements. I am a Software Developer, A Cyclist and a Realist. I hope you will find my blog interesting. Follow me on Google+

...

Please fill the form - I will response as fast as I can!