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