Subversion Repositories PHPX

Rev

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
}