Just wanted to update on this. I decided to go for developing my own Collection based on a normal array. I built an abstract superclass which should be extended by small sub classes. The Collection implements an interface Listable, with the sole method get_key( ) which is used to set the key in the array for our objects. The point is that Collection implements Listable WHILE having Listable object hinting for the methods. (This allows several collections to be the array elements of ONE collection.)
The collection will offer functionality such as add( $object ), remove( $anytype ), get( $key ), getAll( ), contains( $anytype ) and size( );.
The abstract collection looks like this:
<?php
interface Listable
{
/**
* GET_ID()
* Collections need a clear and unique ID to work
*/
public function get_key ( );
/**
* __toString()
* Must implement the magic method toString
*/
public function __toString ( );
}
<?php
abstract class Collection implements Listable
{
private $array = null;
public function __construct ( )
{
$this->array = array();
}
public function add ( Listable $object )
{
// Remove duplicates
if ( $this->contains($object) )
{
return "Object already exists";
}
// Add to array
$this->array[$object->get_key()] = $object;
}
public function add_event( Event $object)
{
$key = count($this->array)+1;
// Set key as object id
$object->set_key($key);
// add to array
$this->array[$key] = $object;
}
public function remove ( $anytype )
{
$key = $this->retrieveKey($anytype);
unset($this->array[$key]);
}
/**
* GET
* Get an object from the array
* @param Object The array key to return
* @return Object The object if found, else null
*/
public function get ( $key )
{
// Get The object
return (isset($this->array[$key])) ? $this->array[$key] : null;
}
public function getAll ( )
{
return $this->array;
}
public function size ( )
{
return count($this->array);
}
/**
* CONTAINS
* Checks wheter the object is in the array
*
* @param anytype $anytype A key or an object
* @return boolean true if not in array, else false
*/
public function contains ( $anytype )
{
$key = $this->retrieveKey($anytype);
return ($key != null) ? true : false;
}
/**
* RETRIEVE
* Retrieve object key
*
* @param anytype $anytype A key or an object
* @return boolean key if in array, else null
*/
private function retrieveKey ( $anytype )
{
// Check whether anytype is a Listable object
if ( $anytype instanceof Listable )
{
return (isset($this->array[$anytype->get_key()])) ? $anytype->get_key() : null;
}
// Use key directly
return (isset($this->array[$anytype])) ? $anytype : null;
}
}
A typical subclass of Collection would look like this:
<?php
class Round extends Collection
{
private $id;
private $name;
public function __construct($id, $name)
{
$this->id = $id;
$this->name = $name;
}
public function add ( Match $club )
{
parent::add($club);
}
public function get_key ( )
{
return $this->id;
}
public function __toString()
{
return $this->name;
}
}
?>
Or this:
<?php
include(&#39;event.php&#39;);
include(&#39;goal.php&#39;);
include(&#39;card.php&#39;);
class Match extends Collection implements Listable
{
private $id;
private $home_team;
private $away_team;
private $kickoff;
private $home_goals;
private $away_goals;
private $number_of_events = 0;
public function __construct($id, $home_team, $away_team, $kickoff, $goals_home = null, $goals_away = null)
{
$this->id = $id;
$this->home_team = $home_team;
$this->away_team = $away_team;
$this->kickoff = $kickoff;
$this->home_goals = $goals_home;
$this->away_goals = $goals_away;
}
public function add ( Event $event )
{
parent::add_event($event);
}
public function get_key ( )
{
return $this->id;
}
public function __toString()
{
return $this->home_team .&#39; vs. &#39;. $this->away_team .&#39; at &#39;. $this->kickoff .&#39; <br /> &#39;. $this->getEventsAsString();
}
private function getEventsAsString( )
{
$out = "";
$events = parent::getAll();
foreach ($events as $event ) {
$out .= &#39;- &#39;. $event . &#39;<br />&#39;;
}
return $out;
}
}
?>
I&#39;m guessing I will find errors/weird behavior initially, but for now, it works REALLY great. By extending a simple Collections class, I can simply add, remove and retrieve objects in a very simple matter. The next implementation will be to create an iterator object inside the Collection for simple output of the data.
Application code would look like this:
<?php
// Create clubs
$juventus = new Club(1, "Juventus");
$barcelona = new Club(2, "Barcelona");
$real = new Club(3, "Real Madrid");
// Create players
$vuci = new Player(10, "Mirko Vucinic", 17, "Vucinic");
$del_piero = new Player(10, "Alessandro Del Piero", 10, "Del Piero");
$messi = new Player(10, "Leonel Messi", 10, "Messi");
$ronaldo = new Player(10, "Cristiano Ronaldo", 10, "Ronaldo");
// Create matches
$match1 = new Match(1, $juventus, $barcelona, &#39;2011-05-20 20:45&#39;, 2, 0);
$match2 = new Match(2, $real, $barcelona, &#39;2011-05-25 20:45&#39;, 0, 6);
// Create events
$match1->add(new Goal( $vuci, 40, $del_piero ));
$match1->add(new Goal( $del_piero, 60, $vuci ));
$match1->add(new Card( $vuci, 65, Card::$YELLOW_CARD));
$match1->add(new Card( $vuci, 75, Card::$RED_CARD));
echo $match1 . &#39;<br />&#39;;
// Create events
$match2->add(new Goal( $messi, 20 ));
$match2->add(new Goal( $messi, 30 ));
$match2->add(new Goal( $messi, 39, $ronaldo ));
$match2->add(new Card( $ronaldo, 39, Card::$YELLOW_CARD));
$match2->add(new Goal( $messi, 60 ));
$match2->add(new Card( $ronaldo, 61, Card::$RED_CARD));
echo $match2;
?>
This produces the following output:Juventus vs. Barcelona at 2011-05-20 20:45
- Goal: Vucinic ( Assist: Del Piero ) 40&#39; min
- Goal: Del Piero ( Assist: Vucinic ) 60&#39; min
- Yellow card Vucinic 65
- Red card Vucinic 75
Real Madrid vs. Barcelona at 2011-05-25 20:45
- Goal: Messi 20&#39; min
- Goal: Messi 30&#39; min
- Goal: Messi ( Assist: Ronaldo ) 39&#39; min
- Yellow card Ronaldo 39
- Goal: Messi 60&#39; min
- Red card Ronaldo 61
And print_r: MATCH 1:Match Object
(
[id:Match:private] => 1
[home_team:Match:private] => Club Object
(
[id:Club:private] => 1
[name:Club:private] => Juventus
)
[away_team:Match:private] => Club Object
(
[id:Club:private] => 2
[name:Club:private] => Barcelona
)
[kickoff:Match:private] => 2011-05-20 20:45
[home_goals:Match:private] => 2
[away_goals:Match:private] => 0
[number_of_events:Match:private] => 0
[array:Collection:private] => Array
(
[1] => Goal Object
(
[id:Goal:private] => 1
[goal:Goal:private] => Player Object
(
[id:Player:private] => 10
[name:Player:private] => Mirko Vucinic
[shirtname:Player:private] =>
[shirtnumber:Player:private] => Vucinic
)
[time:Goal:private] => 40
[assist:Goal:private] => Player Object
(
[id:Player:private] => 10
[name:Player:private] => Alessandro Del Piero
[shirtname:Player:private] =>
[shirtnumber:Player:private] => Del Piero
)
)
[2] => Goal Object
(
[id:Goal:private] => 2
[goal:Goal:private] => Player Object
(
[id:Player:private] => 10
[name:Player:private] => Alessandro Del Piero
[shirtname:Player:private] =>
[shirtnumber:Player:private] => Del Piero
)
[time:Goal:private] => 60
[assist:Goal:private] => Player Object
(
[id:Player:private] => 10
[name:Player:private] => Mirko Vucinic
[shirtname:Player:private] =>
[shirtnumber:Player:private] => Vucinic
)
)
[3] => Card Object
(
[id:Card:private] => 3
[player:Card:private] => Player Object
(
[id:Player:private] => 10
[name:Player:private] => Mirko Vucinic
[shirtname:Player:private] =>
[shirtnumber:Player:private] => Vucinic
)
[time:Card:private] => 65
[type:Card:private] => 1
)
[4] => Card Object
(
[id:Card:private] => 4
[player:Card:private] => Player Object
(
[id:Player:private] => 10
[name:Player:private] => Mirko Vucinic
[shirtname:Player:private] =>
[shirtnumber:Player:private] => Vucinic
)
[time:Card:private] => 75
[type:Card:private] => 2
)
)
)
1 MATCH 2:Match Object
(
[id:Match:private] => 2
[home_team:Match:private] => Club Object
(
[id:Club:private] => 3
[name:Club:private] => Real Madrid
)
[away_team:Match:private] => Club Object
(
[id:Club:private] => 2
[name:Club:private] => Barcelona
)
[kickoff:Match:private] => 2011-05-25 20:45
[home_goals:Match:private] => 0
[away_goals:Match:private] => 6
[number_of_events:Match:private] => 0
[array:Collection:private] => Array
(
[1] => Goal Object
(
[id:Goal:private] => 1
[goal:Goal:private] => Player Object
(
[id:Player:private] => 10
[name:Player:private] => Leonel Messi
[shirtname:Player:private] =>
[shirtnumber:Player:private] => Messi
)
[time:Goal:private] => 20
[assist:Goal:private] =>
)
[2] => Goal Object
(
[id:Goal:private] => 2
[goal:Goal:private] => Player Object
(
[id:Player:private] => 10
[name:Player:private] => Leonel Messi
[shirtname:Player:private] =>
[shirtnumber:Player:private] => Messi
)
[time:Goal:private] => 30
[assist:Goal:private] =>
)
[3] => Goal Object
(
[id:Goal:private] => 3
[goal:Goal:private] => Player Object
(
[id:Player:private] => 10
[name:Player:private] => Leonel Messi
[shirtname:Player:private] =>
[shirtnumber:Player:private] => Messi
)
[time:Goal:private] => 39
[assist:Goal:private] => Player Object
(
[id:Player:private] => 10
[name:Player:private] => Cristiano Ronaldo
[shirtname:Player:private] =>
[shirtnumber:Player:private] => Ronaldo
)
)
[4] => Card Object
(
[id:Card:private] => 4
[player:Card:private] => Player Object
(
[id:Player:private] => 10
[name:Player:private] => Cristiano Ronaldo
[shirtname:Player:private] =>
[shirtnumber:Player:private] => Ronaldo
)
[time:Card:private] => 39
[type:Card:private] => 1
)
[5] => Goal Object
(
[id:Goal:private] => 5
[goal:Goal:private] => Player Object
(
[id:Player:private] => 10
[name:Player:private] => Leonel Messi
[shirtname:Player:private] =>
[shirtnumber:Player:private] => Messi
)
[time:Goal:private] => 60
[assist:Goal:private] =>
)
[6] => Card Object
(
[id:Card:private] => 6
[player:Card:private] => Player Object
(
[id:Player:private] => 10
[name:Player:private] => Cristiano Ronaldo
[shirtname:Player:private] =>
[shirtnumber:Player:private] => Ronaldo
)
[time:Card:private] => 61
[type:Card:private] => 2
)
)
)Sorry for the long post. I understand that it would be difficult to comment upon this without having more code, but that seems a little impractical.
I hope I've succeeded in demonstrating the simplicity in the class design. The question is: Why don't we see more code like this in PHP? I've never seen a Java-like Collection in PHP.
Why do you think that is? Do you understand how the code works, or is this not the way most PHP applications are coded? Hoping for some answers.