Square bracket method in a class?

Is it possible to declare a style method in a class? (Sorry I’m not at a dev machine right now to run a simple test.)

class Items
{

private $_items = array();

// code removed...

public function this[$index]
{
    // return something
}

// more code removed...

}

I think you may want to look at this article

Implementing Iterator or IteratorAggregate is likely what you want.

I’m already doing that. I’m authoring both a Collection class and a Dictionary class. The difference being that the Collection class doesn’t accept a $key. It operates purely on index. For example:

$d = new Dictionary();
$d->Add(‘Primary’, $primaryObj);
$d->Add(‘Secondary’, $secondaryObj);
// key MUST be a non-null, non-empty string

$c = new Collection();
$c->Add($primaryObj);
$c->Add($secondaryObj);
// this just uses numeric indexes

What I’d like to be able to do though is…

$c[2] = $replacementObj;

Instead of…

$c->Replace(2, $replacementObj);

Can this be done?

Gotcha.

If you go to php.net/Iterator, the comment by wavetrex A(nospam)T gmail DOT com seems to be what you want to accomplish.

I haven’t read through all of the comments yet so there may be a better solution than his, but he did do a proof-of-concept of the idea you are wanting to implement.

Just an FYI, same page further down, comment by just_somedood at yahoo dot com

Seems you can implement ArrayAccess to get to what you are wanting to do.

Brilliant. I’ll try it out when I can and let you know if it works.

Please do let me know if it works, as I too will likely attempt this in the near future too, would definitely like to know your experience.

Success!

ICollator.interface.phps


<?php

interface ICollator extends ArrayAccess, Countable, IteratorAggregate
{

}

?>

Collator.class.phps


<?php

abstract class Collator implements ICollator
{

	protected $_items = array();

	protected function __construct(ICollator $collator = null)
	{
		
		if (!is_null($collator))
			foreach ($collator as $offset => $value)
				$this->_items[$offset] = $value;

	}

	public function OffsetExists($offset)
	{

		return array_key_exists($offset, $this->_items);

	}

	public function OffsetGet($offset)
	{

		if ($this->offsetExists($offset))
			return $this->_items[$offset];
		else
			throw new Exception('Requested offset was not found!');
		
	}

	public function OffsetSet($offset, $value)
	{

		if ($this->offsetExists($offset))
			$this->_items[$offset] = $value;
		else
			throw new Exception('Requested offset was not found!');

	}

	public function OffsetUnset($offset)
	{

		throw new Exception('Unsetting an element is not allowed!');

	}

	public function Count()
	{

		return count($this->_items);

	}

	public function GetIterator()
	{

		return new ArrayIterator($this->_items);

	}

}

?>

ICollection.interface.phps


<?php

interface ICollection extends ICollator
{

	function Add($value);

	function Contains($value);

	function Remove($value);

}

?>

Collection.class.phps


<?php

class Collection extends Collator implements ICollection
{

	public function __construct(ICollection $collection = null)
	{

		parent::__construct($collection);		

	}

	public function Add($value)
	{

		if (!$this->Contains($value))
			$this->_items[] = $value;

	}

	public function Contains($value)
	{

		return in_array($value, array_values($this->_items));

	}

	public function Remove($value)
	{

		if ($this->Contains($value))
			unset($this->_items[array_search($value, $this->_items)]);
			
	}

}

?>

IDictionary.interface.phps


<?php

interface IDictionary extends ArrayAccess, Countable, IteratorAggregate
{

	function Add($key, $value);

	function Contains($value);

	function Keys();

	function Remove($key);

	function Values();

}

?>

Dictionary.class.phps


<?php

class Dictionary extends Collator implements IDictionary
{

	public function __construct(IDictionary $dictionary = null)
	{

		parent::__construct($dictionary);		

	}

	public function Add($key, $value)
	{

		if (!is_string($key) || is_null($key) || empty($key))
			throw new Exception('String key expected!');

		if (!$this->Keys()->Contains($key))
			$this->_items[$key] = $value;

	}

	public function Contains($value)
	{

		return in_array($value, array_values($this->_items));

	}

	public function Keys()
	{

		$keys = new Collection();

		foreach (array_keys($this->_items) as $key)
			$keys->Add($key);

		return $keys;

	}

	public function Remove($key)
	{

		if ($this->Keys()->Contains($key))
			unset($this->_items[$key]);

	}

	public function Values()
	{

		$values = new Collection();

		foreach (array_values($this->_items) as $value)
			$values->Add($value);

		return $values;

	}

}

?>

Usage



// creating collections
$collection = new Collection();
$collection = new Collection($existing);

// adding to a collection
$collection->Add($item);

// testing inclusion in a collection
if ($collection->Contains($item))
{
    // do something
}

// getting a collection value
$item = $collection[0];

// setting a collection value
$collection[0] = $item;

// removing a collection value
$collection->Remove($item);

// creating dictionaries
$dictionary = new Dictionary();
$dictionary = new Dictionary($existing);

// adding to a dictionary
$dictionary->Add($key, $item);

// testing key inclusion in a dictionary
if ($dictionary->Keys()->Contains($key))
{
    // do something
}

// testing item inclusion in a dictionary
if ($dictionary->Values()->Contains($item))
{
    // do something
}
// or
if ($dictionary->Contains($item))
{
    // do something
}

// getting a dictionary value
$item = $dictionary["key"];

// setting a dictionary value
$dictionary["key"] = $item;

// removing a dictionary value
$dictionary->Remove($key);


As you can see, it is built to be extensible, so feel free to come up with your own implementations of Collator. I will probably do a typecast version where I extend Collator to TypedCollator and pass in $type before the optional collator instance. You could also do a read only version if you wanted.

=)

Here, I cleaned up the code a little, added a few exceptions and cut out a few ‘else’ statements.

Great, glad it worked out! Thanks for the code too, that will surely come in handy.

Nice code @Serenarules ; , this certainly will help others, and also for your help @cpradio ;.

Steve

You’re welcome. =)