Some Notes About PHP and MVC

I want to give a better explanation on why the short form echo syntax in PHP annoys me so much.

A lot of people argue that PHP is a template language perfectly designed for injecting variables into themes. WordPress themes definitely are the best implementation of the model-view-controller architecture in PHP. You can see that just by looking at any template you have lying around, or just the example one on the codex. Functions return strings which can be injected into other pieces of strings pretty seamlessly. Even inside “The Loop” it’s still really easy to read what’s going on.

There’s no logic in any of those pages. Variables aren’t being defined and set. There’s no if(){}else{} in there because that’s all dealt with on the controller level, the way it should be. When you mix the view and controller you end up with ugly and unmaintainable code. It’s no longer MVC.

That’s why code like that I mentioned in my ranty blog post -

<td style="padding:0 5px 5px 0;">
 <input name="Gas" type="radio" id="Gas" value="0"  <?=(isset($PropertyDetail->Gas) && $PropertyDetail->Gas=="0")?"checked="checked"":""?> onclick="jQuery('#DivGasContainer').css('display','none');" checked/>No
 <input name="Gas" type="radio" id="Gas" value="1" <?=(isset($PropertyDetail->Gas) && $PropertyDetail->Gas=="1")?"checked="checked"":""?> onclick="jQuery('#DivGasContainer').css('display','block');"/>Yes
</td>

- makes me so angry. This is from a project BEA Solutions has inherited from a developer who doesn’t seem to have thought this through very well. In the code above you can’t set a default “what’s checked if $PropertyDetail->Gas isn’t set?” case without making the ternary operator even more ugly than it currently is.

This project has two folders. One called /front_script/, and one called /front_form/. The controller (and accessing the model) is handled in _script/ whilst the view is handled in form/. (Both are included by index.php, which mod_rewrites every URL.) That’s a pretty decent separation.

But when you’re doing logic – complex ternary logic at that – on the view then you’ve destroyed most the benefits of developing with MVC. Which radio button should be checked needs to be decided in _script/ – the controller – not on the view.

If You Do This, I Hate You

I know you’re trying to do MVC architecture, but you’re doing it wrong and it’s entirely unmaintainable. Longer rant later, possibly.

<td style="padding:0 5px 5px 0;">
 <input name="Gas" type="radio" id="Gas" value="0"  <?=(isset($PropertyDetail->Gas) && $PropertyDetail->Gas=="0")?"checked="checked"":""?> onclick="jQuery('#DivGasContainer').css('display','none');" checked/>No
 <input name="Gas" type="radio" id="Gas" value="1" <?=(isset($PropertyDetail->Gas) && $PropertyDetail->Gas=="1")?"checked="checked"":""?> onclick="jQuery('#DivGasContainer').css('display','block');"/>Yes
</td>

Debugging a blank PHP page

I’m writing this post because I’ve had this problem three times in the past two weeks. Each time it’s soaked up more hours of my life than it should.

The problem is that you load you script and nothing is output. Not even an error to tell you where you’ve gone wrong. This must be a PHP bug, but I guess we’ll just have to live with it for now, and try debug around it.

The weird thing is the error that’s causing the page to be blank might not even be a fatal error. Twice for me it was just a warning, which should definitely not halt the processing of the script.

Without a line number or even which include the error is on it’s pretty hard to find out what the problem is to start fixing it.

Ultimately what I end up doing each time is echoing a string, and on the next line exiting. Put this right after the opening <?php on the first line.

echo "got to here.";
exit;

You should see the string output now. If you don’t it indicates that the hidden error is a fatal error, which will probably mean something to do with the syntax of your code, not the logic an undefined method or some such.

To fix that just carefully look through your code. If you don’t see any obvious problems then unindent everything. Now start indenting again if-by-if (or while-by-while, for-by-for, etc). Hopefully before the end of the file you’ll notice that you’ve had to indent twice, or you have left over braces. Delete or add as appropriate.

If you did see the “got to here.” text though, you can start moving those two lines down line by line. When you stop seeing the text you know the line above is the problem line. If you’re unfortunate enough to get to an include and it stops outputting, you’ll have to go through that too.

Once you’ve found the problem line, start debugging the relevant variables. You’ll likely find the problem there. (90% of all programming errors are variable related.)

The PHP-MySQL programming loop…

Seriously. I hate writing applications that consist entirely of

// get result set with mysql_query
//  check if there are any results
     //  loop through each result
          //  output its data
//  no results?
     //  output message saying so

Once you’ve mastered that you can get hundreds of freelance jobs and securely say you have the prerequisite skills. It’s just so dull after writing it a hundred thousand times. Oh, that and

//  has this form field been set?
     //  yes, update database

That’s everything. I want something more interesting. I expect this is why Rails was made because someone got sick of doing this.

This crashes my Apache. wtf.

This may be wrong, but it shouldn’t cause a system failure. Just saying.

<?php

//  A hard coded list of websites for now
$feeds[] = "http://www.reddit.com/.rss";
$feeds[] = "http://feeds.digg.com/digg/popular.rss";
$feeds[] = "http://feeds.arstechnica.com/arstechnica/index";
$feeds[] = "http://www.engadget.com/rss.xml";
$feeds[] = "http://rss.slashdot.org/Slashdot/slashdot";
$feeds[] = "http://feeds.wired.com/wired/index";
$feeds[] = "http://www.hecklerspray.com/feed";

//  Pick one, and open it
$chosen = rand (0, count ($feeds) - 1);
$feed = file_get_contents ($feeds[$chosen]);

$dom = domxml_open_mem ($feed);
//  Nab all the items
$items = $dom->get_elements_by_tagname ('item');
//  Pick a random node
$chosenNode = rand (0, count ($items) - 1);

//  And get the <link>
$itemLink = $items[$chosenNode]->get_elements_by_tagname ('link');

foreach ($itemLink as $item) {
  echo $item->value ();
}

?>

Command line-like string manipulation

I need to convert this:

--foo -a --foobar="Hey there" --lol=laugh -dw randomtext texttext

Into this:

$switch = array ('-a' => true, '-d' => true, '-w' => true);
$parameter = array ('foo' => true, 'foobar' => "Hey there", 'lol' => "laugh");
$misc_args = array ('randomtext' => true, 'texttext' => true);

At the moment, I’m just exploding at spaces which makes $parameter['foobar'] impossible.

//  Whatever's after the function name are arguements, we'll need those too
$argument = explode (' ', trim (preg_replace("/^".quotemeta ($function_name)."/", '', $_GET['r'])));

//  These need to exist
$parameter = array ();
$misc_args = array ();
$switch = array ();

//  If the first array element is empty, they're all empty so remove the array # This is caused by a weird bug, wherein the explode always finds space to explode...
if (empty ($argument[0])) unset ($argument); else {
  //  Look at each argument
  foreach ($argument as $arg) {
    //  Now we need to work out which switches and arguements were included, there are two possible ones: --, and -
    if ($arg[0] == $arg[1] && $arg[1] == "-") {
      //  This could be in the format simply "--hello" or "--hello=weclome", we need to find out which
      if (strpos ($arg, '=') === FALSE) {
        //  Just the simple version
        $parameter[trim ($arg, '-')] = TRUE;
      } else {
        //  Split up the parameter and the value
        $arr_arg = explode ('=', trim ($arg, '-'));
        $parameter[$arr_arg[0]] = $arr_arg[1];
      }
    } elseif ($arg[0] == "-") {
      //  Go through each letter, and add it to the switch array
      for ($x = 1; $x < strlen ($arg); $x++) $switch["-".$arg[$x]] = TRUE;
    } else {
      //  This is just any other random junk
      $misc_args[] = $arg;
    }
  }
}

I haven’t got time to check this out at the moment, but here’s a possible solution I got:

14:15 preg_replace(‘/((?(?=^).*?#OQ#|G)(?:(?!#CQ#).)*?)s+/g’, ‘$1#SP#’, $text)
14:16 though, it would probably be better to split it into two statements. One to
find all #OQ#..#CQ#, another to replace s+ with #SP#.
14:19 preg_replace(‘/(?< =#OQ#)(.*?)(?=#CQ#)/ge’,
‘preg_replace(‘/s+/’,'#SP#’,'$1′)’, $text) or something…
14:23 maybe move the second preg_replace into a function