views:

95

answers:

3

I'm working on a humble website with my mediocre, self-taught PHP skills, and the current interface structure is like this:

<?php
  if (A) {
    $output = someFunc(A);
  } else if (B) {
    $output = anotherFunc(B);
  } else if (C) {
    $output = yetAnotherFunc(C);
  } else {
    $output = 'default stuff';
  }
?>
<html template top half>

<?php echo $output; ?>

</html template bottom half>

This worked ok at first, and seemed pretty well organized, but the functionality required has grown by a factor of 10 and it's rapidly turning into an unmaintainable, embarrassing mess and I don't know how to get out of it.

I feel that the functions being called for each situation are fairly well-written and focused, but am at a loss as to how to handle the middle-step between the user and the functions that creates the layout and handles the return.

I have a feeling that MVC is one solution? But I'm having a hard time grasping how to go from here to there...

I apologize for any headaches or unpleasant memories the above code may have prompted. Thank you for your time.

+4  A: 

You seem to have started the way a lot of people do, a big if and/or case statement that continues to grow. All those "if" checks can take time. MVC is definitely a great way to go, but there are so many ways to implement it. I would recommend also looking to the Front Controller design pattern, which is commonly used with MVC.

One way to change how you are doing things is to switch to a defined list of "actions" using an associative array. And change your functions into includes. Then you can have multiple functions, variables and other processing code.

$actions = array(
'A'=>'action1.php',
'B'=>'action2.php',
'C'=>'action3.php',
'default'=>'action_default.php'
);
if ( isset( $actions[ $_GET['action'] ] ) ) {
    include( $actions[ $_GET['action'] ] );
} else {
    include( $actions['default'] );
}

Then your "index" file is just a routing tool, which is pretty much the Front Controller concept.

Brent Baisley
I'm curious why you're using `include` instead of `require`. Is there any reason behind that?
icktoofay
require will issue a fatal error if the file is missing, include a warning.
Brent Baisley
A: 

A general suggestion: Have you had a look at Smarty? I found it to be a fairly useful template engine. It probably requires some learning but it may be worth it in the long run.

maschka
+3  A: 

In any object oriented code, whenever you see a series of if/else or case statements, it's often better handled by an object hierarchy rather than a bunch if if/else/else.

In your particular case, you might instead have 3 different classes for A, B, and C. And just call a single $obj->doit() method. A, B, and C would each have different implementations of the doit() method.

If you want to get out of your rut, I recommend reading a book about design patterns. Here are some examples of design patterns in PHP: http://www.fluffycat.com/PHP-Design-Patterns/

Patterns that may be of particular interest to you for this particular type of problem are:

  • Strategy.
  • Command.
  • Factory.

Descriptions of these patterns with PHP examples are in the above link. I do recommend reading up more about design patterns elsewhere, but that link has PHP examples.

I actually routinely use the 3 of those together to cleanly organize code in situations similar or identical to what you are describing. It works like this: - Strategy. This is like a cookie-cutter or Mad Libs style of thing. You set up the basics involved in performing a function. The user (the programmer using the base class) can override certain things if he needs to, but the basics for doing the work are all in place. Example: we need to perform a business process. Generally that involves starting a transaction, doing the "meat" of the work, then performing cleanup and logging. Seems overkill perhaps to use a Stragegy/cookie-cutter pattern here, but it's often not: you need to remember to do the cleanup even if there was an error or exception thrown in the "meat" of the code. By using the Strategy/cookie-cutter pattern, you can make all that happen with minimal boilerplate/repeated code.

  • Command: Combined with the ideas of the Strategy pattern I mentioned above, you have less boilerplate code in your functions that do the actual work.

  • Factory. You use a factory method to generate the appropriate kind of command for the situation you're faced with.

Those 3 design patterns put together work very well for this kind of situation, and can lead to some very clean code where you never repeat yourself.

maschka below recommended using Smarty, which is a reasonable idea. A better idea, depending on your application, may be to use an MVC framework. If you're committed to the idea of sticking with PHP, then I recommend CakePHP and have had great success with it. It helps you to lay out your code in a very good way and help keep you out of trouble.

Unoti