Completed
Pull Request — master (#16756)
by Vladimir
13:05
created

BaseObject::__isset()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2.032

Importance

Changes 0
Metric Value
dl 0
loc 9
ccs 4
cts 5
cp 0.8
rs 9.9666
c 0
b 0
f 0
cc 2
nc 2
nop 1
crap 2.032
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
     * @deprecated since 2.0.14. On PHP >=5.5, use `::class` instead.
83
     */
84
    public static function className()
85
    {
86
        return get_called_class();
87
    }
88
89
    /**
90
     * Constructor.
91
     *
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 4047
    public function __construct($config = [])
105
    {
106 4047
        if (!empty($config)) {
107 3768
            Yii::configure($this, $config);
108
        }
109 4047
        $this->init();
110 4042
    }
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 3921
    public function init()
118
    {
119 3921
    }
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 69
    public function __get($name)
133
    {
134 69
        $getter = 'get' . $name;
135 69
        if (method_exists($this, $getter)) {
136 68
            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
        }
140
141 1
        throw new UnknownPropertyException('Getting unknown property: ' . get_class($this) . '::' . $name);
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 1
        } elseif (method_exists($this, 'get' . $name)) {
161 1
            throw new InvalidCallException('Setting read-only property: ' . get_class($this) . '::' . $name);
162
        }
163
164 31
        throw new UnknownPropertyException('Setting unknown property: ' . get_class($this) . '::' . $name);
165
    }
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 bool 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
        }
184
185
        return false;
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 1
        } 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 1
    public function __call($name, $params)
221
    {
222 1
        throw new UnknownMethodException('Calling unknown method: ' . get_class($this) . "::$name()");
223
    }
224
225
    /**
226
     * Returns a value indicating whether a property is defined.
227
     *
228
     * A property is defined if:
229
     *
230
     * - the class has a getter or setter method associated with the specified name
231
     *   (in this case, property name is case-insensitive);
232
     * - the class has a member variable with the specified name (when `$checkVars` is true);
233
     *
234
     * @param string $name the property name
235
     * @param bool $checkVars whether to treat member variables as properties
236
     * @return bool whether the property is defined
237
     * @see canGetProperty()
238
     * @see canSetProperty()
239
     */
240 1
    public function hasProperty($name, $checkVars = true)
241
    {
242 1
        return $this->canGetProperty($name, $checkVars) || $this->canSetProperty($name, false);
243
    }
244
245
    /**
246
     * Returns a value indicating whether a property can be read.
247
     *
248
     * A property is readable if:
249
     *
250
     * - the class has a getter method associated with the specified name
251
     *   (in this case, property name is case-insensitive);
252
     * - the class has a member variable with the specified name (when `$checkVars` is true);
253
     *
254
     * @param string $name the property name
255
     * @param bool $checkVars whether to treat member variables as properties
256
     * @return bool whether the property can be read
257
     * @see canSetProperty()
258
     */
259 7
    public function canGetProperty($name, $checkVars = true)
260
    {
261 7
        return method_exists($this, 'get' . $name) || $checkVars && property_exists($this, $name);
262
    }
263
264
    /**
265
     * Returns a value indicating whether a property can be set.
266
     *
267
     * A property is writable if:
268
     *
269
     * - the class has a setter method associated with the specified name
270
     *   (in this case, property name is case-insensitive);
271
     * - the class has a member variable with the specified name (when `$checkVars` is true);
272
     *
273
     * @param string $name the property name
274
     * @param bool $checkVars whether to treat member variables as properties
275
     * @return bool whether the property can be written
276
     * @see canGetProperty()
277
     */
278 7
    public function canSetProperty($name, $checkVars = true)
279
    {
280 7
        return method_exists($this, 'set' . $name) || $checkVars && property_exists($this, $name);
281
    }
282
283
    /**
284
     * Returns a value indicating whether a method is defined.
285
     *
286
     * The default implementation is a call to php function `method_exists()`.
287
     * You may override this method when you implemented the php magic method `__call()`.
288
     * @param string $name the method name
289
     * @return bool whether the method is defined
290
     */
291 14
    public function hasMethod($name)
292
    {
293 14
        return method_exists($this, $name);
294
    }
295
}
296