Backend Coder Logo

PHP Script Execution Flow

Published: 9th February 2015

In this post I will describe a method to control PHP script execution flow.

We will implement a state machine.

The state will dictate what step in the decision-making flow that we are at, and makes it easy for us to correlate the state with a flow diagram that we designed, and to output diagnostic data including the current state to a log file.

In PHP, we should use the switch statement and have a state variable that we use in the case statements to track where we are in the flow.

Flow Diagram

The first step is to create the flow diagram that shows the relationship between your states and the events that trigger a transition between the states.

I suggest to set up a Google Drive account and use the drawing tool there to create your flow diagram.

Login flow diagram

Diamonds represent decision branches. Circles are just connecting nodes. Each line (path) will be associated with a state.

We could name our states as follows:

  • START
  • LOGGED-IN
  • LOGGED-OUT
  • RESET_PASSWORD
  • CHECK_PASSWORD
  • PASSWORD-OK
  • BAD-PASSWORD
  • DONE

Ideally I should have made the state names identical to the labels in the flow diagram.

Another technique is to write pseudo code and replace this descriptive code with actual code later. But I think that the diagrammatic approach is better for understanding the exact program flow.

In old school flow diagrams, many different symbols were used and the decision diamonds contained text, yes/no text annotations, and arrows were used with the connector lines.

This extra detail takes up more space and slows down the production of the diagram significantly IMO. I think that now, we want to use tools that are quick and easy to produce results, not work around the tool.

State Machine

Here is the PHP code that implements a state machine.


<?php

$input_data = (object) array(
  'reset' => true,
  'password' => md5('xyz')
);

$logged_in = false; //get_login_status();

$output_data = (object) array('status' => 'ok');

echo "<pre>\n";

$state = 'START';
do {

  switch($state) {
    case 'START':
      if ($logged_in)
      	$state = 'LOGGED-IN';
      else
      	$state = 'LOGGED-OUT';
      break;

    case 'LOGGED-IN':
      $state = 'DONE';
      break;

    case 'LOGGED-OUT':
      if ($input_data->reset)
      	$state = 'RESET';
      else 
      	$state = 'CHECK_PASSWORD';
      break;

    case 'RESET_PASSWORD':
        send_password_reset_link();
        $output_data->status = 'reset';
      	$state = 'DONE';
      break;

    case 'CHECK_PASSWORD':
      if (md5('password') == $input_data->password)
      	$state = 'PASSWORD-OK';
      else
      	$state = 'BAD-PASSWORD';
      break;

    case 'PASSWORD-OK':
      set_login_status(true);
      $state = 'DONE';
      break;

     case 'BAD-PASSWORD':
      $output_data->status = 'not ok';
      $state = 'DONE';
      break;                      
  }

  log_state($state);

} while('DONE' != $state);

exit(json_encode($output_data));

function log_state($s) {
  echo "$s\n";
}

function send_password_reset_link() {
  echo "Sent password reset link\n";
}

function set_login_status($v) {
  echo "Set login_status to: $v\n";
}

function get_login_status() {
  return false;
}
?>

You can see that a do ... while loop runs until the DONE state is reached. Also, it is easy to add extra states and change the flow.

De-bugging

To debug the code, you can log the states to a file, and log the responses to various combinations of input data. The expected results should mirror what was planned in the flow diagram.