Search code examples
phparraysclosurespass-by-referencelexical-scope

Manipulating PHP arrays using references like JS objects


I am manipulating an array, as shown below, in JavaScript.

http://ideone.com/vH43iD

<?php

$root = array(
    'nodes'=>array(
        '1'=>array(
            'id'=>'1',
            'nodes'=>array(
                '4'=>array(
                    'id'=>'4',
                    'nodes'=>array(
                        '5'=>array(
                            'id'=>'5',
                            'nodes'=>array()
                        )
                    )
                )
            )
        ),
        '2'=>array(
            'id'=>'2',
            'nodes'=>array()
        ),
        '3'=>array(
            'id'=>'3',
            'nodes'=>array()
        )
    )
);

foreach ($root['nodes'] as $_node_id => &$_root_node) {
    $_put_parent = function (&$_node) use (&$_put_parent) {
        foreach ($_node['nodes'] as $_sub_node_id => &$_sub_node) {
            $_put_parent($_sub_node);
            $_sub_node['parent'] = $_node;
        }
    };

    $_root_node['parent'] = null;
    $_put_parent($_root_node);
}

echo '<pre>';
var_dump($root['nodes']['1']['nodes']['4']);
var_dump($root['nodes']['1']['nodes']['4']['nodes']['5']['parent']);
echo '</pre>';

?>

Output:

array(3) {
  ["id"]=>
  string(1) "4"
  ["nodes"]=>
  &array(1) {
    [5]=>
    array(3) {
      ["id"]=>
      string(1) "5"
      ["nodes"]=>
      array(0) {
      }
      ["parent"]=>
      array(2) {
        ["id"]=>
        string(1) "4"
        ["nodes"]=>
        *RECURSION*
      }
    }
  }
  ["parent"]=>
  array(3) {
    ["id"]=>
    string(1) "1"
    ["nodes"]=>
    &array(1) {
      [4]=>
      *RECURSION*
    }
    ["parent"]=>
    NULL
  }
}
array(2) {
  ["id"]=>
  string(1) "4"
  ["nodes"]=>
  &array(1) {
    [5]=>
    array(3) {
      ["id"]=>
      string(1) "5"
      ["nodes"]=>
      array(0) {
      }
      ["parent"]=>
      *RECURSION*
    }
  }
}

$root['nodes']['1']['nodes']['4']['nodes']['5']['parent'] should point to itself of $root['nodes']['1']['nodes']['4'] but $root['nodes']['1']['nodes']['4']['nodes']['5']['parent'] have not got 'parent' reference.

I do this often in JavaScript but I do not understand what is the problem for php.

Thank you.


Solution

  • I solved it with using ArrayObjects.

    http://ideone.com/J79Wh6

    <?php
    
    $root = new ArrayObject(array(
        'nodes'=>new ArrayObject(array(
            '1'=>new ArrayObject(array(
                'id'=>'1',
                'nodes'=>new ArrayObject(array(
                    '4'=>new ArrayObject(array(
                        'id'=>'4',
                        'nodes'=>new ArrayObject(array(
                            '5'=>new ArrayObject(array(
                                'id'=>'5',
                                'nodes'=>new ArrayObject(array())
                            ))
                        ))
                    ))
                ))
            )),
            '2'=>array(
                'id'=>'2',
                'nodes'=>new ArrayObject(array())
            ),
            '3'=>new ArrayObject(array(
                'id'=>'3',
                'nodes'=>new ArrayObject(array())
            ))
        ))
    ));
    
    foreach ($root['nodes'] as $_node_id => $_root_node) {
        $_put_parent = function ($_node) use (&$_put_parent) {
            foreach ($_node['nodes'] as $_sub_node_id => $_sub_node) {
                $_put_parent($_sub_node);
                $_sub_node['parent'] = $_node;
            }
        };
    
        $_root_node['parent'] = null;
        $_put_parent($_root_node);
    }
    
    echo '<pre>';
    var_dump($root['nodes']['1']['nodes']['4']);
    var_dump($root['nodes']['1']['nodes']['4']['nodes']['5']['parent']);
    echo '</pre>';
    
    ?>
    

    Output is now:

    object(ArrayObject)[5]
      public 'id' => string '4' (length=1)
      public 'nodes' => 
        object(ArrayObject)[6]
          public 5 => 
            object(ArrayObject)[7]
              public 'id' => string '5' (length=1)
              public 'nodes' => 
                object(ArrayObject)[8]
                  ...
              public 'parent' => 
                &object(ArrayObject)[5]
      public 'parent' => 
        object(ArrayObject)[3]
          public 'id' => string '1' (length=1)
          public 'nodes' => 
            object(ArrayObject)[4]
              public 4 => 
                &object(ArrayObject)[5]
          public 'parent' => null
    object(ArrayObject)[5]
      public 'id' => string '4' (length=1)
      public 'nodes' => 
        object(ArrayObject)[6]
          public 5 => 
            object(ArrayObject)[7]
              public 'id' => string '5' (length=1)
              public 'nodes' => 
                object(ArrayObject)[8]
                  ...
              public 'parent' => 
                &object(ArrayObject)[5]
      public 'parent' => 
        object(ArrayObject)[3]
          public 'id' => string '1' (length=1)
          public 'nodes' => 
            object(ArrayObject)[4]
              public 4 => 
                &object(ArrayObject)[5]
          public 'parent' => null