Completed
Push — 2.1 ( 88a4f4...b503dc )
by Carsten
07:25
created

Object::__get()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 3
Metric Value
dl 0
loc 11
rs 9.4285
ccs 7
cts 7
cp 1
cc 3
eloc 8
nc 3
nop 1
crap 3
1
<?php
2
/**
3
 * @link http://www.yiiframework.com/
4
 * @copyright Copyright (c) 2008 Yii Software LLC
5
 * @license http://www.yiiframework.com/license/
6
 */
7
8
namespace yii\base;
9
10
use Yii;
11
12
/**
13
 * Object is the base class that implements the *property* feature.
14
 *
15
 * A property is defined by a getter method (e.g. `getLabel`), and/or a setter method (e.g. `setLabel`). For example,
16
 * the following getter and setter methods define a property named `label`:
17
 *
18
 * ```php
19
 * private $_label;
20
 *
21
 * public function getLabel()
22
 * {
23
 *     return $this->_label;
24
 * }
25
 *
26
 * public function setLabel($value)
27
 * {
28
 *     $this->_label = $value;
29
 * }
30
 * ```
31
 *
32
 * Property names are *case-insensitive*.
33
 *
34
 * A property can be accessed like a member variable of an object. Reading or writing a property will cause the invocation
35
 * of the corresponding getter or setter method. For example,
36
 *
37
 * ```php
38
 * // equivalent to $label = $object->getLabel();
39
 * $label = $object->label;
40
 * // equivalent to $object->setLabel('abc');
41
 * $object->label = 'abc';
42
 * ```
43
 *
44
 * If a property has only a getter method and has no setter method, it is considered as *read-only*. In this case, trying
45
 * to modify the property value will cause an exception.
46
 *
47
 * One can call [[hasProperty()]], [[canGetProperty()]] and/or [[canSetProperty()]] to check the existence of a property.
48
 *
49
 * Besides the property feature, Object also introduces an important object initialization life cycle. In particular,
50
 * creating an new instance of Object or its derived class will involve the following life cycles sequentially:
51
 *
52
 * 1. the class constructor is invoked;
53
 * 2. object properties are initialized according to the given configuration;
54
 * 3. the `init()` method is invoked.
55
 *
56
 * In the above, both Step 2 and 3 occur at the end of the class constructor. It is recommended that
57
 * you perform object initialization in the `init()` method because at that stage, the object configuration
58
 * is already applied.
59
 *
60
 * In order to ensure the above life cycles, if a child class of Object needs to override the constructor,
61
 * it should be done like the following:
62
 *
63
 * ```php
64
 * public function __construct($param1, $param2, ..., $config = [])
65
 * {
66
 *     ...
67
 *     parent::__construct($config);
68
 * }
69
 * ```
70
 *
71
 * That is, a `$config` parameter (defaults to `[]`) should be declared as the last parameter
72
 * of the constructor, and the parent implementation should be called at the end of the constructor.
73
 *
74
 * @author Qiang Xue <[email protected]>
75
 * @since 2.0
76
 */
77
class Object implements Configurable
78
{
79
    /**
80
     * Returns the fully qualified name of this class.
81
     * @return string the fully qualified name of this class.
82
     * @deprecated since version 2.1. PHPs `::class` syntax should be used instead.
83
     * For object instances, use `get_class()`.
84
     */
85
    public static function className()
86
    {
87
        return get_called_class();
88
    }
89
90
    /**
91
     * Constructor.
92
     * The default implementation does two things:
93
     *
94
     * - Initializes the object with the given configuration `$config`.
95
     * - Call [[init()]].
96
     *
97
     * If this method is overridden in a child class, it is recommended that
98
     *
99
     * - the last parameter of the constructor is a configuration array, like `$config` here.
100
     * - call the parent implementation at the end of the constructor.
101
     *
102
     * @param array $config name-value pairs that will be used to initialize the object properties
103
     */
104 2214
    public function __construct($config = [])
105
    {
106 2214
        if (!empty($config)) {
107 2056
            Yii::configure($this, $config);
108 2056
        }
109 2214
        $this->init();
110 2214
    }
111
112
    /**
113
     * Initializes the object.
114
     * This method is invoked at the end of the constructor after the object is initialized with the
115
     * given configuration.
116
     */
117 2075
    public function init()
118
    {
119 2075
    }
120
121
    /**
122
     * Returns the value of an object property.
123
     *
124
     * Do not call this method directly as it is a PHP magic method that
125
     * will be implicitly called when executing `$value = $object->property;`.
126
     * @param string $name the property name
127
     * @return mixed the property value
128
     * @throws UnknownPropertyException if the property is not defined
129
     * @throws InvalidCallException if the property is write-only
130
     * @see __set()
131
     */
132 29
    public function __get($name)
133
    {
134 29
        $getter = 'get' . $name;
135 29
        if (method_exists($this, $getter)) {
136 28
            return $this->$getter();
137 2
        } elseif (method_exists($this, 'set' . $name)) {
138 1
            throw new InvalidCallException('Getting write-only property: ' . get_class($this) . '::' . $name);
139
        } else {
140 1
            throw new UnknownPropertyException('Getting unknown property: ' . get_class($this) . '::' . $name);
141
        }
142
    }
143
144
    /**
145
     * Sets value of an object property.
146
     *
147
     * Do not call this method directly as it is a PHP magic method that
148
     * will be implicitly called when executing `$object->property = $value;`.
149
     * @param string $name the property name or the event name
150
     * @param mixed $value the property value
151
     * @throws UnknownPropertyException if the property is not defined
152
     * @throws InvalidCallException if the property is read-only
153
     * @see __get()
154
     */
155 32
    public function __set($name, $value)
156
    {
157 32
        $setter = 'set' . $name;
158 32
        if (method_exists($this, $setter)) {
159 31
            $this->$setter($value);
160 32
        } elseif (method_exists($this, 'get' . $name)) {
161 1
            throw new InvalidCallException('Setting read-only property: ' . get_class($this) . '::' . $name);
162
        } else {
163 1
            throw new UnknownPropertyException('Setting unknown property: ' . get_class($this) . '::' . $name);
164
        }
165 31
    }
166
167
    /**
168
     * Checks if a property is set, i.e. defined and not null.
169
     *
170
     * Do not call this method directly as it is a PHP magic method that
171
     * will be implicitly called when executing `isset($object->property)`.
172
     *
173
     * Note that if the property is not defined, false will be returned.
174
     * @param string $name the property name or the event name
175
     * @return boolean whether the named property is set (not null).
176
     * @see http://php.net/manual/en/function.isset.php
177
     */
178 2
    public function __isset($name)
179
    {
180 2
        $getter = 'get' . $name;
181 2
        if (method_exists($this, $getter)) {
182 2
            return $this->$getter() !== null;
183
        } else {
184 1
            return false;
185
        }
186
    }
187
188
    /**
189
     * Sets an object property to null.
190
     *
191
     * Do not call this method directly as it is a PHP magic method that
192
     * will be implicitly called when executing `unset($object->property)`.
193
     *
194
     * Note that if the property is not defined, this method will do nothing.
195
     * If the property is read-only, it will throw an exception.
196
     * @param string $name the property name
197
     * @throws InvalidCallException if the property is read only.
198
     * @see http://php.net/manual/en/function.unset.php
199
     */
200 2
    public function __unset($name)
201
    {
202 2
        $setter = 'set' . $name;
203 2
        if (method_exists($this, $setter)) {
204 1
            $this->$setter(null);
205 2
        } elseif (method_exists($this, 'get' . $name)) {
206 1
            throw new InvalidCallException('Unsetting read-only property: ' . get_class($this) . '::' . $name);
207
        }
208 1
    }
209
210
    /**
211
     * Calls the named method which is not a class method.
212
     *
213
     * Do not call this method directly as it is a PHP magic method that
214
     * will be implicitly called when an unknown method is being invoked.
215
     * @param string $name the method name
216
     * @param array $params method parameters
217
     * @throws UnknownMethodException when calling unknown method
218
     * @return mixed the method return value
219
     */
220 28
    public function __call($name, $params)
221
    {
222 1
        throw new UnknownMethodException('Calling unknown method: ' . get_class($this) . "::$name()");
223 28
    }
224
225
    /**
226
     * Returns a value indicating whether a property is defined.
227
     * A property is defined if:
228
     *
229
     * - the class has a getter or setter method associated with the specified name
230
     *   (in this case, property name is case-insensitive);
231
     * - the class has a member variable with the specified name (when `$checkVars` is true);
232
     *
233
     * @param string $name the property name
234
     * @param boolean $checkVars whether to treat member variables as properties
235
     * @return boolean whether the property is defined
236
     * @see canGetProperty()
237
     * @see canSetProperty()
238
     */
239 1
    public function hasProperty($name, $checkVars = true)
240
    {
241 1
        return $this->canGetProperty($name, $checkVars) || $this->canSetProperty($name, false);
242
    }
243
244
    /**
245
     * Returns a value indicating whether a property can be read.
246
     * A property is readable if:
247
     *
248
     * - the class has a getter method associated with the specified name
249
     *   (in this case, property name is case-insensitive);
250
     * - the class has a member variable with the specified name (when `$checkVars` is true);
251
     *
252
     * @param string $name the property name
253
     * @param boolean $checkVars whether to treat member variables as properties
254
     * @return boolean whether the property can be read
255
     * @see canSetProperty()
256
     */
257 6
    public function canGetProperty($name, $checkVars = true)
258
    {
259 6
        return method_exists($this, 'get' . $name) || $checkVars && property_exists($this, $name);
260
    }
261
262
    /**
263
     * Returns a value indicating whether a property can be set.
264
     * A property is writable if:
265
     *
266
     * - the class has a setter method associated with the specified name
267
     *   (in this case, property name is case-insensitive);
268
     * - the class has a member variable with the specified name (when `$checkVars` is true);
269
     *
270
     * @param string $name the property name
271
     * @param boolean $checkVars whether to treat member variables as properties
272
     * @return boolean whether the property can be written
273
     * @see canGetProperty()
274
     */
275 5
    public function canSetProperty($name, $checkVars = true)
276
    {
277 5
        return method_exists($this, 'set' . $name) || $checkVars && property_exists($this, $name);
278
    }
279
280
    /**
281
     * Returns a value indicating whether a method is defined.
282
     *
283
     * The default implementation is a call to php function `method_exists()`.
284
     * You may override this method when you implemented the php magic method `__call()`.
285
     * @param string $name the method name
286
     * @return boolean whether the method is defined
287
     */
288 6
    public function hasMethod($name)
289
    {
290 6
        return method_exists($this, $name);
291
    }
292
}
293