7

How to encode a Javascript function in PHP? I want to encode the callback function with array

$options = array(
'title' => 'Title',
'fnCallback' => someCallback);

equivalent ini Javascript:

var options = {
'title': 'Title',
'fnCallback': someCallback };

I know my PHP code is wrong, how can I fix it?

5
  • JSON only allows for values. You cannot reference a function object with it. You can only supply the function name as string, and then handle the resolution in Javascript (using a map or something). Commented May 29, 2011 at 18:43
  • What is someCallback supposed to be? A constant? Because only constants can be references like that. Commented May 29, 2011 at 18:43
  • 1
    I'm guessing that someCallback is a callback function. Commented May 29, 2011 at 18:44
  • @Gumbo someCallback is a javascript function. Commented May 29, 2011 at 18:49
  • @mario hmmm there is make sense. Thx mario Commented May 29, 2011 at 18:50

8 Answers 8

8

Viola i solved my problem with Zend_JSON encoder

 $options = array(
     'title' => 'Title',
     'fnCallback' => new Zend_Json_Expr('someCallback')
 );      

 Zend_Json::encode(
     $options,
     false,
     array('enableJsonExprFinder' => true));
Sign up to request clarification or add additional context in comments.

1 Comment

Great to see some actual use of ZF ;-). I went ugly and elegant by adding in the php array 'data'=>'@aCallBack()@' and after json_encode before output, did str_replace('"@','') and ('@"',''). PHP4ever.
5

JSON is for passing values around, they are not suitable for passing pieces of code.

You can, instead, pass a function name or other meaningful value and retrieve the right function to call from it on the JavaScript side.

1 Comment

alternatively i solve that by returning a string, but this is make the code not "clean" $returnValue = "{'title': 'Title', 'fnCallback': someCallback}";
1

To make the notice go away in PHP, just write your callback function in quotes:

$options = array(
   'title' => 'Title',
   'fnCallback' => "someCallback");

And then when you receive the JSON in Javascript, you can remap the callback function name to the actual JS function with e.g.:

json = $.getJSON(..);
json.fnCallback = window[json.fnCallback];   // for global callbacks

Comments

0

Don't confuse JSON for actual, native, Javascript object notation syntax (regardless of the name). Javascript objects can contain function references; JSON cannot.

Comments

0

That is not possible without thinking of a convention and implementing it yourself.

Say, you have this JSON

'{"title": "Title", "fnCallback": "someCallback" }'

Then you could do, on the client side

function wireupCallbacks(jsonObject) {
  if (typeof jsonObject === "object") {
    for (var prop in jsonObject) {
      var callbackName = jsonObject[prop];
      if (/Callback$/.test(prop) && typeof callbackName === "string") {
        if (typeof this[callbackName] === "function") {
          jsonObject[prop] = this[callbackName];
        }
      }
    }
  }
  return jsonObject;
}

and call that in the context of an object that provides your callback functions

var someObject = {
  someCallback: function() { alert("It works!"); }
}

var jsonObject = {"title": "Title", "fnCallback": "someCallback" };

wireupCallbacks.call(someObject, jsonObject);

jsonObject.fnCallback(); // alerts "It works!"

What's missing:

  • currently the function only looks for properties named "*Callback".
  • there is no fallback to global functions (these would be properties of the window object)
  • there is no recursion (nested objects are not visited)
  • there is no JSON array handling

Add these features on your own, none of these should be difficult to implement.

Comments

0

Voici le code que j'utilise pour faire cela :

//~ [FUNCTION]
function __json_encode($mVar,$fnCallback="stripcslashes") {
    return preg_replace_callback('#"[ ]{0,}function[ ]{0,}\([^)$]{0,}\)[ ]{0,}\{[ ]{0,}(?(?![ ]{0,}}[ ]{0,}").){0,}[ ]{0,}\}[ ]{0,}"([(?,")|(?\}{0,}$)]{0,})#si', 
        function ($aRes) use ($fnCallback) { 
            for($aRes[0]=substr($aRes[0],1),$sOut="",$i=0,$iOpen=0,$iClose=0;$i<= strlen($aRes[0]) && $sOut.= substr($aRes[0],$i,1);$i++) 
                if (substr($aRes[0],$i,1) == "{") $iOpen++;
                else if (substr($aRes[0],$i,1) == "}" AND $iOpen == ++$iClose) break;
            return is_callable($fnCallback) ? $fnCallback($sOut).$aRes[1] : $sOut.$aRes[1]; 
        },json_encode($mVar)
    );
}



//~ [TEST]
print "<script>\n";
print sprintf(
    "\tvar oTest = %s;",
    __json_encode(
        array( 
            "Numeric"=>1,
            "string"=>"hello world !",
            "myFunction"=>"function(test) {  if (test==1) { alert('myFunction(1)'); return true; } else return false; }",
            "myObject"=>array(
                "Numeric"=>1,
                "string"=>"hello world !",
                "myFunction"=>"function(test) {  alert('myFunction(1)'); return true; }")
        )
    )
);
print "\n\tif (oTest.myFunction(1) == false) alert('myFunction(0)');";
print "\n\tif (oTest.myObject.myFunction(0) == false) alert('myFunction(0)');";
print "\n</script>";

Voici le résultat :

    <script>
        var oTest = {
            "Numeric":1,
            "string":"hello world !",
            "myFunction":function(test) {  if (test==1) { alert('myFunction(1)'); return true; } else return false; },
            "myObject":{
                "Numeric":1,
                "string":"hello world !",
                "myFunction":function(test) {  alert('myFunction(1)'); return true; }
            }
        };
        if (oTest.myFunction(0) == false) alert('myFunction(0)');
        if (oTest.myObject.myFunction(1) == false) alert('myFunction(0)');
    </script>

Cdt.

Comments

0

I liked the idea in this comment, so I expanded upon it.

This uses a unique ID for the replacement, so that it's unlikely to have any character conflicts or accidental replacements. You could alternatively use a GUID.

  $callback_uuid = uniqid();
  $config = [
    'foo' => 'bar',
    'callback' => $callback_uuid,
  ];

  $json = json_encode($config, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT);

  // Replace UUID with JS function, and remove the surrounding quotations.
  // Note: This avoids putting '$0' in the string, because regexes replace that.
  $callback_js = "function(value){return'$'+value+(value?'K':'');}";
  $json = preg_replace("/\"$callback_uuid\"/", $callback_js, $json);

As an alternative, if you need to put the JSON into a URL and simply need a nice way to define the JS prior to encoding it, you can use a Heredoc string:

  $config = <<<EOF
    {
      foo: "bar",
      callback: function(value){return'$'+value+(value?'K':'');}
    }
  EOF;

Comments

-1

You forgot the comma between 'title' and 'fnCallback.'

2 Comments

oops i'm sorry, but it is not the problem. someCallback is illegal in PHP but not in js.
yeah i supposed JSON_ENCODE can reference the function but i'm wrong see @mario

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.