PHP - how to avoid overly long if-else blocks
I'm working on a PHP page. The core page has most of the code under one if statement, and the rest of the code under an "else" statement. I'm about to add a third option, "edit" which will make the page yet longer. What is a good strategy to break up the logic into more readable chunks? Subroutines? I've gotten used to OO through Java. Web scripting seems to make it too easy to get 开发者_高级运维into overly long if / else blocks.
classes, functions, includes.
I like to put content modules that occur on more than one page into their own file and just use include_once() statements. For instance you can keep one php file for your page header and just reuse it on multiple pages.
also, make sure to learn about the __autoload function. it automatically loads classes only when needed.
If you can, check out the MVC design pattern.
You should be able to add a controller which you can group your actions under.
You could incorporate routing so a URL like this...
/user/edit
Would call this in PHP (simplified)...
$controller = new User;
$controller->edit();
Of course, you'd need to use variable function names to get that to work dynamically :)
long if-else is inevitable if you comparing multiple set of conditions
you can make use of switch
statement
Or in PHP 5.3, goto
has been introduced (beware of the dinosaur)
Or wrap the conditions inside a function/method
function lots_of_conditions($id, $type, $category)
{
if ($id==1) return 1;
if ($type=='member') return 2;
if ($category=='keyword') return 4;
return 8;
}
$status = lost_of_conditions($id=2, $type='x', $category='y');
switch ($status)
{
case 1: ...; break;
case 2: ...; break;
case 4: ...; break;
default: ...; break;
}
You've got some real design issues to consider. And MVC as suggested by alex is probably a good idea. You should consider what is common between these three cases, and you might find that they're differences can be accounted for with a few variables.
For the meantime, to avoid your spaghetti code, you can put each of these three cases into a function. I don't know if these functions just need to echo something, or need return values, or what, but you should be able to figure that out.
Among other things, you can either have these as functions in the same file (if this 'core' file has a class, consider making these member functions) or put them in a static class elsewhere. I'll show the static option.
class BodyFunctions
{
public static function one() {echo "this is what you now call the 'if' block";} //think of better names for these first two
public static function two() {echo "this is what you now call the 'else' block";}
public static function three() {echo "this is the edit part you want to add";}
}
And to call them from your 'core' page
BodyFunctions::$mode(); //where mode is 'one', 'two', or 'edit'. like the variable your if statements are currently based on
Or you can just add the functions to your core page like this, and call them with call_user_func
function one() {echo "this is what you now call the 'if' block";}
....
call_user_func($mode);
What I wouldn't recommend is putting these functions in a class you need to instantiate even though this class lacks any kind of state and the sole purpose of instantiation is to run the functions inside. Doing tihs unnecessarily is kind of a pet peeve of mine.
I can't stress enough that this should be considered an intermediate measure to avoid the if-else chain or switch situation you've got going on. Look into MVC or a more thorough solution.
Consider that PHP is usually hosted behind some web server that is already using a "Front Controller" pattern - Apache or Lighttpd or similar. If your file logic looks like this:
/dingbat.php
// local page setup, function definitions, etc...
function foo() { ... }
function bar() { ... }
function everything_else_useful_on_this_page() { ... }
print_standard_header($TITLE);
if ($mode == "edit") {
do_edit_lots_of_hairy_logic();
} else if ($mode = "new thing") {
who_knows();
}
else {
print_form();
}
print_standard_footer();
...you can replace it with a set of files that look like this:
/dingbat/common.php
function foo() { ... }
function bar() { ... }
function everything_else_useful_on_this_page() { ... }
/dingbat/edit.php
include "common.php"
print_standard_header($TITLE);
do_edit_lots_of_hairy_logic();
print_standard_footer();
/dingbat/new-thing.php
include "common.php"
print_standard_header($TITLE);
who_knows();
print_standard_footer();
/dingbat/index.php
include "common.php"
print_standard_header($TITLE);
print_form();
print_standard_footer();
There are a ton of benefits to doing this:
- It's less code to write than implementing your own Front Controller.
- It's less code for the PHP runtime to execute than a single page, and therefore faster.
- It scales out to an arbitrary number of possible modes (limited only by your filesystem).
- It is recursive (imagine
/dingbat/edit/easy.php
vs/dingbat/edit/expert.php
, with a private/dingbat/edit/common.php
for shared functionality). - It keeps individual files smaller and therefore easier to "master" by developers.
- It automatically makes URLs more discoverable to both users and search engines (instead of
/dingbat.php?mode=edit&a=1&b=2
you have/dingbat/edit.php?a=1&b=2
- the "variables" are obvious). - If your page is public, it improves SEO and proxy behavior (URL path is far more important than the querystring). ModRewrite can work around SEO issues, but with this scheme it's simply unnecessary.
The downsides?
- You have to change existing URLs (consider replacing the existing
/dingbat.php
with a page that redirects). - The
common.php
files may seem unnatural at first, because it is mostly "page-local logic". This will go away over time. - If the common logic overwhelms the individual page content, then there isn't very much benefit.
Other users have mentioned the MVC pattern, which works in concert with this file-based architecture.
This isn't really an answer, because the question is PHP, but I'm considering converting the whole code base to Rails. I know PHP has MVC frameworks like Cake, but it seems as if RoR has MVC built into it - enforced. Now, how long is it gonna take me to do this when I just wanted to add an edit function?
精彩评论