1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10: 11:
12:
13:
14:
15: 16: 17: 18: 19: 20:
21: final class ObjectMixin
22: {
23:
24: private static $methods;
25:
26:
27: private static $props;
28:
29:
30: 31: 32:
33: final public function __construct()
34: {
35: throw new StaticClassException;
36: }
37:
38:
39:
40: 41: 42: 43: 44: 45: 46: 47:
48: public static function call($_this, $name, $args)
49: {
50: $class = get_class($_this);
51: $isProp = self::hasProperty($class, $name);
52:
53: if ($name === '') {
54: throw new MemberAccessException("Call to class '$class' method without name.");
55:
56: } elseif ($isProp === 'event') {
57: if (is_array($_this->$name) || $_this->$name instanceof Traversable) {
58: foreach ($_this->$name as $handler) {
59: Callback::create($handler)->invokeArgs($args);
60: }
61: } elseif ($_this->$name !== NULL) {
62: throw new UnexpectedValueException("Property $class::$$name must be array or NULL, " . gettype($_this->$name) ." given.");
63: }
64:
65: } elseif ($cb = ClassReflection::from($_this)->getExtensionMethod($name)) {
66: array_unshift($args, $_this);
67: return $cb->invokeArgs($args);
68:
69: } else {
70: throw new MemberAccessException("Call to undefined method $class::$name().");
71: }
72: }
73:
74:
75:
76: 77: 78: 79: 80: 81: 82: 83:
84: public static function callProperty($_this, $name, $args)
85: {
86: if (strlen($name) > 3) {
87: $op = substr($name, 0, 3);
88: $prop = strtolower($name[3]) . substr($name, 4);
89: if ($op === 'add' && self::hasProperty(get_class($_this), $prop.'s')) {
90: $_this->{$prop.'s'}[] = $args[0];
91: return $_this;
92:
93: } elseif ($op === 'set' && self::hasProperty(get_class($_this), $prop)) {
94: $_this->$prop = $args[0];
95: return $_this;
96:
97: } elseif ($op === 'get' && self::hasProperty(get_class($_this), $prop)) {
98: return $_this->$prop;
99: }
100: }
101: return self::call($_this, $name, $args);
102: }
103:
104:
105:
106: 107: 108: 109: 110: 111: 112: 113:
114: public static function callStatic($class, $method, $args)
115: {
116: throw new MemberAccessException("Call to undefined static method $class::$method().");
117: }
118:
119:
120:
121: 122: 123: 124: 125: 126: 127:
128: public static function & get($_this, $name)
129: {
130: $class = get_class($_this);
131: $uname = ucfirst($name);
132:
133: if (!isset(self::$methods[$class])) {
134: self::$methods[$class] = array_flip(get_class_methods($class));
135: }
136:
137: if ($name === '') {
138: throw new MemberAccessException("Cannot read a class '$class' property without name.");
139:
140: } elseif (isset(self::$methods[$class][$m = 'get' . $uname]) || isset(self::$methods[$class][$m = 'is' . $uname])) {
141: $val = $_this->$m();
142: return $val;
143:
144: } elseif (isset(self::$methods[$class][$name])) {
145: $val = Callback::create($_this, $name);
146: return $val;
147:
148: } else {
149: $type = isset(self::$methods[$class]['set' . $uname]) ? 'a write-only' : 'an undeclared';
150: throw new MemberAccessException("Cannot read $type property $class::\$$name.");
151: }
152: }
153:
154:
155:
156: 157: 158: 159: 160: 161: 162: 163:
164: public static function set($_this, $name, $value)
165: {
166: $class = get_class($_this);
167: $uname = ucfirst($name);
168:
169: if (!isset(self::$methods[$class])) {
170: self::$methods[$class] = array_flip(get_class_methods($class));
171: }
172:
173: if ($name === '') {
174: throw new MemberAccessException("Cannot write to a class '$class' property without name.");
175:
176: } elseif (self::hasProperty($class, $name)) {
177: $_this->$name = $value;
178:
179: } elseif (isset(self::$methods[$class][$m = 'set' . $uname])) {
180: $_this->$m($value);
181:
182: } else {
183: $type = isset(self::$methods[$class]['get' . $uname]) || isset(self::$methods[$class]['is' . $uname])
184: ? 'a read-only' : 'an undeclared';
185: throw new MemberAccessException("Cannot write to $type property $class::\$$name.");
186: }
187: }
188:
189:
190:
191: 192: 193: 194: 195: 196: 197:
198: public static function remove($_this, $name)
199: {
200: $class = get_class($_this);
201: if (!self::hasProperty($class, $name)) {
202: throw new MemberAccessException("Cannot unset the property $class::\$$name.");
203: }
204: }
205:
206:
207:
208: 209: 210: 211: 212: 213:
214: public static function has($_this, $name)
215: {
216: $class = get_class($_this);
217: $name = ucfirst($name);
218: if (!isset(self::$methods[$class])) {
219: self::$methods[$class] = array_flip(get_class_methods($class));
220: }
221: return $name !== '' && (isset(self::$methods[$class]['get' . $name]) || isset(self::$methods[$class]['is' . $name]));
222: }
223:
224:
225:
226: 227: 228: 229:
230: private static function hasProperty($class, $name)
231: {
232: $prop = & self::$props[$class][$name];
233: if ($prop === NULL) {
234: $prop = FALSE;
235: try {
236: $rp = new ReflectionProperty($class, $name);
237: if ($name === $rp->getName() && $rp->isPublic() && !$rp->isStatic()) {
238: $prop = preg_match('#^on[A-Z]#', $name) ? 'event' : TRUE;
239: }
240: } catch (ReflectionException $e) {}
241: }
242: return $prop;
243: }
244:
245: }
246: