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