This is a fun little example of the new Closure features in php.
class TArray { public $pMembers = array(); public $pCurrentIndex = 0; public function __construct() { $args = func_get_args(); if (empty($args)) return; if (count($args) == 1) $args = $args[0]; foreach ($args as $arg) array_push($this->pMembers,$arg); } public function push() { $args = func_get_args(); foreach ($args as $arg) { array_push($this->pMembers,$arg); } } public function pop() { return array_pop($this->pMembers); } public function each() { $args = func_get_args(); if (empty($args)) { if ($this->pCurrentIndex > count($this->pMembers)) { $this->pCurrentIndex = 0; return null; } $ret = $this->pMembers[$this->pCurrentIndex]; $this->pCurrentIndex++; return $ret; } else if (is_callable($args[0])) { array_walk($this->pMembers,$args[0]); } else { throw new Exception("Array->each does not understand that..."); } } public function resetIndex() { $this->pCurrentIndex = 0; } } $array = new TArray(1,2,3,4,5,6); while ($i = $array->each()) { echo "$i\n"; } $array->each(function ($elem) { echo "$elem\n";}); |
We can go a little further, and do like this.
class Person { public $name; public function __construct($name) { $this->name = $name; } } $array = new TArray(new Person('John'), new Person('Jane')); $array->each(function ($person) { echo "{$person->name}\n";}); |
An issue that comes up is, how do I get the $this variable in there. The short answer is, you don’t. You can finaigle it after a fashion, but it’s just ugly.
The issue is, people want the $this var, because they want to be able to manipulate the values, in a permanent fashion, or do something else. How you accomplish it, in a pretty way is:
1. Give up the ghost, you can’t have $this, it’s just a word, pick a different word.
2. standardize the new $this word
3. pass that word as a reference.
So, we end up modifying the code a little:
... public function each() { $args = func_get_args(); if (empty($args)) { if ($this->pCurrentIndex > count($this->pMembers)) { $this->pCurrentIndex = 0; return null; } $ret = $this->pMembers[$this->pCurrentIndex]; $this->pCurrentIndex++; return $ret; } else if (is_callable($args[0])) { foreach ($this->pMembers as &$member) { call_user_func($args[0],$member); } } else { throw new Exception("Array->each does not understand that..."); } } ... |
Then we can do stuff like this:
class Person { public $name; public $type = 'Human'; public function __construct($name) { $this->name = $name; } } class Pet { public $type; public $name; public function __construct($name,$type) { $this->name = $name; $this->type = $type; } } $array = new TArray(new Person('John'), new Person('Jane'), new Pet('Cecil','Dog')); $array->each(function ($self) { $self->type = 'Who Knows...'; } ); $array->each(function ($self) { echo "{$self->name} of type {$self->type}\n"; } ); |
Well, that’s some PHP Closure funness.
