What could be better than chainable operators in jQuery, .addClass("beautiful").show("slow")
-style? Almost nothing, but adding those to PHP would make code cleaner and life easier.
At first sight, implementing these looks almost impossible, but after a quick look at extensions we notice that SPL could offer something similar, if combined with magic methods. Let’s implement ArrayAccess interface and see how it works:
<?php
$fruits = new Chain(array(
new String('apple'),
new String('mango'),
new String('kiwi')
));
echo "First fruit: ";
echo $fruits[0];
echo "\n";
echo "All fruits: ";
echo $fruits->toUpperCase()->join();
echo "\n";
?>
Outputs:
First fruit: apple
All fruits: APPLE, MANGO, KIWI
Beautiful, eh?
Here’s complete source code:
<?php
class Chain implements ArrayAccess {
private $items = array();
public function __construct($items = array()) {
if (!is_array($items)) return;
$this->items = $items;
}
public function add($element) {
$this->items[] = $element;
}
public function __call($method, $args) {
if (count($this->items)
&& !method_exists($this->items[0], $method)) {
throw new BadMethodCallException();
}
$returnChain = new Chain();
foreach($this->items as $item) {
$returnChain->add(call_user_func_array(array($item, $method), $args));
}
return $returnChain;
}
public function rewind() {
reset($this->items);
}
public function current() {
return current($this->items);
}
public function key() {
return key($this->items);
}
public function next() {
return next($this->items);
}
public function valid() {
return $this->current() !== false;
}
public function offsetExists($offset) {
return isset($this->items[$offset]);
}
public function offsetGet($offset) {
return $this->items[$offset];
}
public function offsetSet($offset, $value) {
return $this->items[$offset] = $value;
}
public function offsetUnset($offset) {
unset($this->items[$offset]);
}
// convenience method
public function join($separator = ', ') {
return implode($this->items, $separator);
}
}
class String{
private $s;
public function __construct($s) {
$this->s = $s;
}
public function toUpperCase() {
$this->s = strtoupper($this->s);
return $this;
}
public function __toString() {
return $this->s;
}
}
$fruits = new Chain(array(
new String('apple'),
new String('mango'),
new String('kiwi')
));
echo "First fruit: ";
echo $fruits[0];
echo "\n";
echo "All fruits: ";
echo $fruits->toUpperCase()->join();
echo "\n";
?>