2

I'm having troubles building a deeply nested associative array in PHP. From the questions/answers I've seen here and there, I gathered I should use references but I just can't figure out how to do so.

I am using PHP 5.3

I'm parsing a file that looks like JSON. It contains nested "sections" enclosed in curly braces and I want to build up a tree representation of the file using nested associative arrays.

I'm starting with a root section and a "current section" variables:

$rootSection = array();
$currentSection = $rootSection;
$sections = array();

When I enter a new section ('{'), this is what I do:

$currentSection[$newSectionName] = array();
array_push($sections, $currentSection);
$currentSection = $currentSection[$newSectionName];

I use the $sections variable to pop out of a section ('}') into its parent one:

$currentSection = array_pop($sections);

And finally, when I want to add a property to my section, I basically do:

$currentSection[$name] = $value;

I've removed all attempt to use references from the above code, as nothing has worked so far... I might as well say that I am used to Javascript, where references are the default...

But it's apparently not the case with PHP? I've dumped my variables in my parsing code and I could see that all properties were correctly added to the same array, but the rootSection array or the one pushed inside $sections would not be updated identically.

I've been looking for a way to do this for a few hours now and I really don't get it... So please share any help/pointers you might have for me!

UPDATE: The solution

Thanks to chrislondon I tried using =& again, and managed to make it work.

Init code:

$rootSection = array();
$currentSection =& $rootSection;
$sections = array();

New section ('{'):

$currentSection[$newSectionName] = array();
$sections[] =& $currentSection;
$currentSection =& $currentSection[$newSectionName];

Exiting a section ('}'):

$currentSection =& $sections[count($sections) - 1];
array_pop($sections);

Note that starting around PHP 5.3, doing something like array_push($a, &$b); is deprecated and triggers a warning. $b =& array_pop($a) is also not allowed; that's why I'm using the []=/[] operators to push/"pop" in my $sections array.

What I initially had problems with was actually this push/pop to my sections stack, I couldn't maintain a reference to the array and was constantly getting a copy.

Thanks for your help :)

2
  • 1
    Best way to parse potentially infinite levels of hierarchy is to use recursion. Regarding references, objects are all passed by reference in PHP. Arrays are not. You should probably avoid using references unless you're sure you need them. Commented Jun 11, 2013 at 3:09
  • @StevenMoseley I'm parsing the file using a lexer/scanner I specifically generated for it (using JLexPHP). It breaks the file content into tokens for me, and at each new '{' or '}' token, I execute the code given in my question. Therefore, I need to maintain a state of "where" I am in the file tree, that's what my $rootSection, $sections and $currentSection are for. As they are the same arrays pushed/assigned at different places depending on my parser state, I do need references :) Commented Jun 11, 2013 at 9:56

2 Answers 2

2

If you want to pass something by reference use =& like this:

$rootSection = array();
$currentSection =& $rootSection;

$currentSection['foo'] = 'bar';

print_r($rootSection);
// Outputs: Array ( [foo] => bar )

I've also seen the syntax like this $currentSection = &$rootSection; but they're functionally the same.

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

1 Comment

Thank you @chrislondon! This is what I had been trying to use, but after some time off the problem (and some sleep!) I followed that pointer again and managed to make it work :) I'll update my question with the solution.
0

A method for updating a nested associative array: for a given key-value pair, use a new k-v pair to overwrite the original one, and insert new k-v pairs when needed.

eg 1

use Illuminate\Support\Arr;

$data = [
  'feature_a1_enabled' => true,
  'feature_a2_enabled' => true,
  'feature_a2' => [
    'feature_a21_enabled' => true,
    'feature_a22_enabled' => true,
    'feature_a23_enabled' => true,
    'feature_a23' => [
      'feature_a231_enabled' => true,
      'feature_a232_enabled' => true,
    ],
  ],
  'feature_a3_enabled' => true,
];

$updates = [
  'feature_a2' => [
    'feature_a22_enabled' => false,
    'feature_a23' => [
      'feature_a233_enabled' => false,
    ],
  ],
  'feature_a3_enabled' => false,
  'feature_a4_enabled' => false,
];

$flattendUpdates = Arr::dot($updates);
foreach ($flattendUpdates as $k => $v) {
    Arr::set($data, $k, $v);
}
var_dump($data);

Result:

[
    "feature_a1_enabled" => true,
    "feature_a2_enabled" => true,
    "feature_a2" => [
      "feature_a21_enabled" => true,
      "feature_a22_enabled" => false,
      "feature_a23_enabled" => true,
      "feature_a23" => [
        "feature_a231_enabled" => true,
        "feature_a232_enabled" => true,
        "feature_a233_enabled" => false,
      ],
    ],
    "feature_a3_enabled" => false,
    "feature_a4_enabled" => false,
]

eg 2

use Illuminate\Support\Arr;

$data = [];

$updates = [
  'feature_a2' => [
    'feature_a22_enabled' => false,
    'feature_a23' => [
      'feature_a233_enabled' => false,
    ],
  ],
  'feature_a3_enabled' => false,
  'feature_a4_enabled' => false,
];

$flattendUpdates = Arr::dot($updates);
foreach ($flattendUpdates as $k => $v) {
    Arr::set($data, $k, $v);
}

var_dump($data);

Result:

[
    "feature_a2" => [
      "feature_a22_enabled" => false,
      "feature_a23" => [
        "feature_a233_enabled" => false,
      ],
    ],
    "feature_a3_enabled" => false,
    "feature_a4_enabled" => false,
]

This method can update or insert, but not delete a key.

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.