SyntaxHighlighter

Thursday, 14 July 2011

Favourite PHP/Javascript Functions - switchAssign()

In this series of articles I describe simple, elegant functions from my own personal library that have proven useful to me over the course of many projects.


The switchAssign() functions make my list of favourites because they are elegant, concise, and make code more readable.

Have you ever written code similar to this?

switch ($carManufacturerName)
{
 case 'ford'      : $bestSellingCarModelName = 'falcon'   ; break;
 case 'holden'    : $bestSellingCarModelName = 'commodore'; break;
 case 'mitsubishi': $bestSellingCarModelName = 'lancer'   ; break;
 case 'toyota'    : $bestSellingCarModelName = 'corolla'  ; break;
 default          : throw new Exception("Unknown car manufacturer '$carManufacturerName'.");
}

Or this?

$bestSellingCarModelNameByCarManufacturerName = array
(
   'ford'       => 'falcon'   ,
   'holden'     => 'commodore',
   'mitsubishi' => 'lancer'   ,
   'toyota'     => 'corolla'
);

if (!array_key_exists($carManufacturerName, $bestSellingCarModelByCarManufacturerName))
{
   throw new Exception('Unknown car manufacturer '$carManufacturerName'.");
}

$bestSellingCarModelName = $bestSellingCarModelNameByCarManufacturerName[$carManufacturerName];

The first alternative is compact, but repeats the words 'case' and 'break' and the name of the variable to be assigned for each case.

The second alternative is less text-heavy, but also less encapsulated. It works well when enclosed in a function, but when used on the fly this method clutters code, since it requires three blocks of code to accomplish the single task of assigning a value to a variable.

Often code of this sort is only required once, and in such cases wrapping the assignment code in its own function adds unnecessarily to the number of functions in the file or class, negatively impacting readability and maintainability.

Instead of the two alternatives described above, I prefer writing

$bestSellingCarModelName = switchAssign
(
   $carManufacturerName, array
   (
      'ford'       => 'falcon'   ,
      'holden'     => 'commodore',
      'mitsubishi' => 'lancer'   ,
      'toyota'     => 'corolla'
   )
);

Which uses the simple function switchAssign (defined below). The effect of the above code is exactly the same as in the earlier two examples, with an exception being thrown if the car manufacturer is not recognised.

If it is desired that a default case be provided, the function can be used as follows.

$bestSellingCarModelName = switchAssign
(
   $carManufacturerName, array
   (
      'ford'       => 'falcon'   ,
      'holden'     => 'commodore',
      'mitsubishi' => 'lancer'   ,
      'toyota'     => 'corolla'
   ), 'unknown'
);

In the above example, if no case matches the supplied car manufacturer name, then the $bestSellingCarName variable is set to 'unknown'.

See PHP and Javascript versions of function switchAssign() below, and note that in either, null can be used as a default assignment value.

PHP Version


/*
 * Usage example:
 *    $bestSellingCarModelName = Utils_misc::switchAssign
 *    (
 *       $carManufacturerName, array
 *       (
 *          'ford'   => 'falcon',
 *          'holden' => 'commodore'
 *       )
 *    );
 *
 * The above code is equivalent to:
 *    switch ($carManufacturerName)
 *    {
 *     case 'ford'  : $bestSellingCarModelName = 'falcon'   ; break;
 *     case 'holden': $bestSellingCarModelName = 'commodore'; break;
 *     default      : throw new Exception("Unknown car manufacturer '$carManufacturerName'.");
 *    }
 *
 * @param $defaultOutputValue {any type}
 *     This parameter is optional.  If it is not supplied, then there will be no output value
 *     for the default case specified and so an exception will be thrown in the default case.
 */
function switchAssign($inputValue, $outputValueByInputValue, $defaultOutputValue = null)
{
   if (array_key_exists($inputValue, $outputValueByInputValue))
   {
      return $outputValueByInputValue[$inputValue];
   }

   if (func_num_args() == 3)
   {
      return $defaultOutputValue;
   }

   throw new Exception
   (
      "Case '$inputValue' not handled in switchAssign and no default supplied."
   );
}

Javascript version

/*
 * Usage example:
 *    var bestSellingCarModelName = Utils_misc::switchAssign
 *    (
 *       carManufacturerName,
 *       {
 *          ford  : 'falcon',
 *          holden: 'commodore'
 *       }
 *    );
 *
 * The above code is equivalent to:
 *    switch (carManufacturerName)
 *    {
 *     case 'ford'  : var bestSellingCarModelName = 'falcon'   ; break;
 *     case 'holden': var bestSellingCarModelName = 'commodore'; break;
 *     default      : throw new Exception('Unknown car manufacturer "' + carManufacturerName + '".');
 *    }
 *
 * @param defaultOutputValue {any type}
 *     This parameter is optional.  If it is not supplied, then there will be no output value
 *     for the default case specified and so an exception will be thrown in the default case.
 */
function (inputValue, outputValueByInputValue, defaultOutputValue)
{
   if (typeof outputValueByInputValue[inputValue] != 'undefined')
   {
      return outputValueByInputValue[inputValue];
   }

   if (arguments.length == 3)
   {
      return defaultOutputValue;
   }

   throw new Exception
   (
      'Case "' + inputValue + '" not handled in switchAssign and no default supplied.'
   );
};

If anyone wishes to use these functions, I suggest adding them to a class so they can be called in php like

$x = Utils::switchAssign(...);

or in javascript

var x = Utils.switchAssign(...);

No comments:

Post a Comment