Issues (321)

src/Value.php (1 issue)

1
<?php
2
3
namespace PhpXmlRpc;
4
5
use PhpXmlRpc\Exception\StateErrorException;
6
use PhpXmlRpc\Exception\TypeErrorException;
7
use PhpXmlRpc\Exception\ValueErrorException;
8
use PhpXmlRpc\Traits\CharsetEncoderAware;
9
use PhpXmlRpc\Traits\DeprecationLogger;
10
11
/**
12
 * This class enables the creation of values for XML-RPC, by encapsulating plain php values.
13
 *
14
 * @property Value[]|mixed $me deprecated - public access left in purely for BC. Access via scalarVal()/__construct()
15
 * @property int $params $mytype - public access left in purely for BC. Access via kindOf()/__construct()
16
 * @property string|null $_php_class deprecated - public access left in purely for BC.
17
 */
18
class Value implements \Countable, \IteratorAggregate, \ArrayAccess
19
{
20
    use CharsetEncoderAware;
21
    use DeprecationLogger;
22
23
    public static $xmlrpcI4 = "i4";
24
    public static $xmlrpcI8 = "i8";
25
    public static $xmlrpcInt = "int";
26
    public static $xmlrpcBoolean = "boolean";
27
    public static $xmlrpcDouble = "double";
28
    public static $xmlrpcString = "string";
29
    public static $xmlrpcDateTime = "dateTime.iso8601";
30
    public static $xmlrpcBase64 = "base64";
31
    public static $xmlrpcArray = "array";
32
    public static $xmlrpcStruct = "struct";
33
    public static $xmlrpcValue = "undefined";
34
    public static $xmlrpcNull = "null";
35
36
    public static $xmlrpcTypes = array(
37
        "i4" => 1,
38
        "i8" => 1,
39
        "int" => 1,
40
        "boolean" => 1,
41
        "double" => 1,
42
        "string" => 1,
43
        "dateTime.iso8601" => 1,
44
        "base64" => 1,
45
        "array" => 2,
46
        "struct" => 3,
47
        "null" => 1,
48
    );
49
50
    /** @var Value[]|mixed */
51
    protected $me = array();
52
    /**
53
     * @var int 0 for undef, 1 for scalar, 2 for array, 3 for struct
54 1
     */
55
    protected $mytype = 0;
56 1
    /** @var string|null */
57 1
    protected $_php_class = null;
58
59 1
    /**
60
     * Build an xml-rpc value.
61
     *
62
     * When no value or type is passed in, the value is left uninitialized, and the value can be added later.
63
     *
64
     * @param Value[]|mixed $val if passing in an array, all array elements should be PhpXmlRpc\Value themselves
65
     * @param string $type any valid xml-rpc type name (lowercase): i4, int, boolean, string, double, dateTime.iso8601,
66
     *                     base64, array, struct, null.
67 594
     *                     If null, 'string' is assumed.
68
     *                     You should refer to http://xmlrpc.com/spec.md for more information on what each of these mean.
69 594
     */
70 435
    public function __construct($val = -1, $type = '')
71
    {
72 594
        // optimization creep - do not call addXX, do it all inline.
73
        // downside: booleans will not be coerced anymore
74
        if ($val !== -1 || $type != '') {
75
            switch ($type) {
76
                case '':
77
                    $this->mytype = 1;
78
                    $this->me['string'] = $val;
79
                    break;
80
                case 'i4':
81
                case 'i8':
82
                case 'int':
83
                case 'double':
84
                case 'string':
85
                case 'boolean':
86
                case 'dateTime.iso8601':
87
                case 'base64':
88
                case 'null':
89
                    $this->mytype = 1;
90
                    $this->me[$type] = $val;
91 746
                    break;
92
                case 'array':
93
                    $this->mytype = 2;
94
                    $this->me['array'] = $val;
95 746
                    break;
96 745
                case 'struct':
97 745
                    $this->mytype = 3;
98 251
                    $this->me['struct'] = $val;
99 251
                    break;
100 251
                default:
101 743
                    $this->getLogger()->error("XML-RPC: " . __METHOD__ . ": not a known type ($type)");
102 743
            }
103 743
        }
104 698
    }
105 677
106 469
    /**
107 448
     * Add a single php value to an xml-rpc value.
108 425
     *
109 404
     * If the xml-rpc value is an array, the php value is added as its last element.
110 717
     * If the xml-rpc value is empty (uninitialized), this method makes it a scalar value, and sets that value.
111 717
     * Fails if the xml-rpc value is not an array (i.e. a struct or a scalar) and already initialized.
112 717
     *
113 403
     * @param mixed $val
114 241
     * @param string $type allowed values: i4, i8, int, boolean, string, double, dateTime.iso8601, base64, null.
115 241
     * @return int 1 or 0 on failure
116 241
     *
117 295
     * @todo arguably, as we have addArray to add elements to an Array value, and addStruct to add elements to a Struct
118 295
     *       value, we should not allow this method to add values to an Array. The 'scalar' in the method name refers to
119 295
     *       the expected state of the target object, not to the type of $val. Also, this works differently from
120 295
     *       addScalar/addStruct in that, when adding an element to an array, it wraps it into a new Value
121
     * @todo rename?
122
     */
123
    public function addScalar($val, $type = 'string')
124
    {
125 746
        $typeOf = null;
126
        if (isset(static::$xmlrpcTypes[$type])) {
127
            $typeOf = static::$xmlrpcTypes[$type];
128
        }
129
130
        if ($typeOf !== 1) {
131
            $this->getLogger()->error("XML-RPC: " . __METHOD__ . ": not a scalar type ($type)");
132
            return 0;
133
        }
134
135
        // coerce booleans into correct values
136
        /// @todo we should either do it for datetimes, integers, i8 and doubles, too, or just plain remove this check,
137
        ///       implemented on booleans only...
138
        if ($type == static::$xmlrpcBoolean) {
139 1
            if (strcasecmp($val, 'true') == 0 || $val == 1 || ($val == true && strcasecmp($val, 'false'))) {
140
                $val = true;
141 1
            } else {
142 1
                $val = false;
143 1
            }
144
        }
145
146 1
        switch ($this->mytype) {
147
            case 1:
148
                $this->getLogger()->error('XML-RPC: ' . __METHOD__ . ': scalar xmlrpc value can have only one value');
149
                return 0;
150
            case 3:
151
                $this->getLogger()->error('XML-RPC: ' . __METHOD__ . ': cannot add anonymous scalar to struct xmlrpc value');
152
                return 0;
153
            case 2:
154 1
                // we're adding a scalar value to an array here
155
                /// @todo should we try avoiding re-wrapping Value objects?
156
                $class = get_class($this);
157
                $this->me['array'][] = new $class($val, $type);
158
159
                return 1;
160
            default:
161
                // a scalar, so set the value and remember we're scalar
162 1
                $this->me[$type] = $val;
163 1
                $this->mytype = $typeOf;
164
165
                return 1;
166 1
        }
167 1
    }
168 1
169
    /**
170
     * Add an array of xml-rpc value objects to an xml-rpc value.
171
     *
172
     * If the xml-rpc value is an array, the elements are appended to the existing ones.
173
     * If the xml-rpc value is empty (uninitialized), this method makes it an array value, and sets that value.
174
     * Fails otherwise.
175
     *
176
     * @param Value[] $values
177
     * @return int 1 or 0 on failure
178
     *
179
     * @todo add some checking for $values to be an array of xml-rpc values?
180
     * @todo rename to addToArray?
181
     */
182
    public function addArray($values)
183
    {
184
        if ($this->mytype == 0) {
185
            $this->mytype = static::$xmlrpcTypes['array'];
186
            $this->me['array'] = $values;
187
188
            return 1;
189
        } elseif ($this->mytype == 2) {
190
            // we're adding to an array here
191
            $this->me['array'] = array_merge($this->me['array'], $values);
192
193
            return 1;
194
        } else {
195
            $this->getLogger()->error('XML-RPC: ' . __METHOD__ . ': already initialized as a [' . $this->kindOf() . ']');
196 1
            return 0;
197
        }
198 1
    }
199
200
    /**
201
     * Merges an array of named xml-rpc value objects into an xml-rpc value.
202
     *
203 1
     * If the xml-rpc value is a struct, the elements are merged with the existing ones (overwriting existing ones).
204
     * If the xml-rpc value is empty (uninitialized), this method makes it a struct value, and sets that value.
205 1
     * Fails otherwise.
206
     *
207 1
     * @param Value[] $values
208
     * @return int 1 or 0 on failure
209
     *
210
     * @todo add some checking for $values to be an array of xml-rpc values?
211
     * @todo rename to addToStruct?
212
     */
213
    public function addStruct($values)
214
    {
215
        if ($this->mytype == 0) {
216
            $this->mytype = static::$xmlrpcTypes['struct'];
217
            $this->me['struct'] = $values;
218
219
            return 1;
220
        } elseif ($this->mytype == 3) {
221
            // we're adding to a struct here
222
            $this->me['struct'] = array_merge($this->me['struct'], $values);
223
224
            return 1;
225
        } else {
226
            $this->getLogger()->error('XML-RPC: ' . __METHOD__ . ': already initialized as a [' . $this->kindOf() . ']');
227 1
            return 0;
228
        }
229 1
    }
230
231
    /**
232
     * Returns a string describing the base type of the value.
233
     *
234 1
     * @return string either "struct", "array", "scalar" or "undef"
235
     */
236 1
    public function kindOf()
237
    {
238 1
        switch ($this->mytype) {
239
            case 3:
240
                return 'struct';
241
            case 2:
242
                return 'array';
243
            case 1:
244
                return 'scalar';
245
            default:
246
                return 'undef';
247
        }
248
    }
249
250 627
251
    /**
252 627
     * Returns the value of a scalar xml-rpc value (base 64 decoding is automatically handled here)
253 627
     *
254 150
     * @return mixed
255 606
     */
256 214
    public function scalarVal()
257 583
    {
258 583
        $b = reset($this->me);
259
260
        return $b;
261
    }
262
263
    /**
264
     * Returns the type of the xml-rpc value.
265
     *
266
     * @return string For integers, 'int' is always returned in place of 'i4'. 'i8' is considered a separate type and
267
     *                returned as such
268
     */
269
    public function scalarTyp()
270 705
    {
271
        reset($this->me);
272 705
        $a = key($this->me);
273
        if ($a == static::$xmlrpcI4) {
274 705
            $a = static::$xmlrpcInt;
275 2
        }
276
277
        return $a;
278 705
    }
279 705
280
    /**
281 684
     * Returns the xml representation of the value. XML prologue not included.
282 23
     *
283 23
     * @param string $charsetEncoding the charset to be used for serialization. If null, US-ASCII is assumed
284 684
     * @return string
285 46
     */
286 46
    public function serialize($charsetEncoding = '')
287 663
    {
288
        $val = reset($this->me);
289 573
        $typ = key($this->me);
290 573
291 474
        return '<value>' . $this->serializeData($typ, $val, $charsetEncoding) . "</value>\n";
292 68
    }
293 68
294 430
    /**
295 430
     * @param string $typ
296 68
     * @param Value[]|mixed $val
297
     * @param string $charsetEncoding
298
     * @return string
299
     *
300
     * @deprecated this should be folded back into serialize()
301
     */
302 24
    protected function serializeData($typ, $val, $charsetEncoding = '')
303 24
    {
304 47
        $this->logDeprecationUnlessCalledBy('serialize');
305 25
306 24
        if (!isset(static::$xmlrpcTypes[$typ])) {
307 23
            return '';
308 22
        }
309 23
310 23
        switch (static::$xmlrpcTypes[$typ]) {
311
            case 1:
312
                switch ($typ) {
313
                    case static::$xmlrpcBase64:
314
                        $rs = "<{$typ}>" . base64_encode($val) . "</{$typ}>";
0 ignored issues
show
It seems like $val can also be of type PhpXmlRpc\Value[]; however, parameter $string of base64_encode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

314
                        $rs = "<{$typ}>" . base64_encode(/** @scrutinizer ignore-type */ $val) . "</{$typ}>";
Loading history...
315 25
                        break;
316 23
                    case static::$xmlrpcBoolean:
317 23
                        $rs = "<{$typ}>" . ($val ? '1' : '0') . "</{$typ}>";
318 23
                        break;
319
                    case static::$xmlrpcString:
320 1
                        // Do NOT use htmlentities, since it will produce named html entities, which are invalid xml
321
                        $rs = "<{$typ}>" . $this->getCharsetEncoder()->encodeEntities($val, PhpXmlRpc::$xmlrpc_internalencoding, $charsetEncoding) . "</{$typ}>";
322 23
                        break;
323
                    case static::$xmlrpcInt:
324
                    case static::$xmlrpcI4:
325
                    case static::$xmlrpcI8:
326
                        $rs = "<{$typ}>" . (int)$val . "</{$typ}>";
327
                        break;
328 684
                    case static::$xmlrpcDouble:
329 218
                        // avoid using standard conversion of float to string because it is locale-dependent,
330
                        // and also because the xml-rpc spec forbids exponential notation.
331 133
                        // sprintf('%F') could be most likely ok, but it fails e.g. on 2e-14.
332 1
                        // The code below tries its best at keeping max precision while avoiding exp notation,
333
                        // but there is of course no limit in the number of decimal places to be used...
334 133
                        $rs = "<{$typ}>" . preg_replace('/\\.?0+$/', '', number_format((double)$val, PhpXmlRpc::$xmlpc_double_precision, '.', '')) . "</{$typ}>";
335
                        break;
336 133
                    case static::$xmlrpcDateTime:
337
                        if (is_string($val)) {
338 133
                            $rs = "<{$typ}>{$val}</{$typ}>";
339 112
                        // DateTimeInterface is not present in php 5.4...
340
                        } elseif (is_a($val, 'DateTimeInterface') || is_a($val, 'DateTime')) {
341 112
                            $rs = "<{$typ}>" . $val->format('Ymd\TH:i:s') . "</{$typ}>";
342 112
                        } elseif (is_int($val)) {
343
                            $rs = "<{$typ}>" . date('Ymd\TH:i:s', $val) . "</{$typ}>";
344 133
                        } else {
345 133
                            // not really a good idea here: but what should we output anyway? left for backward compat...
346 154
                            $rs = "<{$typ}>{$val}</{$typ}>";
347
                        }
348 154
                        break;
349
                    case static::$xmlrpcNull:
350 154
                        if (PhpXmlRpc::$xmlrpc_null_apache_encoding) {
351
                            $rs = "<ex:nil/>";
352 154
                        } else {
353
                            $rs = "<nil/>";
354 154
                        }
355 154
                        break;
356
                    default:
357
                        // no standard type value should arrive here, but provide a possibility
358
                        // for xml-rpc values of unknown type...
359
                        $rs = "<{$typ}>{$val}</{$typ}>";
360 705
                }
361
                break;
362
            case 3:
363
                // struct
364
                if ($this->_php_class) {
365
                    $rs = '<struct php_class="' . $this->_php_class . "\">\n";
366
                } else {
367
                    $rs = "<struct>\n";
368
                }
369
                $charsetEncoder = $this->getCharsetEncoder();
370 705
                /** @var Value $val2 */
371
                foreach ($val as $key2 => $val2) {
372 705
                    $rs .= '<member><name>' . $charsetEncoder->encodeEntities($key2, PhpXmlRpc::$xmlrpc_internalencoding, $charsetEncoding) . "</name>\n";
373 705
                    $rs .= $val2->serialize($charsetEncoding);
374
                    $rs .= "</member>\n";
375 705
                }
376
                $rs .= '</struct>';
377
                break;
378
            case 2:
379
                // array
380
                $rs = "<array>\n<data>\n";
381
                /** @var Value $element */
382
                foreach ($val as $element) {
383
                    $rs .= $element->serialize($charsetEncoding);
384
                }
385
                $rs .= "</data>\n</array>";
386
                break;
387
            default:
388
                /// @todo log a warning?
389 2
                $rs = '';
390
                break;
391
        }
392
393 2
        return $rs;
394
    }
395
396
    /**
397
     * Returns the number of members in an xml-rpc value:
398
     * - 0 for uninitialized values
399
     * - 1 for scalar values
400
     * - the number of elements for struct and array values
401
     *
402
     * @return integer
403
     */
404
    #[\ReturnTypeWillChange]
405
    public function count()
406 29
    {
407
        switch ($this->mytype) {
408
            case 3:
409
                return count($this->me['struct']);
410 29
            case 2:
411
                return count($this->me['array']);
412
            case 1:
413
                return 1;
414
            default:
415
                return 0;
416
        }
417
    }
418
419
    /**
420
     * Implements the IteratorAggregate interface
421
     * @internal required to be public to implement an Interface
422
     *
423
     * @return \ArrayIterator
424
     */
425
    #[\ReturnTypeWillChange]
426
    public function getIterator()
427
    {
428
        switch ($this->mytype) {
429
            case 3:
430
                return new \ArrayIterator($this->me['struct']);
431
            case 2:
432
                return new \ArrayIterator($this->me['array']);
433
            case 1:
434
                return new \ArrayIterator($this->me);
435
            default:
436
                return new \ArrayIterator();
437
        }
438
    }
439
440
    /**
441
     * @internal required to be public to implement an Interface
442
     *
443
     * @param mixed $offset
444 660
     * @param mixed $value
445
     * @return void
446 660
     * @throws ValueErrorException|TypeErrorException
447
     */
448 660
    #[\ReturnTypeWillChange]
449
    public function offsetSet($offset, $value)
450
    {
451
        switch ($this->mytype) {
452
            case 3:
453
                if (!($value instanceof Value)) {
454
                    throw new TypeErrorException('It is only possible to add Value objects to an XML-RPC Struct');
455
                }
456
                if (is_null($offset)) {
457
                    // disallow struct members with empty names
458 454
                    throw new ValueErrorException('It is not possible to add anonymous members to an XML-RPC Struct');
459
                } else {
460 454
                    $this->me['struct'][$offset] = $value;
461 454
                }
462 454
                return;
463
            case 2:
464
                if (!($value instanceof Value)) {
465
                    throw new TypeErrorException('It is only possible to add Value objects to an XML-RPC Array');
466 454
                }
467
                if (is_null($offset)) {
468
                    $this->me['array'][] = $value;
469
                } else {
470
                    // nb: we are not checking that $offset is above the existing array range...
471
                    $this->me['array'][$offset] = $value;
472
                }
473
                return;
474
            case 1:
475
                /// @todo: should we handle usage of i4 to retrieve int (in both set/unset/isset)? After all we consider
476
                ///        'int' to be the preferred form, as evidenced in scalarTyp()
477
                reset($this->me);
478 43
                $type = key($this->me);
479
                if ($type != $offset && ($type != 'i4' || $offset != 'int')) {
480
                    throw new ValueErrorException('...');
481
                }
482 43
                $this->me[$type] = $value;
483
                return;
484
            default:
485
                // it would be nice to allow empty values to be turned into non-empty ones this way, but we miss info to do so
486
                throw new ValueErrorException("XML-RPC Value is of type 'undef' and its value can not be set using array index");
487
        }
488
    }
489
490
    /**
491
     * @internal required to be public to implement an Interface
492 44
     *
493
     * @param mixed $offset
494
     * @return bool
495
     */
496 44
    #[\ReturnTypeWillChange]
497
    public function offsetExists($offset)
498
    {
499
        switch ($this->mytype) {
500
            case 3:
501
                return isset($this->me['struct'][$offset]);
502
            case 2:
503
                return isset($this->me['array'][$offset]);
504
            case 1:
505
                // handle i4 vs int
506 23
                if ($offset == 'i4') {
507
                    // to be consistent with set and unset, we disallow usage of i4 to check for int
508
                    reset($this->me);
509
                    return $offset == key($this->me);
510 23
                } else {
511
                    return $offset == $this->scalarTyp();
512
                }
513
            default:
514
                return false;
515
        }
516
    }
517
518
    /**
519
     * @internal required to be public to implement an Interface
520
     *
521
     * @param mixed $offset
522 25
     * @return void
523
     * @throws ValueErrorException|StateErrorException
524 25
     */
525 25
    #[\ReturnTypeWillChange]
526
    public function offsetUnset($offset)
527 25
    {
528 25
        switch ($this->mytype) {
529
            case 3:
530
                unset($this->me['struct'][$offset]);
531
                return;
532
            case 2:
533
                unset($this->me['array'][$offset]);
534
                return;
535
            case 1:
536
                // can not remove value from a scalar
537
                /// @todo feature creep - allow this to move back the value to 'undef' state?
538
                throw new StateErrorException("XML-RPC Value is of type 'scalar' and its value can not be unset using array index");
539
            default:
540
                throw new StateErrorException("XML-RPC Value is of type 'undef' and its value can not be unset using array index");
541
        }
542
    }
543 258
544
    /**
545 258
     * @internal required to be public to implement an Interface
546 258
     *
547 65
     * @param mixed $offset
548 215
     * @return mixed|Value|null
549 215
     * @throws StateErrorException
550
     */
551
    #[\ReturnTypeWillChange]
552
    public function offsetGet($offset)
553
    {
554
        switch ($this->mytype) {
555
            case 3:
556
                return isset($this->me['struct'][$offset]) ? $this->me['struct'][$offset] : null;
557
            case 2:
558
                return isset($this->me['array'][$offset]) ? $this->me['array'][$offset] : null;
559
            case 1:
560
                /// @todo what to return on bad type: null or exception?
561
                $value = reset($this->me);
562
                $type = key($this->me);
563
                return $type == $offset ? $value : (($type == 'i4' && $offset == 'int') ? $value : null);
564 22
            default:
565
                // return null or exception?
566 22
                throw new StateErrorException("XML-RPC Value is of type 'undef' and can not be accessed using array index");
567 22
        }
568
    }
569
570
    // *** BC layer ***
571
572
    /**
573
     * Checks whether a struct member with a given name is present.
574
     *
575
     * Works only on xml-rpc values of type struct.
576
     *
577
     * @param string $key the name of the struct member to be looked up
578 22
     * @return boolean
579 22
     *
580
     * @deprecated use array access, e.g. isset($val[$key])
581
     */
582 22
    public function structMemExists($key)
583 22
    {
584
        $this->logDeprecation('Method ' . __METHOD__ . ' is deprecated');
585
586
        return array_key_exists($key, $this->me['struct']);
587
    }
588 22
589
    /**
590
     * Returns the value of a given struct member (an xml-rpc value object in itself).
591
     * Will raise a php warning if struct member of given name does not exist.
592
     *
593
     * @param string $key the name of the struct member to be looked up
594
     * @return Value
595
     *
596
     * @deprecated use array access, e.g. $val[$key]
597
     */
598
    public function structMem($key)
599
    {
600
        $this->logDeprecation('Method ' . __METHOD__ . ' is deprecated');
601
602
        return $this->me['struct'][$key];
603
    }
604
605
    /**
606
     * Reset internal pointer for xml-rpc values of type struct.
607
     * @return void
608
     *
609
     * @deprecated iterate directly over the object using foreach instead
610
     */
611
    public function structReset()
612
    {
613
        $this->logDeprecation('Method ' . __METHOD__ . ' is deprecated');
614
615
        reset($this->me['struct']);
616
    }
617
618
    /**
619
     * Return next member element for xml-rpc values of type struct.
620
     *
621
     * @return array having the same format as PHP's `each` method
622
     *
623
     * @deprecated iterate directly over the object using foreach instead
624
     */
625
    public function structEach()
626
    {
627
        $this->logDeprecation('Method ' . __METHOD__ . ' is deprecated');
628
629
        $key = key($this->me['struct']);
630
        $value = current($this->me['struct']);
631
        next($this->me['struct']);
632
        return array(1 => $value, 'value' => $value, 0 => $key, 'key' => $key);
633
    }
634
635
    /**
636
     * Returns the n-th member of an xml-rpc value of array type.
637
     *
638
     * @param integer $key the index of the value to be retrieved (zero based)
639
     *
640
     * @return Value
641
     *
642
     * @deprecated use array access, e.g. $val[$key]
643
     */
644
    public function arrayMem($key)
645
    {
646
        $this->logDeprecation('Method ' . __METHOD__ . ' is deprecated');
647
648
        return $this->me['array'][$key];
649
    }
650
651
    /**
652
     * Returns the number of members in an xml-rpc value of array type.
653
     *
654
     * @return integer
655 175
     *
656
     * @deprecated use count() instead
657 175
     */
658 175
    public function arraySize()
659 173
    {
660 24
        $this->logDeprecation('Method ' . __METHOD__ . ' is deprecated');
661 24
662
        return count($this->me['array']);
663
    }
664
665
    /**
666
     * Returns the number of members in an xml-rpc value of struct type.
667
     *
668
     * @return integer
669
     *
670
     * @deprecated use count() instead
671
     */
672
    public function structSize()
673
    {
674
        $this->logDeprecation('Method ' . __METHOD__ . ' is deprecated');
675
676
        return count($this->me['struct']);
677
    }
678
679
    // we have to make this return by ref in order to allow calls such as `$resp->_cookies['name'] = ['value' => 'something'];`
680
    public function &__get($name)
681
    {
682
        switch ($name) {
683
            case 'me':
684
            case 'mytype':
685
            case '_php_class':
686
                $this->logDeprecation('Getting property Value::' . $name . ' is deprecated');
687
                return $this->$name;
688
            default:
689
                /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout...
690
                $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
691
                trigger_error('Undefined property via __get(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING);
692
                $result = null;
693
                return $result;
694
        }
695
    }
696
697
    public function __set($name, $value)
698
    {
699
        switch ($name) {
700
            case 'me':
701
            case 'mytype':
702
            case '_php_class':
703
                $this->logDeprecation('Setting property Value::' . $name . ' is deprecated');
704
                $this->$name = $value;
705
                break;
706
            default:
707
                /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout...
708
                $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
709
                trigger_error('Undefined property via __set(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING);
710
        }
711
    }
712
713
    public function __isset($name)
714
    {
715
        switch ($name) {
716
            case 'me':
717
            case 'mytype':
718
            case '_php_class':
719
                $this->logDeprecation('Checking property Value::' . $name . ' is deprecated');
720
                return isset($this->$name);
721
            default:
722
                return false;
723
        }
724
    }
725
726
    public function __unset($name)
727
    {
728
        switch ($name) {
729
            case 'me':
730
            case 'mytype':
731
            case '_php_class':
732
                $this->logDeprecation('Unsetting property Value::' . $name . ' is deprecated');
733
                unset($this->$name);
734
                break;
735
            default:
736
                /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout...
737
                $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
738
                trigger_error('Undefined property via __unset(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING);
739
        }
740
    }
741
}
742