Some time ago someone here advised me to move my script's action parsing away from using $_REQUEST for security reasons. I initially chaffed at the idea. I did however study the reasoning and came across reasons to make the switch. Along the way I picked up an interesting trick.

My controllers are now structured such that post actions are implicitly write oriented actions, and get actions are reads. I'm trying to avoid having an exception. This sorting does however help with form organization. Take a basic login form. Now that I've separated POST and GET out I use the source array as part of the actions name. For example

$_GET['action'] = 'login' sets the system to fetch the login form while
$_POST['action'] = 'login' actually executes the login.

These pairs come up quite a bit and there is an elegance to this that having an actions named 'login' and 'doLogin' respectively lack.

Here's the code block for the curious.

PHP Code:
    /**
     * Search the $_POST array, then the $_GET array for an action to take.
     * If neither is set fall to the default (which must be a $_GET action).
     * $_POST actions require a table to be specified, $_GET actions can
     * set a table if desired, else the system will default to the first table
     * listed for the controller.
     * 
     * @throws RequestException
     */
    
protected function parseAction() {

        
/**
         * $_POST actions. These actions write to the database.
         */
        
if (isset($_POST['action'])) {
            if ( 
array_key_exists($_POST['action'], $this->postActions) && 
                
$this->parseTable($_POST$this->postActions[$_POST['action']]) &&
                
$this->table // POST actions require a table.
            
) {
                
$this->actionType 'post';
                
$this->action $this->postActions[$_POST['action']]['method'];
            } else {
                throw new 
PAMWF_RequestException();
            }
        }
        
/**
         * $_GET actions. These actions read from the database.
         */
        
else if (isset($_GET['action'])) {
            if ( 
array_key_exists($_GET['action'], $this->getActions) && 
                
$this->parseTable($_GET$this->postActions[$_GET['action']])
            ) {
                
$this->actionType 'get';
                
$this->action $this->getActions[$_GET['action']]['method'];    
            } else {
                throw new 
PAMWF_RequestException();
            }
        } 
        
/**
         * The default action - which MUST be one of the $_GET actions.
         */
        
else {
            
$this->action $this->getActions[$this->defaultAction]['method'];
        }
    }
    
    
/**
     * Parse the table for the action. Return true on success or false on fail.
     *
     * @param array $input Get or Post (process same for both)
     * @param array $action The action we are checking for.
     * 
     * @return boolean
     */
    
protected function parseTable$request$action ) {
        
        
/**
         * If neither the action nor the request specifies a table
         * return true but don't set a table. This is the reason
         * the $_POST actions check for a table after calling this
         * function in the code below.
         */
        
if ((!isset($action['tables']) || empty($action['tables'])) && !isset($request['table'])) {
            return 
true;
        } else if (isset(
$action['tables'])) {
            
$actionTables explode(','$action['tables']);            
        } else {
            
$actionTables = array();
        }
    
        
/**
         * If no table was specified but the action only has one table
         * we set that table.
         */
        
if (!isset($request['table']) && count($actionTables) == ) {
            
$this->table array_pop($actionTables);    
        } 
        
/**
         * If a table was specified and is allowed for the action set
         * that table.
         */
        
else if (isset($request['table']) && in_array($request['table'], $actionTables)) {
            
$this->table $request['table'];
        }
        
/**
         * All other situations are invalid.
         */
        
else {
            return 
false;
        }
        
        
/**
         * Now a sanity check to make sure the action is valid for the controller.
         * This error should only happen during coding so we'll use assert.
         */
        
assert(isset($this->tables[$this->table]));
            
        return 
true;
    }