Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.3.x will end 7 October 2024 (12 months).
  • Bug fixes for security issues in 4.3.x will end 21 April 2025 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.2.x is supported too.

Differences Between: [Versions 401 and 403]

   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       */
  55      protected $mytype = 0;
  56      /** @var string|null */
  57      protected $_php_class = null;
  58  
  59      /**
  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       *                     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       */
  70      public function __construct($val = -1, $type = '')
  71      {
  72          // 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                      break;
  92                  case 'array':
  93                      $this->mytype = 2;
  94                      $this->me['array'] = $val;
  95                      break;
  96                  case 'struct':
  97                      $this->mytype = 3;
  98                      $this->me['struct'] = $val;
  99                      break;
 100                  default:
 101                      $this->getLogger()->error("XML-RPC: " . __METHOD__ . ": not a known type ($type)");
 102              }
 103          }
 104      }
 105  
 106      /**
 107       * Add a single php value to an xml-rpc value.
 108       *
 109       * If the xml-rpc value is an array, the php value is added as its last element.
 110       * If the xml-rpc value is empty (uninitialized), this method makes it a scalar value, and sets that value.
 111       * Fails if the xml-rpc value is not an array (i.e. a struct or a scalar) and already initialized.
 112       *
 113       * @param mixed $val
 114       * @param string $type allowed values: i4, i8, int, boolean, string, double, dateTime.iso8601, base64, null.
 115       * @return int 1 or 0 on failure
 116       *
 117       * @todo arguably, as we have addArray to add elements to an Array value, and addStruct to add elements to a Struct
 118       *       value, we should not allow this method to add values to an Array. The 'scalar' in the method name refers to
 119       *       the expected state of the target object, not to the type of $val. Also, this works differently from
 120       *       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          $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              if (strcasecmp($val, 'true') == 0 || $val == 1 || ($val == true && strcasecmp($val, 'false'))) {
 140                  $val = true;
 141              } else {
 142                  $val = false;
 143              }
 144          }
 145  
 146          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                  // 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                  $this->me[$type] = $val;
 163                  $this->mytype = $typeOf;
 164  
 165                  return 1;
 166          }
 167      }
 168  
 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              return 0;
 197          }
 198      }
 199  
 200      /**
 201       * Merges an array of named xml-rpc value objects into an xml-rpc value.
 202       *
 203       * 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       * Fails otherwise.
 206       *
 207       * @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              return 0;
 228          }
 229      }
 230  
 231      /**
 232       * Returns a string describing the base type of the value.
 233       *
 234       * @return string either "struct", "array", "scalar" or "undef"
 235       */
 236      public function kindOf()
 237      {
 238          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  
 251      /**
 252       * Returns the value of a scalar xml-rpc value (base 64 decoding is automatically handled here)
 253       *
 254       * @return mixed
 255       */
 256      public function scalarVal()
 257      {
 258          $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      {
 271          reset($this->me);
 272          $a = key($this->me);
 273          if ($a == static::$xmlrpcI4) {
 274              $a = static::$xmlrpcInt;
 275          }
 276  
 277          return $a;
 278      }
 279  
 280      /**
 281       * Returns the xml representation of the value. XML prologue not included.
 282       *
 283       * @param string $charsetEncoding the charset to be used for serialization. If null, US-ASCII is assumed
 284       * @return string
 285       */
 286      public function serialize($charsetEncoding = '')
 287      {
 288          $val = reset($this->me);
 289          $typ = key($this->me);
 290  
 291          return '<value>' . $this->serializeData($typ, $val, $charsetEncoding) . "</value>\n";
 292      }
 293  
 294      /**
 295       * @param string $typ
 296       * @param Value[]|mixed $val
 297       * @param string $charsetEncoding
 298       * @return string
 299       *
 300       * @deprecated this should be folded back into serialize()
 301       */
 302      protected function serializeData($typ, $val, $charsetEncoding = '')
 303      {
 304          $this->logDeprecationUnlessCalledBy('serialize');
 305  
 306          if (!isset(static::$xmlrpcTypes[$typ])) {
 307              return '';
 308          }
 309  
 310          switch (static::$xmlrpcTypes[$typ]) {
 311              case 1:
 312                  switch ($typ) {
 313                      case static::$xmlrpcBase64:
 314                          $rs = "<{$typ}>" . base64_encode($val) . "</{$typ}>";
 315                          break;
 316                      case static::$xmlrpcBoolean:
 317                          $rs = "<{$typ}>" . ($val ? '1' : '0') . "</{$typ}>";
 318                          break;
 319                      case static::$xmlrpcString:
 320                          // 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                          break;
 323                      case static::$xmlrpcInt:
 324                      case static::$xmlrpcI4:
 325                      case static::$xmlrpcI8:
 326                          $rs = "<{$typ}>" . (int)$val . "</{$typ}>";
 327                          break;
 328                      case static::$xmlrpcDouble:
 329                          // 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                          // sprintf('%F') could be most likely ok, but it fails e.g. on 2e-14.
 332                          // 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                          $rs = "<{$typ}>" . preg_replace('/\\.?0+$/', '', number_format((double)$val, PhpXmlRpc::$xmlpc_double_precision, '.', '')) . "</{$typ}>";
 335                          break;
 336                      case static::$xmlrpcDateTime:
 337                          if (is_string($val)) {
 338                              $rs = "<{$typ}>{$val}</{$typ}>";
 339                          // DateTimeInterface is not present in php 5.4...
 340                          } elseif (is_a($val, 'DateTimeInterface') || is_a($val, 'DateTime')) {
 341                              $rs = "<{$typ}>" . $val->format('Ymd\TH:i:s') . "</{$typ}>";
 342                          } elseif (is_int($val)) {
 343                              $rs = "<{$typ}>" . date('Ymd\TH:i:s', $val) . "</{$typ}>";
 344                          } else {
 345                              // not really a good idea here: but what should we output anyway? left for backward compat...
 346                              $rs = "<{$typ}>{$val}</{$typ}>";
 347                          }
 348                          break;
 349                      case static::$xmlrpcNull:
 350                          if (PhpXmlRpc::$xmlrpc_null_apache_encoding) {
 351                              $rs = "<ex:nil/>";
 352                          } else {
 353                              $rs = "<nil/>";
 354                          }
 355                          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                  }
 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                  /** @var Value $val2 */
 371                  foreach ($val as $key2 => $val2) {
 372                      $rs .= '<member><name>' . $charsetEncoder->encodeEntities($key2, PhpXmlRpc::$xmlrpc_internalencoding, $charsetEncoding) . "</name>\n";
 373                      $rs .= $val2->serialize($charsetEncoding);
 374                      $rs .= "</member>\n";
 375                  }
 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                  $rs = '';
 390                  break;
 391          }
 392  
 393          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      {
 407          switch ($this->mytype) {
 408              case 3:
 409                  return count($this->me['struct']);
 410              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       * @param mixed $value
 445       * @return void
 446       *
 447       * @throws ValueErrorException|TypeErrorException
 448       */
 449      #[\ReturnTypeWillChange]
 450      public function offsetSet($offset, $value)
 451      {
 452          switch ($this->mytype) {
 453              case 3:
 454                  if (!($value instanceof Value)) {
 455                      throw new TypeErrorException('It is only possible to add Value objects to an XML-RPC Struct');
 456                  }
 457                  if (is_null($offset)) {
 458                      // disallow struct members with empty names
 459                      throw new ValueErrorException('It is not possible to add anonymous members to an XML-RPC Struct');
 460                  } else {
 461                      $this->me['struct'][$offset] = $value;
 462                  }
 463                  return;
 464              case 2:
 465                  if (!($value instanceof Value)) {
 466                      throw new TypeErrorException('It is only possible to add Value objects to an XML-RPC Array');
 467                  }
 468                  if (is_null($offset)) {
 469                      $this->me['array'][] = $value;
 470                  } else {
 471                      // nb: we are not checking that $offset is above the existing array range...
 472                      $this->me['array'][$offset] = $value;
 473                  }
 474                  return;
 475              case 1:
 476                  /// @todo: should we handle usage of i4 to retrieve int (in both set/unset/isset)? After all we consider
 477                  ///        'int' to be the preferred form, as evidenced in scalarTyp()
 478                  reset($this->me);
 479                  $type = key($this->me);
 480                  if ($type != $offset && ($type != 'i4' || $offset != 'int')) {
 481                      throw new ValueErrorException('...');
 482                  }
 483                  $this->me[$type] = $value;
 484                  return;
 485              default:
 486                  // it would be nice to allow empty values to be turned into non-empty ones this way, but we miss info to do so
 487                  throw new ValueErrorException("XML-RPC Value is of type 'undef' and its value can not be set using array index");
 488          }
 489      }
 490  
 491      /**
 492       * @internal required to be public to implement an Interface
 493       *
 494       * @param mixed $offset
 495       * @return bool
 496       */
 497      #[\ReturnTypeWillChange]
 498      public function offsetExists($offset)
 499      {
 500          switch ($this->mytype) {
 501              case 3:
 502                  return isset($this->me['struct'][$offset]);
 503              case 2:
 504                  return isset($this->me['array'][$offset]);
 505              case 1:
 506                  // handle i4 vs int
 507                  if ($offset == 'i4') {
 508                      // to be consistent with set and unset, we disallow usage of i4 to check for int
 509                      reset($this->me);
 510                      return $offset == key($this->me);
 511                  } else {
 512                      return $offset == $this->scalarTyp();
 513                  }
 514              default:
 515                  return false;
 516          }
 517      }
 518  
 519      /**
 520       * @internal required to be public to implement an Interface
 521       *
 522       * @param mixed $offset
 523       * @return void
 524       *
 525       * @throws ValueErrorException|StateErrorException
 526       */
 527      #[\ReturnTypeWillChange]
 528      public function offsetUnset($offset)
 529      {
 530          switch ($this->mytype) {
 531              case 3:
 532                  unset($this->me['struct'][$offset]);
 533                  return;
 534              case 2:
 535                  unset($this->me['array'][$offset]);
 536                  return;
 537              case 1:
 538                  // can not remove value from a scalar
 539                  /// @todo feature creep - allow this to move back the value to 'undef' state?
 540                  throw new StateErrorException("XML-RPC Value is of type 'scalar' and its value can not be unset using array index");
 541              default:
 542                  throw new StateErrorException("XML-RPC Value is of type 'undef' and its value can not be unset using array index");
 543          }
 544      }
 545  
 546      /**
 547       * @internal required to be public to implement an Interface
 548       *
 549       * @param mixed $offset
 550       * @return mixed|Value|null
 551       * @throws StateErrorException
 552       */
 553      #[\ReturnTypeWillChange]
 554      public function offsetGet($offset)
 555      {
 556          switch ($this->mytype) {
 557              case 3:
 558                  return isset($this->me['struct'][$offset]) ? $this->me['struct'][$offset] : null;
 559              case 2:
 560                  return isset($this->me['array'][$offset]) ? $this->me['array'][$offset] : null;
 561              case 1:
 562                  /// @todo what to return on bad type: null or exception?
 563                  $value = reset($this->me);
 564                  $type = key($this->me);
 565                  return $type == $offset ? $value : (($type == 'i4' && $offset == 'int') ? $value : null);
 566              default:
 567                  // return null or exception?
 568                  throw new StateErrorException("XML-RPC Value is of type 'undef' and can not be accessed using array index");
 569          }
 570      }
 571  
 572      // *** BC layer ***
 573  
 574      /**
 575       * Checks whether a struct member with a given name is present.
 576       *
 577       * Works only on xml-rpc values of type struct.
 578       *
 579       * @param string $key the name of the struct member to be looked up
 580       * @return boolean
 581       *
 582       * @deprecated use array access, e.g. isset($val[$key])
 583       */
 584      public function structMemExists($key)
 585      {
 586          $this->logDeprecation('Method ' . __METHOD__ . ' is deprecated');
 587  
 588          return array_key_exists($key, $this->me['struct']);
 589      }
 590  
 591      /**
 592       * Returns the value of a given struct member (an xml-rpc value object in itself).
 593       * Will raise a php warning if struct member of given name does not exist.
 594       *
 595       * @param string $key the name of the struct member to be looked up
 596       * @return Value
 597       *
 598       * @deprecated use array access, e.g. $val[$key]
 599       */
 600      public function structMem($key)
 601      {
 602          $this->logDeprecation('Method ' . __METHOD__ . ' is deprecated');
 603  
 604          return $this->me['struct'][$key];
 605      }
 606  
 607      /**
 608       * Reset internal pointer for xml-rpc values of type struct.
 609       * @return void
 610       *
 611       * @deprecated iterate directly over the object using foreach instead
 612       */
 613      public function structReset()
 614      {
 615          $this->logDeprecation('Method ' . __METHOD__ . ' is deprecated');
 616  
 617          reset($this->me['struct']);
 618      }
 619  
 620      /**
 621       * Return next member element for xml-rpc values of type struct.
 622       *
 623       * @return array having the same format as PHP's `each` method
 624       *
 625       * @deprecated iterate directly over the object using foreach instead
 626       */
 627      public function structEach()
 628      {
 629          $this->logDeprecation('Method ' . __METHOD__ . ' is deprecated');
 630  
 631          $key = key($this->me['struct']);
 632          $value = current($this->me['struct']);
 633          next($this->me['struct']);
 634          return array(1 => $value, 'value' => $value, 0 => $key, 'key' => $key);
 635      }
 636  
 637      /**
 638       * Returns the n-th member of an xml-rpc value of array type.
 639       *
 640       * @param integer $key the index of the value to be retrieved (zero based)
 641       *
 642       * @return Value
 643       *
 644       * @deprecated use array access, e.g. $val[$key]
 645       */
 646      public function arrayMem($key)
 647      {
 648          $this->logDeprecation('Method ' . __METHOD__ . ' is deprecated');
 649  
 650          return $this->me['array'][$key];
 651      }
 652  
 653      /**
 654       * Returns the number of members in an xml-rpc value of array type.
 655       *
 656       * @return integer
 657       *
 658       * @deprecated use count() instead
 659       */
 660      public function arraySize()
 661      {
 662          $this->logDeprecation('Method ' . __METHOD__ . ' is deprecated');
 663  
 664          return count($this->me['array']);
 665      }
 666  
 667      /**
 668       * Returns the number of members in an xml-rpc value of struct type.
 669       *
 670       * @return integer
 671       *
 672       * @deprecated use count() instead
 673       */
 674      public function structSize()
 675      {
 676          $this->logDeprecation('Method ' . __METHOD__ . ' is deprecated');
 677  
 678          return count($this->me['struct']);
 679      }
 680  
 681      // we have to make this return by ref in order to allow calls such as `$resp->_cookies['name'] = ['value' => 'something'];`
 682      public function &__get($name)
 683      {
 684          switch ($name) {
 685              case 'me':
 686              case 'mytype':
 687              case '_php_class':
 688                  $this->logDeprecation('Getting property Value::' . $name . ' is deprecated');
 689                  return $this->$name;
 690              default:
 691                  /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout...
 692                  $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
 693                  trigger_error('Undefined property via __get(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING);
 694                  $result = null;
 695                  return $result;
 696          }
 697      }
 698  
 699      public function __set($name, $value)
 700      {
 701          switch ($name) {
 702              case 'me':
 703              case 'mytype':
 704              case '_php_class':
 705                  $this->logDeprecation('Setting property Value::' . $name . ' is deprecated');
 706                  $this->$name = $value;
 707                  break;
 708              default:
 709                  /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout...
 710                  $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
 711                  trigger_error('Undefined property via __set(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING);
 712          }
 713      }
 714  
 715      public function __isset($name)
 716      {
 717          switch ($name) {
 718              case 'me':
 719              case 'mytype':
 720              case '_php_class':
 721                  $this->logDeprecation('Checking property Value::' . $name . ' is deprecated');
 722                  return isset($this->$name);
 723              default:
 724                  return false;
 725          }
 726      }
 727  
 728      public function __unset($name)
 729      {
 730          switch ($name) {
 731              case 'me':
 732              case 'mytype':
 733              case '_php_class':
 734                  $this->logDeprecation('Unsetting property Value::' . $name . ' is deprecated');
 735                  unset($this->$name);
 736                  break;
 737              default:
 738                  /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout...
 739                  $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
 740                  trigger_error('Undefined property via __unset(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING);
 741          }
 742      }
 743  }