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