2011-03-16 40 views
4

當使用PHP的json_encode將數組編碼爲JSON字符串時,有沒有辦法阻止函數引用返回的字符串中的特定值?我問的原因是因爲我需要javascript來將對象中的某些值解釋爲實際變量名稱,例如現有JavaScript函數的名稱。防止用PHP引用某些值json_encode()

我的最終目標是使用輸出的json作爲ExtJS菜單組件的配置對象,所以事實上所有事情都會被引用,這使得我無法成功設置孩子的「處理程序」(點擊事件處理函數)等屬性項目數組。

回答

0

這是我落得這樣做,這是非常接近斯特凡什麼上述建議,我認爲:

class JSObject 
{ 
    var $jsexp = 'JSEXP:'; 

    /** 
    * Encode object 
    * 
    * 
    * @param  array $properties 
    * @return string 
    */ 
    function encode($properties=array()) 
    { 
     $output = ''; 
     $enc_left = $this->is_assoc($properties) ? '{' : '['; 
     $enc_right = ($enc_left == '{') ? '}' : ']'; 

     foreach($properties as $prop => $value) 
     { 
      //map 'true' and 'false' string values to their boolean equivalent 
      if($value === 'true') { $value = true; } 
      if($value === 'false') { $value = false; } 

      if((is_array($value) && !empty($value)) || (is_string($value) && strlen(trim(str_replace($this->jsexp, '', $value))) > 0) || is_int($value) || is_float($value) || is_bool($value)) 
      { 
       $output .= (is_string($prop)) ? $prop.': ' : ''; 

       if(is_array($value)) 
       { 
        $output .= $this->encode($value); 
       } 
       else if(is_string($value)) 
       { 
        $output .= (substr($value, 0, strlen($this->jsexp)) == $this->jsexp) ? substr($value, strlen($this->jsexp)) : '\''.$value.'\''; 
       } 
       else if(is_bool($value)) 
       { 
        $output .= ($value ? 'true' : 'false'); 
       } 
       else 
       { 
        $output .= $value; 
       } 

       $output .= ','; 
      } 
     } 

     $output = rtrim($output, ','); 
     return $enc_left.$output.$enc_right; 
    } 

    /** 
    * JS expression 
    * 
    * Prefixes a string with the JS expression flag 
    * Strings with this flag will not be quoted by encode() so they are evaluated as expressions 
    * 
    * @param string $str 
    * @return string 
    */ 
    function js($str) 
    { 
     return $this->jsexp.$str; 
    } 
} 
1

不,json_encode不能這樣做。你需要手工來構建你的JS表達則:

$json = "{'special':" . json_encode($string) . " + js_var," 
     . "'value': 123}"; 

(嘗試仍然使用json_encode爲固定值的部分,就像上面的例子)。

+0

是啊,這就是我所擔心的,因爲這是具有未知深度的子陣列wh的多維數組我會用手來構造這個json字符串一個主要的痛苦:-( – 2011-03-16 20:05:18

+0

雖然寫一個你自己的小json編碼器並不那麼複雜。只要將它鏈接到PHP提供的用於普通值(字符串和數字)的json_encode,並讓它爲任何對象調用__toString(這樣您就可以引用您自己的JS表達式)。你可能不需要數組支持,甚至不需要遞歸。 (但是手寫全部可能是最簡單的選擇。) – mario 2011-03-16 20:09:27

1

的json_encode功能不適用於提供任何功能控制報價。引號對JavaScript正確形成JavaScript端的對象也是必需的。

爲了使用返回的值在JavaScript端構建對象,請使用json_encoded字符串在關聯中設置標誌。

例如:

json_encode(array("click_handler"=> "FOO")); 

JavaScript端的AJAX:

if(json.click_handler == "FOO") { 
    json.click_handler = Your_Handler; 
} 

完成這些步驟後,你可以通過你的對象過的地方。

3

我們所做的是(也就是Zend_Json::encode()所做的),是使用特殊的標記類,它將Javascript表達式封裝在特殊的類中。編碼然後遞歸遍歷我們要編碼的數組,用一些字符串替換所有標記實例。使用內置的json_encode()後,我們只需進行一次字符串替換即可將各個特殊字符串替換爲標記實例的__toString()值。

您可以直接使用Zend_Json(如果可能的話)或檢查how they do it並根據您的需要調整代碼。

2

比爾的功能差不多的工作,它只是需要is_assoc()函數中添加。

但是,當我整理出來,我把它清理了一下。這似乎對我來說很好:

<?php 

/** 
* JSObject class. 
*/ 

class JSObject { 
    var $jsexp = 'JSEXP:'; 

    /** 
    * is_assoc function. 
    * 
    * Determines whether or not the object is an associative array 
    * 
    * @access public 
    * @param mixed $arr 
    * @return boolean 
    */ 
    function is_assoc($arr) { 
     return (is_array($arr) && count(array_filter(array_keys($arr),'is_string')) == count($arr)); 
    } 

    /** 
    * Encode object 
    * 
    * Encodes the object as a json string, parsing out items that were flagged as objects so that they are not wrapped in double quotes. 
    * 
    * @param  array $properties 
    * @return string 
    */ 
    function encode($properties = array()) { 

     $is_assoc = $this->is_assoc($properties); 

     $enc_left = $is_assoc ? '{' : '['; 
     $enc_right = $is_assoc ? '}' : ']'; 

     $outputArray = array(); 

     foreach ($properties as $prop => $value) { 

      if ((is_array($value) && !empty($value)) || (is_string($value) && strlen(trim(str_replace($this->jsexp, '', $value))) > 0) || is_int($value) || is_float($value) || is_bool($value)) { 

       $output = (is_string($prop)) ? $prop.': ' : ''; 

       if (is_array($value)) { 
        $output .= $this->encode($value); 
       } 
       else if (is_string($value)) { 
        $output .= (substr($value, 0, strlen($this->jsexp)) == $this->jsexp) ? substr($value, strlen($this->jsexp)) : json_encode($value); 
       } 
       else { 
        $output .= json_encode($value); 
       } 


       $outputArray[] = $output; 
      } 
     } 

     $fullOutput = implode(', ', $outputArray); 

     return $enc_left . $fullOutput . $enc_right; 
    } 

    /** 
    * JS expression 
    * 
    * Prefixes a string with the JS expression flag 
    * Strings with this flag will not be quoted by encode() so they are evaluated as expressions 
    * 
    * @param string $str 
    * @return string 
    */ 
    function js($str) { 
     return $this->jsexp.$str; 
    } 
} 
0

在Stefan Gehrig的帶領下,我把這個粗略的小課堂放在了一起。下面的例子。必須記住如果使用了標記方法,則使用序列化方法,否則標記將保留在最終的json中。

class json_extended { 

    public static function mark_for_preservation($str) { 
     return 'OINK' . $str . 'OINK'; // now the oinks will be next to the double quotes 
    } 

    public static function serialize($stuff) { 
     $json = json_encode($stuff); 
     $json = str_replace(array('"OINK', 'OINK"'), '', $json); 
     return $json; 
    } 
} 


$js_arguments['submitHandler'] = json_extended::mark_for_preservation('handle_submit'); 

<script> 
$("form").validate(<?=json_extended::serialize($js_arguments)?>); 
// produces: $("form").validate({"submitHandler":handle_submit}); 
function handle_submit() {alert('Yay, pigs!'); } 
</script> 
1

我的quickfix是這樣的:

$myobject->withquotes = 'mystring'; 
$myobject->withoutquotes = '##noquote## mystring ##noquote##'; 

後來

str_replace(array('"##noquote## ', ' ##noquote##"'), '', json_encode($myobject)) 

結果是這樣的

{"withquotes":"mystring","withoutquotes":mystring}