1: <?php
2:
3: namespace Alchemy\util;
4:
5:
6: /**
7: * Allow method chaining and simulated object immutablity
8: * by performing every method call on a clone of the object
9: * you started with.
10: */
11: class Monad {
12: protected $value;
13:
14:
15: /**
16: * Object constructor.
17: *
18: * @param Object $value Object to wrap
19: */
20: public function __construct($value) {
21: $this->value = $value;
22: }
23:
24:
25: /**
26: * Clone the inner object, call a method on it, and return it
27: *
28: * @param string $fn Method Name
29: * @param array $args
30: * @return Monad
31: */
32: public function __call($fn, $args) {
33: $that = clone $this;
34:
35: $method = array($that->value, $fn);
36: $value = call_user_func_array($method, $args);
37: $cls = get_class($this->value);
38:
39: // Returned nothing, is probably just did internal mutation
40: if ($value instanceof $cls) {
41: $that->value = $value;
42: return $that;
43: }
44:
45: // Returned a value to send to the user
46: if (!is_null($value)) {
47: return $value;
48: }
49:
50: return $that;
51: }
52:
53:
54: /**
55: * Force PHP to deep clone
56: */
57: public function __clone() {
58: $this->value = clone $this->value;
59: }
60:
61:
62: /**
63: * Unwrap the value
64: *
65: * @return mixed
66: */
67: public function unwrap() {
68: return clone $this->value;
69: }
70: }
71: