In this post I’ll present a way to send javascript functions over JSON from a php server (but it should work on other platforms too). Since PHP version 5.20 PHP includes the functions json_encode() and json_decode(). These functions encode values into JSON formatting and decode JSON formatted strings into associative arrays. The json_encode() function is not able to encode a value into a (javascript) function. This is a common issue when configuring graphs from Flotr (my Javascript plotting library) with JSON data. Here are my findings.

The Problem: Server-side

To get a better feeling for the problem, I’ll show you what happens when we pass an array to json_encode:

// Our sample array
$foo = array(
  'number'  => 1,
  'float'   => 1.5,
  'array'   => array(1,2),
  'string'  => 'bar',
  'function'=> 'function(){return "foo bar";}'
);

// Now encode the array to JSON format
$json = json_encode($foo);

// Send to to the client
echo $json;
...
// This sends the following string to the client:
{
  "number":1,
  "float":1.5,
  "array":[1,2],
  "string":"bar",
  "function":"function(){return \"foo bar\";}"
}

Because PHP reports some errors when we don’t enclose the ‘function’ with quotation marks, it not possible to omit those. So basically, it’s not possible to use json_encode() to create a JSON formatted string with functions.

The solution

My solution is very simple:

  • Loop over the associative array that is about to be encoded
  • Look for values that start with a function definition (like ‘function(‘)
  • Remember the value and replace it with a unique key (within the assoc array)
  • Encode the changed assoc array to JSON using json_encode()
  • Replace the unique keys enclosed in quotation marks with their original values
  • Echo the json string

In PHP:

// Our sample array
$foo = array(
  'number'  => 1,
  'float'   => 1.5,
  'array'   => array(1,2),
  'string'  => 'bar',
  'function'=> 'function(){return "foo bar";}'
);

$value_arr = array();
$replace_keys = array();
foreach($foo as $key => &$value){
  // Look for values starting with 'function('
  if(strpos($value, 'function(')===0){
    // Store function string.
    $value_arr[] = $value;
    // Replace function string in $foo with a 'unique' special key.
    $value = '%' . $key . '%';
    // Later on, we'll look for the value, and replace it.
    $replace_keys[] = '"' . $value . '"';
  }
}

// Now encode the array to json format
$json = json_encode($foo);

// $json looks like:
{
  "number":1,
  "float":1.5,
  "array":[1,2],
  "string":"bar",
  "function":"%function%"
}

// Replace the special keys with the original string.
$json = str_replace($replace_keys, $value_arr, $json);

// Send to to the client
echo $json;

// This echoes the following string:
{
  "number":1,
  "float":1.5,
  "array":[1,2],
  "string":"bar",
  "function":function(){return "foo bar";}
}

Now the ‘function’ key is not a String anymore, but it’s a function. So our problem is solved. When using Prototype, it will look something like this:

new Ajax.Request('json_server.php', {
  method:'get',
  onSuccess: function(transport){
     var json = transport.responseText.evalJSON();
     alert(json.function()); // => alerts 'foo bar'
   }
});

There might be dozens of solutions to the problem stated above, but I couldn’t find ‘em on the net. If you know a better technique, please share it!