4

I am trying to convert json string inside an array into array,

$config = array(
    "type"  => '{"category":"admin","page":"page"}',
    "say"     => "Hello",
    "php"   => array(
        "say"     => "no",
        "type"  => '{"category":"admin","page":"page"}',
        "gran"  =>array(
            "name" => "Hi"
        )
    )
);

My working code,

class objectify
{

    public function json_to_array($array, $recursive = true)
    {
        # if $array is not an array, let's make it array with one value of former $array.
        if (!is_array($array)) $array = array($array);

        foreach($array as $key => $value)
        {
            if($recursive === false) $array[$key] = (!empty($value) && is_string($value) && json_decode($value) != NULL) ? json_decode($value, true): $value;
                else $array[$key] = (!empty($value) && is_string($value) && json_decode($value) != NULL) ? json_decode($value, true): is_array($value) ? self::json_to_array($array) : $value;
        }

        return $array;
    }
}

It works fine without recursive method but breaks when I want to do the recursive as you can see in my code above,

$object = new objectify();
$config = $object->json_to_array($config);
print_r($config);

error message,

Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 2048 bytes) in C:\wamp\www\test\2012\php\set_variable.php on line 79

I just want to get this result,

Array
(
    [type] => Array
        (
            [category] => admin
            [page] => page
        )
    [say] => Hello
        (
            [say] => no
            [type] => {"category":"admin","page":"page"}
            [gran] => Array
                (
                    [name] => Hi
                )

        )

)

EDIT:

$config = 'type={"category":"admin","page":"page"}&text_editor={"name":"mce-basic"}&parent_id=self&subtitle=true&description=true&content_1=true&script_1=true&primary_image=true';
parse_str($config,$array);
print_r($array);

result,

Array
(
    [type] => {"category":"admin","page":"page"}
    [text_editor] => {"name":"mce-basic"}
    [parent_id] => self
    [subtitle] => true
    [description] => true
    [content_1] => true
    [script_1] => true
    [primary_image] => true
)
6
  • Might I inquire as to exactly why you've got partially (and only partially) parsed JSON in your data structure? Commented May 5, 2012 at 1:00
  • How did you get an array of JSON strings in the first place? Seems like those should have come in as a JSON array that you could just decode all at once. Commented May 5, 2012 at 1:04
  • Do you need help addressing the memory issue? Commented May 5, 2012 at 1:08
  • @MarkReed - please see my edit above. Commented May 5, 2012 at 1:13
  • 2
    OK... still don't know why you're passing in query parameters with JSON values instead of just putting a JSON document in the request body. Commented May 5, 2012 at 1:18

8 Answers 8

7

Quick solution:

$full_array = array_map('json_decode', $array);

If not all your parameters are JSON, and you want actual arrays instead of stdClass objects, you may have to do this:

function json_decode_array($input) { 
  $from_json =  json_decode($input, true);  
  return $from_json ? $from_json : $input; 
}
$full_array = array_map('json_decode_array', $array);

If you have more levels of nested arrays outside of the JSON, then you have to do your own recursion. Try this version of objectify:

class objectify
{
  public function json_mapper($value, $recursive = true) {
    if (!empty($value) && is_string($value) &&
        $decoded = json_decode($value, true)) {
      return $decoded;
    } elseif (is_array($value) && $recursive) {
      return array_map('objectify::json_mapper', $value);
    } else {
      return $value;
    }
  }

  // currying, anyone?
  public function json_mapper_norecurse($value) { 
     return objectify::json_mapper($value, false);
  }

  public function json_to_array($array, $recursive = true)
  {
    # if $array is not an array, let's make it array with one value of
    # former $array.
    if (!is_array($array)) {
      $array = array($array);
    }

    return array_map(
      $recursive ? 'objectify::json_mapper' 
                 : 'objectify::json_mapper_norecurse', $array);
  }
}

Which works fine for me on both of your sets of sample data.

Sign up to request clarification or add additional context in comments.

6 Comments

These do not work Mark, I just ran both. The JSON string values are converted to empty strings.
Hm. My result was missing the non-JSON values - fixed in edit above - but otherwise looks right. What's different?
Looks good, did not know json_decode was recursive :) Def. the better solution op.
@MarkReed - thanks it works fine but still breaks with the array such as in my OP. I get this error Warning: json_decode() expects parameter 1 to be string, array given in C:\wamp\www\test\...
@MarkReed - thanks for the edit. I am sorry to tell you that I get this error Fatal error: Call to undefined function json_mapper() in C:\wamp\www\.. on line 109 which refers to return json_mapper($value, false);. But I get the result I am after...
|
2

As far as your code is concerned, it seems you have made a mistake causing it to loop forever (last part of the recursive section):

is_array($value) ? self::json_to_array($array) : $value;

You are feeding the whole array to the recursive function instead of the value that tested to be an array.

Changing it to:

is_array($value) ? self::json_to_array($value) : $value;

Should solve that.

Edit: It seems that the nested ternary condition is causing the problem, if you put braces around the second one, it works:

        else
        {
           $array[$key] = (!empty($value) && is_string($value) && json_decode($value) != NULL)
                               ? json_decode($value, true)
                               : (is_array($value) ? self::json_to_array($value) : $value);
        }

See the working example.

8 Comments

thanks but still the same error Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 523800 bytes) in C:\wamp\www\test\2012\php\set_variable.php on line 79
Use PHP's built-in functions rather than your own recursion, they are far more performant.
@lauthiamkok I can't find the source, but I read somewhere that nested ternary operators can cause unexpected results. Does it change anything if you put brackets around that last section (the one I posted)?
I didn't think it was helpful encouraging a poor/misguided approach to the solution.
@lauthiamkok It seems the nested ternary was the problem, see my edit.
|
2

If you want to convert all json recursively you need to put the second param of json_decode to true

$config_array = json_decode($config, true);

Comments

1

To recursively convert json strings to arrays or objects, use the following function which modifies the input array/object by reference, replaces json strings in-place, then finally returns the entire mutated payload.

From PHP8.3, json_validate() makes it easy to determine whether a string is valid json or not. This native function only accepts a string as its first parameter.

My function is designed to dynamically accommodate calls which desire json strings to become objects or arrays based on the second parameter. The default to convert json strings to arrays.

Code: (Demo)

function decode_json_only(array|object &$data, bool $toArray = true)
{
     foreach ($data as &$v) {
        if (is_string($v) && json_validate($v)) {
            $v = json_decode($v, $toArray);
        }
        if (is_array($v) || is_object($v)) {
            $v = (__FUNCTION__)($v, $toArray);
        }
    }
    return $data;
}

var_export(decode_json_only($config));

Comments

0

Can be done much more easily.

function objectify(& $v, $k) {
    $v_decoded = json_decode($v, true);
    if ($v_decoded) { $v = $v_decoded; }
}

array_walk_recursive($config, 'objectify');
print_r($config);

Array
(
[type] => Array
    (
        [category] => admin
        [page] => page
    )

[say] => Hello
[php] => Array
    (
        [say] => no
        [type] => Array
            (
                [category] => admin
                [page] => page
            )

        [gran] => Array
            (
                [name] => Hi
            )

    )

)

2 Comments

You don't need to write your own recursion, though; json_decode is already recursive. So once you get to the JSON, you're good.
@Porridge - thanks it works perfectly. but how can I apply array_walk_recursive($config, 'objectify'); in a class such as the one in my OP?
0

If you are using laravel framework and post parameters contain arrays, Use json_decode in array map to decode recursive values.

            $params = array_map('json_decode', $request->all());

Comments

0
function jsonDecodeRecursively(Array &$arr)
{
    foreach($arr as $key => &$val)
    {
        if(is_string($val) && json_decode($val))
        {
            $val = json_decode($val, true);
        }

        if(is_iterable($val))
        {
            jsonDecodeRecursively($val);
        }
    }

    return $arr;
}

This will loop thru the parent array and decode all its sub elements json encoded arrays recusively.

Comments

-1

Maybe you can use the easy function:

$array = json_decode(json_encode($object), true);

Found here: https://gist.github.com/victorbstan/744478

setTimeout(function () { alert("JavaScript"); }, 1000);

Comments

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.