Implementing PHP Iterator

PHP programming forum. Ask questions or help people concerning PHP code. Don't understand a function? Need help implementing a class? Don't understand a class? Here is where to ask. Remember to do your homework!

Moderator: General Moderators

aliasxneo
Forum Contributor
Posts: 136
Joined: Thu Aug 31, 2006 12:01 am

Implementing PHP Iterator

Post by aliasxneo »

This is going to be pretty advanced and therefor hard to understand so I'm hoping one of you can help me out here.

First let me introduce the class I want to work on. I have a class called dynamicObject that overloads the default __get() and __set() PHP functions to create essentially a dynamic class. It allows coding like the following:

Code: Select all

$test = new dynamicObject();
$test->someVar = "some value";
echo $test->someVar; // Prints "some value"
As you can see it let's me dynamically set variables and then access them later by using the __get and __set functions with an internal array. Well now I want to extend this functionality a little more.

Basically I want the object to act as an array as well. I want it so that when the object is put through a loop it loops through all it's current variables and returns their appropriate values (by using the array). In example:

Code: Select all

$test = new dynamicObject();
$test->someVar1 = "some value1";
$test->someVar2 = "some value2";

foreach($test as $name => $value)
{
    // For the first loop $name should be "someVar1";
    // For the first loop $value should be "some value1";
}
It shouldn't be too hard seeing as all the variable information is held in a single array. I know there exists a class called Iterator in PHP5 but I'm a little lost in how I would use it in this case. Is it even possible? If so how might I go about it?

If I lost anyone just ask and I'll try to add more to the explanation but in summary I just need a way to be able to iterate via a foreach() loop through all the variables in my dynamicObject class which are held in one array. Thanks in advance.

Cheers,
Josh

P.S Here is the code to my dynamicObject class:

Code: Select all

<?php

/**
 * A dynamic class representing any object
 * 
 * This class uses dynamic coding to create
 * a class that can fit around almost any
 * object. By overloading default class
 * functions a dynamic environment can 
 * be created.
 * 
 * @author Joshua Gilman (AliasXNeo)
 *
 */
class dynamicObject
{
	/**
	 * Mixed array used for holding class attributes
	 *
	 * @var Mixed
	 */
	private $details = array();
	
	/**
	 * Class constructor
	 *
	 */
	function __construct()
	{
		
	}
	
	/**
	 * The default __get() class function
	 * 
	 * This function overloads the default __get()
	 * function allowing the class to take on a 
	 * dynamic form.
	 *
	 * @param String $var
	 * @return Mixed
	 */
	function __get($var)
	{
		if (isset($this->{$var}))
		{
			return $this->{$var};
		} else if(isset($this->details[$var])) {
			return $this->details[$var];
		} else {
			return NULL;
		}
	}

	/**
	 * The default __set() class function
	 * 
	 * This function overloads the default __set()
	 * function allowing the class to take on a 
	 * dynamic form.
	 *
	 * @param String $var
	 * @param Mixed $value
	 */
	function __set($var, $value)
	{
		if (isset($this->{$var}))
		{
			$this->{$var} = $value;
		} else {
			$this->details[$var] = $value;
		}
	}
	
	/**
	 * Returns the current list of class attributes
	 *
	 * @return Mixed
	 */
	public function getAttributes()
	{
		return $this->details;
	}
	
	/**
	 * Returns the number of class attributes
	 *
	 * @return Integer
	 */
	public function numAttributes()
	{
		return sizeof($this->details);
	}
}

?>
User avatar
s.dot
Tranquility In Moderation
Posts: 5001
Joined: Sun Feb 06, 2005 7:18 pm
Location: Indiana

Post by s.dot »

You could probably make use of get_defined_vars(). You could do it in a method -- but that would inherit the method scope. You would need to call it in the object scope, I'm guessing.

EDIT| get_object_vars() looks promising.
Set Search Time - A google chrome extension. When you search only results from the past year (or set time period) are displayed. Helps tremendously when using new technologies to avoid outdated results.
aliasxneo
Forum Contributor
Posts: 136
Joined: Thu Aug 31, 2006 12:01 am

Post by aliasxneo »

scottayy wrote:You could probably make use of get_defined_vars(). You could do it in a method -- but that would inherit the method scope. You would need to call it in the object scope, I'm guessing.

EDIT| get_object_vars() looks promising.
I think you are misunderstanding. It's not a matter of getting what's defined, all the dynamic variables of the class are all in the $details array. All I want to do is make the below functionality work:

Code: Select all

$test = new dynamicObject();
$test->someVar1 = "some value1";
$test->someVar2 = "some value2";

foreach($test as $name => $value)
{
    // For the first loop $name should be "someVar1";
    // For the first loop $value should be "some value1";
}
User avatar
feyd
Neighborhood Spidermoddy
Posts: 31559
Joined: Mon Mar 29, 2004 3:24 pm
Location: Bothell, Washington, USA

Post by feyd »

Adding "implements Iterator" and adding the required functions should probably help.
aliasxneo
Forum Contributor
Posts: 136
Joined: Thu Aug 31, 2006 12:01 am

Post by aliasxneo »

feyd wrote:Adding "implements Iterator" and adding the required functions should probably help.
I realize that, but as I said in the post looking at the documentation/tutorials I am confused in how it would be used in my case.
User avatar
feyd
Neighborhood Spidermoddy
Posts: 31559
Joined: Mon Mar 29, 2004 3:24 pm
Location: Bothell, Washington, USA

Post by feyd »

The functions are chiefly what the foreach function looks for.. Technically it looks to see that the object implements Iterator, but that's neither here nor there, as implementing an interface requires defining those methods to pass compilation.
aliasxneo
Forum Contributor
Posts: 136
Joined: Thu Aug 31, 2006 12:01 am

Post by aliasxneo »

feyd wrote:The functions are chiefly what the foreach function looks for.. Technically it looks to see that the object implements Iterator, but that's neither here nor there, as implementing an interface requires defining those methods to pass compilation.
I understand all of that. I know the basics of how the Iterator works with all of it's functions. Basically you have a global counter that keeps track of where you are in iterating the array and then you supply functions for incrementing and decrementing, etc. etc.

My problem is not with that, but with this exact statement:

Code: Select all

$test = new dynamicObject();
$test->someVar1 = "some value1";
$test->someVar2 = "some value2";

foreach($test as $name => $value)
{
    // For the first loop $name should be "someVar1";
    // For the first loop $value should be "some value1";
}
First of all, $details is an associative array and therefor cannot be traversed via a number. Second of all in the above statement what functions are called? How does it know what to return to $name and $value. Do you see where I'm getting lost?
User avatar
feyd
Neighborhood Spidermoddy
Posts: 31559
Joined: Mon Mar 29, 2004 3:24 pm
Location: Bothell, Washington, USA

Post by feyd »

$details doesn't exist in your post. Secondly, Iterator doesn't care about a number, per se.
aliasxneo
Forum Contributor
Posts: 136
Joined: Thu Aug 31, 2006 12:01 am

Post by aliasxneo »

feyd wrote:$details doesn't exist in your post. Secondly, Iterator doesn't care about a number, per se.
I was referring to the dynamicObject class in my first post. All the variables in the dynamicObject class are held in an associative array called $details. It is this array I am trying to iterate in the class.
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post by Christopher »

What feyd is talking about is pretty advanced so if he lost you just ask and he'll try to add more to the explanation ...

http://www.php.net/~helly/php/ext/spl/i ... rator.html
(#10850)
aliasxneo
Forum Contributor
Posts: 136
Joined: Thu Aug 31, 2006 12:01 am

Post by aliasxneo »

arborint wrote:What feyd is talking about is pretty advanced so if he lost you just ask and he'll try to add more to the explanation ...

http://www.php.net/~helly/php/ext/spl/i ... rator.html
Well the whole thing is advanced to me really. All I'm looking for is an example that would work for the example I gave. I learn better from examples than explanations. I've read 3 different tutorials so far on the Iterator class and none of them have solved my problem.
jeffery
Forum Contributor
Posts: 105
Joined: Mon Apr 03, 2006 3:13 am
Location: Melbourne, Australia
Contact:

Post by jeffery »

would the Reflection API help? http://php.net/reflection
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post by Christopher »

I believe if you implement the Iterator interface and you class has the following methods it will just work:

current ()
key ()
next ()
rewind ()
valid ()

The return values for those methods are on the page I provided the link to.
(#10850)
User avatar
feyd
Neighborhood Spidermoddy
Posts: 31559
Joined: Mon Mar 29, 2004 3:24 pm
Location: Bothell, Washington, USA

Post by feyd »

http://php.net/language.oop5.iterations seems pretty self explanatory.
Begby
Forum Regular
Posts: 575
Joined: Wed Dec 13, 2006 10:28 am

Post by Begby »

Here is the really simple way to do it.

Code: Select all

class DynamicObject implements IteratorAggregate, Countable
{
  private $details = array(); 
  
  //.. stuff

  
  // This is the method needed for the IteratorAggregate interface
  public function getIterator()
  {
     return new ArrayIterator($this->details) ;
  }

  // It threw this in here as well which is what is needed for the countable interface which you can use in place of
  // numAttributes()
  public function count()
  {
     return count($this->details) ;
  }

}


$test = new DynamicObject() ;

// ...

// use IteratorAggregate
foreach ($test as $key => $value)
{
  // do stuff
}

// Use Countable
echo count($test) ;
Post Reply