I have been programming for a number of years now and in PHP for about 4 of those years. I have always wondered what is the best approach when it comes your program deciding what action to take based on a user action.
Let me narrow this down a little bit. I have a small custom built CMS running, one of the pages allows an admin to view and edit user account details such as name, generate a new password, change payment dates and so on.
I have a number of different actions here:
- View all users
- View single user
- View users (search string)
- Edit user
- Edit Subscription
- Edit Name
- Etc
- Delete User
- Blacklist
For all of these actions i provide a let with GET data, for exampele:
<a href="users.php?action=show_user&uid=12">User A</a>
The links for the other things like editing a user would be "action=edit_subscription" for example.
When My page loads i usually use an IF ELSE statement to check if an action is present before doing on.
if($_GET['action'] == "show_user"){
}
else if($_GET['action'] == "edit_subscription"){
}
Once the program matches the action it checks for other data such as UID and then sends that data off into a classes to be processed. Sometimes this can feel a little long winded and can be a little difficult to debug.
I don't know if this is the best way of doing it, i was recently looking into using a switch statement and wondered if this would be better but I'm not sure if it.
So if there a better way for me to achieve this selection process, maybe some sort of pattern that can be used?
Once last point is that i am trying to keep everything in once file (apart from classes) so the HTML and the PHP for matching actions are all in the same .php file, also not 100% sure if this is best practice as well.
Thanks for your time.
3 Answers 3
I recommend looking at the router code in most modern MVC frameworks. The prevailing approach is to use reflection to invoke a particular function named after the action.
Here's the relevant code from Yii:
- https://github.com/yiisoft/yii/blob/master/framework/web/CController.php#L413
- https://github.com/yiisoft/yii/blob/master/framework/web/actions/CInlineAction.php#L45
Or from Laravel:
/**
* Execute an action on the controller.
*
* @param string $method
* @param array $parameters
* @return \Symfony\Component\HttpFoundation\Response
*/
public function callAction($method, $parameters)
{
return call_user_func_array(array($this, $method), $parameters);
}
https://github.com/laravel/framework/blob/5.0/src/Illuminate/Routing/Controller.php#L246
In the Yii example it's looking for a function within the class called action<action name>
and calling it if it exists. For example if you invoked the ViewUsers actions it would call the actionViewUsers()
function. For friendly URLs there's also often a layer above that maps a path to a controller/action combination.
The advantages of this are numerous:
- It avoids massive and unmanageable case or if statements
- It keeps variables limited to the scope of their action function
- The mapping of action -> function is done dynamically so you don't need to maintain a list of these mappings
-
Not even close to how laravel (or other "prevailing") frameworks work. A typical laravel route looks like: Route::get('user/{id}', 'UserController@showProfile'); It's worth looking at the documentation: laravel.com/docs/5.0/routingCerad– Cerad2015年03月28日 01:20:25 +00:00Commented Mar 28, 2015 at 1:20
-
@Cerad defining routes that way is generally just another layer of indirection to map a path to a controller/action combo. If you use implicit controllers they will be invoked in the way I described: laravel.com/docs/4.2/controllers#implicit-controllers My specific example using the "action" prefix is Yii specific though, and I've edited my post to clarify.thexacre– thexacre2015年03月28日 01:38:05 +00:00Commented Mar 28, 2015 at 1:38
If you want to get fancy, you could consider a jump table.
Just have an array where the the key is "show_user", "edit_subscription", etc, and the corresponding value is a function to be called. After declaring your array, the actual code is just a single statement to call the function.
I don't have a PHP IDE at the moment, to code it for you, but you can base on the C example.
From memory, something like
$func = myArray[$_GET['action']];
$func();
-
1You don't need a lookup table, most MVC frameworks have a dynamic association between action name and function name.thexacre– thexacre2015年03月27日 12:47:07 +00:00Commented Mar 27, 2015 at 12:47
-
Hardly worth the downvote though, was it? I just expected a lot of if vs switch discussion & thought I'd throw in a rarely considered alternative. It's certainyl valid & maybe OP, even he doesn't use it now, will have learned something that he can use elsewhere in future.Mawg– Mawg2015年03月27日 12:50:59 +00:00Commented Mar 27, 2015 at 12:50
I think, you are looking for the Routing component for your code. The code I linked is rather individual code library used and provided by Symfony2 framework.
You could inspect approaches it uses to configure and determine routes and controllers for them.