Simple PHP closure/lamda/anonymous function usage.

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.

About Jason

I am a 26 year old programmer living in the south of France. I currently work actively in the fields of Ruby/PHP/Javascript and server/website administration.
This entry was posted in OOP, PHP Tutorials, PHP/MySQL, Topics and tagged , , . Bookmark the permalink.