PHP json_encode 函数的编码

7
如何在PHP中编码JavaScript函数?我想使用数组对回调函数进行编码。
$options = array(
'title' => 'Title',
'fnCallback' => someCallback);

JavaScript 中的等价项:

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

我知道我的PHP代码有问题,我该怎么修复它?

JSON仅允许值,无法引用函数对象。您只能提供函数名称作为字符串,然后在Javascript中处理解析(使用映射或其他方式)。 - mario
someCallback 应该是什么?一个常量吗?因为只有常量可以像那样被引用。 - Gumbo
1
我猜 someCallback 是一个回调函数。 - Kevin Ji
@Gumbo,someCallback是一个JavaScript函数。 - Hensembryan
@mario 嗯,有道理。谢谢 Mario。 - Hensembryan
8个回答

8

Viola,我用Zend_JSON编码器解决了我的问题。

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

 Zend_Json::encode(
     $options,
     false,
     array('enableJsonExprFinder' => true));

3
很高兴看到实际使用ZF的例子 ;-). 我通过在php数组'data'=>'@aCallBack()@'中添加,在输出前使用json_encode,然后做了str_replace('"@','')和 ('@"','')来实现难看而优雅的效果。PHP4ever. - Teson

5

JSON用于传递值,不适合传递代码段。

相反,您可以传递函数名称或其他有意义的值,并从JavaScript侧检索正确的要调用的函数。


或者我通过返回一个字符串来解决这个问题,但这会使代码不够“简洁”$returnValue = "{'title': 'Title', 'fnCallback': someCallback}"; - Hensembryan

1

要让 PHP 中的通知消失,只需将您的回调函数用引号括起来:

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

然后当您在Javascript中接收到JSON时,您可以使用以下方法将回调函数名称重新映射为实际的JS函数:

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

0

如果没有考虑一种约定并自己实现它,那是不可能的。

比如说,你有这个JSON:

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

然后你可以在客户端上执行

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;
}

并在提供回调函数的对象上下文中调用它

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

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

wireupCallbacks.call(someObject, jsonObject);

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

缺少的功能:

  • 目前该函数仅查找名为"*Callback"的属性。
  • 没有回退到全局函数(这些将是window对象的属性)
  • 没有递归(嵌套对象不会被访问)
  • 没有JSON数组处理

自行添加这些功能,这些都不难实现。


0

这是我用来做这件事的代码:

//~ [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>";

这是结果:

    <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.


0
不要把JSON和实际的、本地的Javascript对象注释语法混为一谈(不管叫什么名字)。Javascript对象可以包含函数引用,而JSON则不能。

0

我喜欢这条评论中的想法,所以我进行了扩展。

这使用了唯一的ID进行替换,因此不太可能出现任何字符冲突或意外替换。您也可以使用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);

作为一种替代方案,如果您需要将JSON放入URL中,并且只需要在编码之前定义JS的良好方式,则可以使用Heredoc字符串
  $config = <<<EOF
    {
      foo: "bar",
      callback: function(value){return'$'+value+(value?'K':'');}
    }
  EOF;

-1
您忘记在“title”和“fnCallback”之间加逗号了。

抱歉,但这不是问题所在。在PHP中,someCallback 是非法的,但在js中不是。 - Hensembryan
是的,我原以为JSON_ENCODE可以引用该函数,但我错了,请参考@mario。 - Hensembryan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接