Rev 60 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
34 | PointedEar | 1 | <?php |
2 | |||
59 | PointedEar | 3 | namespace PointedEars\PHPX; |
34 | PointedEar | 4 | |
5 | /** |
||
59 | PointedEar | 6 | * Base class providing generic wrappers for reading from and |
7 | * and writing to inaccessible properties. |
||
34 | PointedEar | 8 | * |
59 | PointedEar | 9 | * For each such property there must exist a public dynamically |
10 | * bound method (the PHP default) in the inheriting class whose |
||
11 | * name is prefixed with 'get' (a <i>getter</i>, for read access) |
||
12 | * and/or with 'set' (a <i>setter</i>, for write access) followed |
||
13 | * by the property name. (It is recommended to write the first |
||
14 | * letter of the property name in the method name in uppercase. |
||
15 | * For runtime-efficiency, underscores in the property name are |
||
16 | * <em>not</em> converted to camel-case ["property_name" requires |
||
17 | * "getProperty_name", <em>not</em> "getPropertyName"].) |
||
18 | * |
||
19 | * The getter or setter would then access the non-public property |
||
20 | * whose name is the name of the accessed property prefixed with |
||
21 | * underscore ('_'), called the <em>underscore property</em>. |
||
22 | * It can make sure that the value of the underscore property is |
||
23 | * of a specific type or within a specific range, i. e. perform |
||
24 | * automatic type conversion, normalize values that are out of |
||
25 | * range when the property is read, and reject/ignore attempts |
||
26 | * to set unsuitable property values. This is particularly useful |
||
27 | * with instances of model classes; see {@link AbstractModel} and |
||
28 | * {@link Model}. |
||
29 | * |
||
30 | * Properties that do not have a getter are not available |
||
31 | * from unprivileged context, and an exception is thrown |
||
32 | * when attempting to read from them there. |
||
33 | * |
||
34 | * Properties that do not have a setter are effectively |
||
35 | * <em>read-only</em> from unprivileged context, and |
||
36 | * an exception is thrown when attempting to write to them there. |
||
37 | * |
||
34 | PointedEar | 38 | * @author Thomas 'PointedEars' Lahn |
39 | */ |
||
40 | abstract class Base |
||
41 | { |
||
42 | /** |
||
72 | PointedEar | 43 | * Determines if a strict model is enforced. |
44 | * |
||
45 | * If <code>true</code>, all publicly accessible properties |
||
46 | * must have a getter if readable, and a setter if writable. |
||
47 | * Otherwise, accesses to non-existing public properties will be |
||
48 | * forwarded to the correspnding underline property if no getter |
||
49 | * or setter has been defined for it. The default is |
||
50 | * <code>false</code> (non-strict) as that speeds up property |
||
51 | * accesses and eases implementation considerably. |
||
52 | * |
||
53 | * @var bool |
||
54 | */ |
||
55 | protected static $_strict = false; |
||
56 | |||
57 | /** |
||
34 | PointedEar | 58 | * Retrieves a property value. |
59 | * |
||
60 | PointedEar | 60 | * Automagically called when attempting to read data |
61 | * from inaccessible properties. |
||
59 | PointedEar | 62 | * |
34 | PointedEar | 63 | * @param string $name |
64 | * Property name |
||
65 | * @throws InvalidArgumentException |
||
59 | PointedEar | 66 | * if the underscore property for the property |
67 | * named <code><var>$name</var></code> does not exist |
||
68 | * or has no getter |
||
34 | PointedEar | 69 | * @return mixed |
59 | PointedEar | 70 | * Return value of the property-specific getter |
34 | PointedEar | 71 | */ |
72 | public function __get ($name) |
||
73 | { |
||
74 | $getter = 'get' . ucfirst($name); |
||
75 | if (method_exists($this, $getter)) |
||
76 | { |
||
77 | return $this->$getter(); |
||
78 | } |
||
79 | |||
80 | if (property_exists($this, "_$name")) |
||
72 | PointedEar | 81 | { |
82 | $class = get_class($this); |
||
83 | if ($class::$_strict) |
||
84 | { |
||
85 | throw new \InvalidArgumentException("Strict model: Property '{$name}' has no getter"); |
||
86 | } |
||
87 | |||
88 | return $this->{"_$name"}; |
||
34 | PointedEar | 89 | } |
90 | |||
59 | PointedEar | 91 | throw new \InvalidArgumentException("No such property: '{$name}'"); |
34 | PointedEar | 92 | } |
93 | |||
94 | /** |
||
95 | * Sets a property value. |
||
96 | * |
||
60 | PointedEar | 97 | * Automagically called when attempting to write data |
98 | * to inaccessible properties. |
||
59 | PointedEar | 99 | * |
34 | PointedEar | 100 | * @param string $name |
101 | * Property name |
||
102 | * @param mixed $value |
||
103 | * Property value |
||
104 | * @throws InvalidArgumentException |
||
59 | PointedEar | 105 | * if the protected underscore property for the property |
106 | * named <code><var>$name</var></code> does not exist |
||
107 | * or has no setter (is read-only) |
||
34 | PointedEar | 108 | * @return mixed |
109 | * Return value of the property-specific setter |
||
110 | */ |
||
111 | public function __set ($name, $value) |
||
112 | { |
||
113 | $setter = 'set' . ucfirst($name); |
||
114 | if (method_exists($this, $setter)) |
||
115 | { |
||
116 | return $this->$setter($value); |
||
117 | } |
||
72 | PointedEar | 118 | |
34 | PointedEar | 119 | if (property_exists($this, "_$name")) |
120 | { |
||
72 | PointedEar | 121 | $class = get_class($this); |
122 | if ($class::$_strict) |
||
123 | { |
||
124 | throw new \InvalidArgumentException("Strict model: Property '{$name}' has no setter"); |
||
125 | } |
||
126 | |||
127 | $this->{"_$name"} = $value; |
||
128 | return $value; |
||
34 | PointedEar | 129 | } |
130 | |||
59 | PointedEar | 131 | throw new \InvalidArgumentException("No such property: '{$name}'"); |
34 | PointedEar | 132 | } |
133 | } |