Как стать автором
Обновить

Передача функций через JSON

Время на прочтение3 мин
Количество просмотров17K
Автор оригинала: Bas Wenneker
Из этого топика вы узнаете как отправить JavaScript функции, через JSON используя PHP (сама концепция может быть применена и для других языков).

PHP, начиная с версии 5.2.0, включает функции json_encode() и json_decode(). Эти функции кодируют данные в формат JSON и декодиуют JSON в ассоциативные массивы. В json_encode() не может быть закодирована функция. В ряде случаев это чертовски неудобно.
  1. Добавлен пример реализации в Zend Framework.
  2. Вопрос к кармавампирам — вы знаете вариант как передать handler для создания объекта иначе?
  3. Комментарий о том для чего и кому это нужно.

Проблема

// Возьмем произвольный массив
$foo = array(
    'number' => 1,
    'float'  => 1.5,
    'array'  => array(1,2),
    'string' => 'bar',
    'function'=> 'function(){return "foo bar";}'
);
// Теперь преобразуем массив в JSON
$json = json_encode($foo);
// Отдадим клиенту
echo $json;


* This source code was highlighted with Source Code Highlighter.

Результат

{
    "number":1,
    "float":1.5,
    "array":[1,2],
    "string":"bar",
    "function":"function(){return \"foo bar\";}"
}

* This source code was highlighted with Source Code Highlighter.


Так как если не заключить определение функции в кавычки, т. е. не определить как строку, код не будет исполнятся. Так что в принципе jscon_encode() не годится для реализации этого функционала.

Решение

  1. Проходим по массиву который будет закодирован.
  2. Проверяем кодируемое значение на предмет наличия определения функции.
  3. Запоминаем значение и заменяем его уникальной меткой.
  4. Кодируем измененный массив используя json_encode().
  5. Заменяем уникальную метку на оригинальное значение.
  6. Отдаем JSON клиенту.
// Обрабатываемый массив.
$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){
 // Проверяем значения на наличие определения функции
 if(strpos($value, 'function(')===0){
    // Запоминаем значение для послудующей замены.
    $value_arr[] = $value;
    // Заменяем определение функции 'уникальной' меткой..
    $value = '%' . $key . '%';
    // Запоминаем метку для послудующей замены.
    $replace_keys[] = '"' . $value . '"';
 }
}

// Кодируем массив в JSON
$json = json_encode($foo);

// Полученный $json будет выглядеть так:
{
 "number":1,
 "float":1.5,
 "array":[1,2],
 "string":"bar",
 "function":"%function%"
}

// Заменяем метски оригинальными значениями.
$json = str_replace($replace_keys, $value_arr, $json);

// Отправляем клиенту.
echo $json;

// Клиент получит JSON такого вида:
{
 "number":1,
 "float":1.5,
 "array":[1,2],
 "string":"bar",
 "function":function(){return "foo bar";}
}


* This source code was highlighted with Source Code Highlighter.
Теперь в полученном обьекте «function» является не строкой, а функцией. Собственно проблема решена. Если использовать это решение совместно с Prototype, то оно будет выглядеть примерно так:
new Ajax.Request('json_server.php', {
 method:'get',
 onSuccess: function(transport){
     var json = transport.responseText.evalJSON();
     alert(json.function()); // => Отобразится alert 'foo bar'
  }
});


* This source code was highlighted with Source Code Highlighter.


Реализация в Zend Framework:


$foo = array(
  'integer' =>9,
  'string'  =>'test string',
  'function' => Zend_Json_Expr(
    'function(){ window.alert("javascript function encoded by Zend_Json") }'
  ),
);

Zend_Json::encode($foo, false, array('enableJsonExprFinder' => true));
// it will returns json encoded string:
{
  "integer":9,
  "string":"test string",
  "function":function(){
    window.alert("javascript function encoded by Zend_Json")
  }
}


* This source code was highlighted with Source Code Highlighter.
Теги:
Хабы:
Всего голосов 18: ↑7 и ↓11-4
Комментарии26

Публикации

Истории

Работа

Ближайшие события