Nested Objects to Associative Array - Without Recursion

Right,

Here’s one for you.

Let’s say I have these 3 classes.


abstract class Model
{
  public function toArray(){
    $array = array();
    /*
      Do stuff, here.
    */
    return $array;
  }
}


class RouteCollection extends Model
{
  public
    $routes = array();
}


class Route extends Model
{
  protected
    $username = 'anthonysterling',
    $password = '5up3rS3cre7P@s5';
    
  public
    $url      = '';
}

Given the following usage…


$routes = new RouteCollection;

$routes->routes[0] = new Route;
$routes->routes[0]->url = 'Google Inc';

$routes->routes[1] = new Route;
$routes->routes[1]->url = 'Yahoo Inc';
$routes->routes[1]->cfg = new stdClass;
$routes->routes[1]->cfg->public = true;

var_dump(
  $routes->toArray()
);

I’d like to see the following associative array created…


/*
  array(
    'routes'  => array(
      0 => array(
        'username' => 'anthonysterling',
        'password' => '5up3rS3cre7P@s5',
        'url'      => 'Google Inc'
      ),
      1 => array(
        'username' => 'anthonysterling',
        'password' => '5up3rS3cre7P@s5',
        'url'      => 'Yahoo Inc',
        'cfg'      => array(
          'public'  => true
        )
      )
    )
  )
*/

The gotchas? No recursion allowed, unlimited depth, not all nested objects are routes and some of the required properties are not public. The ->toArray method could be called on any object which extends Model and it should return the tree from that point forward.

I’d love to see some SPL usage, as to provide a standard approach but I cannot see how this is possible due to the non-public properties - reflection appears to be out too for the very same reason (at least on < 5.3.0).

So, shoot! :smiley:

Well then you are going have to use something other then stdClass otherwise it will just get messier and messier. :stuck_out_tongue: PHP does have its limits.

Or…use recursion.

Ha.

I refuse to be beaten, although I admit, recursion is (at least currently) the more cleaner option.

Still, I’ll hack away… :eye:

Thanks!

But what about the stdClass’ children? Those won’t be iterated…

Then you only need (array)$…


if ( $value instanceof YourSpecialClass ) {
    $value->toArray();
    continue;
}

if ( is_object( $value ) ) (array)$value;

Something to that effect.

Why the requirement for no recursion? That seems like it would be the best way to do things.

I scared you with too much code didn’t I ? :stuck_out_tongue:

Heh, not really. I had a little play with an internal stack and an endless while loop which I broke out of one no more ‘children’ were present, but it was awfully messy.

What can be done recursively can be done iteratively, but I think this will make a mess of code in PHP due to no proper pointers. Did you get anything working? I had a quick go, but gave up pretty quickly :expressionless:

No idea really…


<?php

class Tester
{
    protected $username, $password, $special;
    public function __construct ( $username, $password ) {
        $this->username = $username;
        $this->password = $password;
    }

    public function addSpecial ( Tester $special ) {
        $this->special = $special;
        return $this;
    }

    public function toArray ()
    {
        $ret = array();
        foreach ( (array)$this as $prop => $value ) {
            $prop = trim( $prop, "\\0*" ); // For Protected properties.

            if ( empty( $value ) ) continue;

            if ( is_object( $value ) ) {
                $ret[ $prop ] = $value->toArray();
                continue;
            }

            $ret[ $prop ] = $value;
        }
                
        return $ret;
    }
}

$t = new Tester( "Logic", "Fake" );
    $t->addSpecial( new Tester( "Frank", "Bob" ) );
var_dump( $t->toArray() );

/*
array(3) {
  ["username"]=>
  string(5) "Logic"
  ["password"]=>
  string(4) "Fake"
  ["special"]=>
  array(2) {
    ["username"]=>
    string(5) "Frank"
    ["password"]=>
    string(3) "Bob"
  }
}
*/

I don’t like the idea of it. :smiley:

I can do it with recursion, but it still seems messy to me. Iteration, that’s the name of the game.

:wink:

The stdClass doesn’t have a toArray() method. :wink:


$routes->routes[1]->cfg = new stdClass;
$routes->routes[1]->cfg->public = true;