1 | 2 | simandl | <?php |
2 | | | |
3 | | | namespace Phem\Core; |
4 | | | |
5 | | | /** |
6 | | | * Description of ObjectMixin |
7 | | | * |
8 | | | * @author Vejvis |
9 | | | */ |
10 | | | final class ObjectMixin |
11 | | | { |
12 | | | |
13 | | | /** @var array */ |
14 | | | private static $methods; |
15 | | | |
16 | | | /** |
17 | | | * Returns property value. |
18 | | | * @param object |
19 | | | * @param string property name |
20 | | | * @return mixed property value |
21 | | | * @throws MemberAccessException if the property is not defined. |
22 | | | */ |
23 | | | public static function & get($_this, $name) |
24 | | | { |
25 | | | $class = get_class($_this); |
26 | | | |
27 | | | if ($name === '') |
28 | | | { |
29 | | | throw new MemberAccessException("Cannot read a class '$class' property without name."); |
30 | | | } |
31 | | | |
32 | | | if (!isset(self::$methods[$class])) |
33 | | | { |
34 | | | // get_class_methods returns ONLY PUBLIC methods of objects |
35 | | | // but returns static methods too (nothing doing...) |
36 | | | // and is much faster than reflection |
37 | | | // (works good since 5.0.4) |
38 | | | self::$methods[$class] = array_flip(get_class_methods($class)); |
39 | | | } |
40 | | | |
41 | | | // public method as closure getter |
42 | | | if (isset(self::$methods[$class][$name])) |
43 | | | { |
44 | | | $val = function() use ($_this, $name) |
45 | | | { |
46 | | | return call_user_func_array(array($_this, $name), func_get_args()); |
47 | | | }; |
48 | | | return $val; |
49 | | | } |
50 | | | |
51 | | | // property getter support |
52 | | | $name[0] = $name[0] & "\xDF"; // case-sensitive checking, capitalize first character |
53 | | | $m = 'get' . $name; |
54 | | | if (isset(self::$methods[$class][$m])) |
55 | | | { |
56 | | | // ampersands: |
57 | | | // - uses &__get() because declaration should be forward compatible |
58 | | | // - doesn't call &$_this->$m because user could bypass property setter by: $x = & $obj->property; $x = 'new value'; |
59 | | | $val = $_this->$m(); |
60 | | | return $val; |
61 | | | } |
62 | | | |
63 | | | $m = 'is' . $name; |
64 | | | if (isset(self::$methods[$class][$m])) |
65 | | | { |
66 | | | $val = $_this->$m(); |
67 | | | return $val; |
68 | | | } |
69 | | | |
70 | | | $type = isset(self::$methods[$class]['set' . $name]) ? 'a write-only' : 'an undeclared'; |
71 | | | $name = func_get_arg(1); |
72 | | | throw new MemberAccessException("Cannot read $type property $class::\$$name."); |
73 | | | } |
74 | | | |
75 | | | /** |
76 | | | * Sets value of a property. |
77 | | | * @param object |
78 | | | * @param string property name |
79 | | | * @param mixed property value |
80 | | | * @return void |
81 | | | * @throws MemberAccessException if the property is not defined or is read-only |
82 | | | */ |
83 | | | public static function set($_this, $name, $value) |
84 | | | { |
85 | | | $class = get_class($_this); |
86 | | | |
87 | | | if ($name === '') |
88 | | | { |
89 | | | throw new MemberAccessException("Cannot write to a class '$class' property without name."); |
90 | | | } |
91 | | | |
92 | | | if (!isset(self::$methods[$class])) |
93 | | | { |
94 | | | self::$methods[$class] = array_flip(get_class_methods($class)); |
95 | | | } |
96 | | | |
97 | | | // property setter support |
98 | | | $name[0] = $name[0] & "\xDF"; // case-sensitive checking, capitalize first character |
99 | | | |
100 | | | $m = 'set' . $name; |
101 | | | if (isset(self::$methods[$class][$m])) |
102 | | | { |
103 | | | $_this->$m($value); |
104 | | | return; |
105 | | | } |
106 | | | |
107 | | | $type = isset(self::$methods[$class]['get' . $name]) || isset(self::$methods[$class]['is' . $name]) ? 'a read-only' : 'an undeclared'; |
108 | | | $name = func_get_arg(1); |
109 | | | throw new MemberAccessException("Cannot write to $type property $class::\$$name."); |
110 | | | } |
111 | | | |
112 | | | } |