Completed
Push — master ( 000192...393fc2 )
by Carsten
15:23
created

BaseObject::canSetProperty()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 3
eloc 2
nc 3
nop 2
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
 * BaseObject 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, BaseObject also introduces an important object initialization life cycle. In particular,
50
 * creating an new instance of BaseObject 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 BaseObject 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.13
76
 */
77
class BaseObject implements Configurable
78
{
79
    /**
80
     * Returns the fully qualified name of this class.
81
     * @return string the fully qualified name of this class.
82
     */
83 961
    public static function className()
84
    {
85 961
        return get_called_class();
86
    }
87
88
    /**
89
     * Constructor.
90
     * The default implementation does two things:
91
     *
92
     * - Initializes the object with the given configuration `$config`.
93
     * - Call [[init()]].
94
     *
95
     * If this method is overridden in a child class, it is recommended that
96
     *
97
     * - the last parameter of the constructor is a configuration array, like `$config` here.
98
     * - call the parent implementation at the end of the constructor.
99
     *
100
     * @param array $config name-value pairs that will be used to initialize the object properties
101
     */
102 3323
    public function __construct($config = [])
103
    {
104 3323
        if (!empty($config)) {
105 3087
            Yii::configure($this, $config);
106
        }
107 3323
        $this->init();
108 3318
    }
109
110
    /**
111
     * Initializes the object.
112
     * This method is invoked at the end of the constructor after the object is initialized with the
113
     * given configuration.
114
     */
115 3152
    public function init()
116
    {
117 3152
    }
118
119
    /**
120
     * Returns the value of an object property.
121
     *
122
     * Do not call this method directly as it is a PHP magic method that
123
     * will be implicitly called when executing `$value = $object->property;`.
124
     * @param string $name the property name
125
     * @return mixed the property value
126
     * @throws UnknownPropertyException if the property is not defined
127
     * @throws InvalidCallException if the property is write-only
128
     * @see __set()
129
     */
130 61
    public function __get($name)
131
    {
132 61
        $getter = 'get' . $name;
133 61
        if (method_exists($this, $getter)) {
134 60
            return $this->$getter();
135 2
        } elseif (method_exists($this, 'set' . $name)) {
136 1
            throw new InvalidCallException('Getting write-only property: ' . get_class($this) . '::' . $name);
137
        }
138
139 1
        throw new UnknownPropertyException('Getting unknown property: ' . get_class($this) . '::' . $name);
140
    }
141
142
    /**
143
     * Sets value of an object property.
144
     *
145
     * Do not call this method directly as it is a PHP magic method that
146
     * will be implicitly called when executing `$object->property = $value;`.
147
     * @param string $name the property name or the event name
148
     * @param mixed $value the property value
149
     * @throws UnknownPropertyException if the property is not defined
150
     * @throws InvalidCallException if the property is read-only
151
     * @see __get()
152
     */
153 31
    public function __set($name, $value)
154
    {
155 31
        $setter = 'set' . $name;
156 31
        if (method_exists($this, $setter)) {
157 30
            $this->$setter($value);
158 2
        } elseif (method_exists($this, 'get' . $name)) {
159 1
            throw new InvalidCallException('Setting read-only property: ' . get_class($this) . '::' . $name);
160
        } else {
161 1
            throw new UnknownPropertyException('Setting unknown property: ' . get_class($this) . '::' . $name);
162
        }
163 30
    }
164
165
    /**
166
     * Checks if a property is set, i.e. defined and not null.
167
     *
168
     * Do not call this method directly as it is a PHP magic method that
169
     * will be implicitly called when executing `isset($object->property)`.
170
     *
171
     * Note that if the property is not defined, false will be returned.
172
     * @param string $name the property name or the event name
173
     * @return bool whether the named property is set (not null).
174
     * @see http://php.net/manual/en/function.isset.php
175
     */
176 2
    public function __isset($name)
177
    {
178 2
        $getter = 'get' . $name;
179 2
        if (method_exists($this, $getter)) {
180 2
            return $this->$getter() !== null;
181
        }
182
183 1
        return false;
184
    }
185
186
    /**
187
     * Sets an object property to null.
188
     *
189
     * Do not call this method directly as it is a PHP magic method that
190
     * will be implicitly called when executing `unset($object->property)`.
191
     *
192
     * Note that if the property is not defined, this method will do nothing.
193
     * If the property is read-only, it will throw an exception.
194
     * @param string $name the property name
195
     * @throws InvalidCallException if the property is read only.
196
     * @see http://php.net/manual/en/function.unset.php
197
     */
198 2
    public function __unset($name)
199
    {
200 2
        $setter = 'set' . $name;
201 2
        if (method_exists($this, $setter)) {
202 1
            $this->$setter(null);
203 1
        } elseif (method_exists($this, 'get' . $name)) {
204 1
            throw new InvalidCallException('Unsetting read-only property: ' . get_class($this) . '::' . $name);
205
        }
206 1
    }
207
208
    /**
209
     * Calls the named method which is not a class method.
210
     *
211
     * Do not call this method directly as it is a PHP magic method that
212
     * will be implicitly called when an unknown method is being invoked.
213
     * @param string $name the method name
214
     * @param array $params method parameters
215
     * @throws UnknownMethodException when calling unknown method
216
     * @return mixed the method return value
217
     */
218 1
    public function __call($name, $params)
219
    {
220 1
        throw new UnknownMethodException('Calling unknown method: ' . get_class($this) . "::$name()");
221
    }
222
223
    /**
224
     * Returns a value indicating whether a property is defined.
225
     * A property is defined if:
226
     *
227
     * - the class has a getter or setter method associated with the specified name
228
     *   (in this case, property name is case-insensitive);
229
     * - the class has a member variable with the specified name (when `$checkVars` is true);
230
     *
231
     * @param string $name the property name
232
     * @param bool $checkVars whether to treat member variables as properties
233
     * @return bool whether the property is defined
234
     * @see canGetProperty()
235
     * @see canSetProperty()
236
     */
237 1
    public function hasProperty($name, $checkVars = true)
238
    {
239 1
        return $this->canGetProperty($name, $checkVars) || $this->canSetProperty($name, false);
240
    }
241
242
    /**
243
     * Returns a value indicating whether a property can be read.
244
     * A property is readable if:
245
     *
246
     * - the class has a getter method associated with the specified name
247
     *   (in this case, property name is case-insensitive);
248
     * - the class has a member variable with the specified name (when `$checkVars` is true);
249
     *
250
     * @param string $name the property name
251
     * @param bool $checkVars whether to treat member variables as properties
252
     * @return bool whether the property can be read
253
     * @see canSetProperty()
254
     */
255 7
    public function canGetProperty($name, $checkVars = true)
256
    {
257 7
        return method_exists($this, 'get' . $name) || $checkVars && property_exists($this, $name);
258
    }
259
260
    /**
261
     * Returns a value indicating whether a property can be set.
262
     * A property is writable if:
263
     *
264
     * - the class has a setter method associated with the specified name
265
     *   (in this case, property name is case-insensitive);
266
     * - the class has a member variable with the specified name (when `$checkVars` is true);
267
     *
268
     * @param string $name the property name
269
     * @param bool $checkVars whether to treat member variables as properties
270
     * @return bool whether the property can be written
271
     * @see canGetProperty()
272
     */
273 5
    public function canSetProperty($name, $checkVars = true)
274
    {
275 5
        return method_exists($this, 'set' . $name) || $checkVars && property_exists($this, $name);
276
    }
277
278
    /**
279
     * Returns a value indicating whether a method is defined.
280
     *
281
     * The default implementation is a call to php function `method_exists()`.
282
     * You may override this method when you implemented the php magic method `__call()`.
283
     * @param string $name the method name
284
     * @return bool whether the method is defined
285
     */
286 10
    public function hasMethod($name)
287
    {
288 10
        return method_exists($this, $name);
289
    }
290
}
291