1
0

Value.php 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741
  1. <?php
  2. namespace PhpXmlRpc;
  3. use PhpXmlRpc\Exception\StateErrorException;
  4. use PhpXmlRpc\Exception\TypeErrorException;
  5. use PhpXmlRpc\Exception\ValueErrorException;
  6. use PhpXmlRpc\Traits\CharsetEncoderAware;
  7. use PhpXmlRpc\Traits\DeprecationLogger;
  8. /**
  9. * This class enables the creation of values for XML-RPC, by encapsulating plain php values.
  10. *
  11. * @property Value[]|mixed $me deprecated - public access left in purely for BC. Access via scalarVal()/__construct()
  12. * @property int $params $mytype - public access left in purely for BC. Access via kindOf()/__construct()
  13. * @property string|null $_php_class deprecated - public access left in purely for BC.
  14. */
  15. class Value implements \Countable, \IteratorAggregate, \ArrayAccess
  16. {
  17. use CharsetEncoderAware;
  18. use DeprecationLogger;
  19. public static $xmlrpcI4 = "i4";
  20. public static $xmlrpcI8 = "i8";
  21. public static $xmlrpcInt = "int";
  22. public static $xmlrpcBoolean = "boolean";
  23. public static $xmlrpcDouble = "double";
  24. public static $xmlrpcString = "string";
  25. public static $xmlrpcDateTime = "dateTime.iso8601";
  26. public static $xmlrpcBase64 = "base64";
  27. public static $xmlrpcArray = "array";
  28. public static $xmlrpcStruct = "struct";
  29. public static $xmlrpcValue = "undefined";
  30. public static $xmlrpcNull = "null";
  31. public static $xmlrpcTypes = array(
  32. "i4" => 1,
  33. "i8" => 1,
  34. "int" => 1,
  35. "boolean" => 1,
  36. "double" => 1,
  37. "string" => 1,
  38. "dateTime.iso8601" => 1,
  39. "base64" => 1,
  40. "array" => 2,
  41. "struct" => 3,
  42. "null" => 1,
  43. );
  44. /** @var Value[]|mixed */
  45. protected $me = array();
  46. /**
  47. * @var int 0 for undef, 1 for scalar, 2 for array, 3 for struct
  48. */
  49. protected $mytype = 0;
  50. /** @var string|null */
  51. protected $_php_class = null;
  52. /**
  53. * Build an xml-rpc value.
  54. *
  55. * When no value or type is passed in, the value is left uninitialized, and the value can be added later.
  56. *
  57. * @param Value[]|mixed $val if passing in an array, all array elements should be PhpXmlRpc\Value themselves
  58. * @param string $type any valid xml-rpc type name (lowercase): i4, int, boolean, string, double, dateTime.iso8601,
  59. * base64, array, struct, null.
  60. * If null, 'string' is assumed.
  61. * You should refer to http://xmlrpc.com/spec.md for more information on what each of these mean.
  62. */
  63. public function __construct($val = -1, $type = '')
  64. {
  65. // optimization creep - do not call addXX, do it all inline.
  66. // downside: booleans will not be coerced anymore
  67. if ($val !== -1 || $type != '') {
  68. switch ($type) {
  69. case '':
  70. $this->mytype = 1;
  71. $this->me['string'] = $val;
  72. break;
  73. case 'i4':
  74. case 'i8':
  75. case 'int':
  76. case 'double':
  77. case 'string':
  78. case 'boolean':
  79. case 'dateTime.iso8601':
  80. case 'base64':
  81. case 'null':
  82. $this->mytype = 1;
  83. $this->me[$type] = $val;
  84. break;
  85. case 'array':
  86. $this->mytype = 2;
  87. $this->me['array'] = $val;
  88. break;
  89. case 'struct':
  90. $this->mytype = 3;
  91. $this->me['struct'] = $val;
  92. break;
  93. default:
  94. $this->getLogger()->error("XML-RPC: " . __METHOD__ . ": not a known type ($type)");
  95. }
  96. }
  97. }
  98. /**
  99. * Add a single php value to an xml-rpc value.
  100. *
  101. * If the xml-rpc value is an array, the php value is added as its last element.
  102. * If the xml-rpc value is empty (uninitialized), this method makes it a scalar value, and sets that value.
  103. * Fails if the xml-rpc value is not an array (i.e. a struct or a scalar) and already initialized.
  104. *
  105. * @param mixed $val
  106. * @param string $type allowed values: i4, i8, int, boolean, string, double, dateTime.iso8601, base64, null.
  107. * @return int 1 or 0 on failure
  108. *
  109. * @todo arguably, as we have addArray to add elements to an Array value, and addStruct to add elements to a Struct
  110. * value, we should not allow this method to add values to an Array. The 'scalar' in the method name refers to
  111. * the expected state of the target object, not to the type of $val. Also, this works differently from
  112. * addScalar/addStruct in that, when adding an element to an array, it wraps it into a new Value
  113. * @todo rename?
  114. */
  115. public function addScalar($val, $type = 'string')
  116. {
  117. $typeOf = null;
  118. if (isset(static::$xmlrpcTypes[$type])) {
  119. $typeOf = static::$xmlrpcTypes[$type];
  120. }
  121. if ($typeOf !== 1) {
  122. $this->getLogger()->error("XML-RPC: " . __METHOD__ . ": not a scalar type ($type)");
  123. return 0;
  124. }
  125. // coerce booleans into correct values
  126. /// @todo we should either do it for datetimes, integers, i8 and doubles, too, or just plain remove this check,
  127. /// implemented on booleans only...
  128. if ($type == static::$xmlrpcBoolean) {
  129. if (strcasecmp($val, 'true') == 0 || $val == 1 || ($val == true && strcasecmp($val, 'false'))) {
  130. $val = true;
  131. } else {
  132. $val = false;
  133. }
  134. }
  135. switch ($this->mytype) {
  136. case 1:
  137. $this->getLogger()->error('XML-RPC: ' . __METHOD__ . ': scalar xmlrpc value can have only one value');
  138. return 0;
  139. case 3:
  140. $this->getLogger()->error('XML-RPC: ' . __METHOD__ . ': cannot add anonymous scalar to struct xmlrpc value');
  141. return 0;
  142. case 2:
  143. // we're adding a scalar value to an array here
  144. /// @todo should we try avoiding re-wrapping Value objects?
  145. $class = get_class($this);
  146. $this->me['array'][] = new $class($val, $type);
  147. return 1;
  148. default:
  149. // a scalar, so set the value and remember we're scalar
  150. $this->me[$type] = $val;
  151. $this->mytype = $typeOf;
  152. return 1;
  153. }
  154. }
  155. /**
  156. * Add an array of xml-rpc value objects to an xml-rpc value.
  157. *
  158. * If the xml-rpc value is an array, the elements are appended to the existing ones.
  159. * If the xml-rpc value is empty (uninitialized), this method makes it an array value, and sets that value.
  160. * Fails otherwise.
  161. *
  162. * @param Value[] $values
  163. * @return int 1 or 0 on failure
  164. *
  165. * @todo add some checking for $values to be an array of xml-rpc values?
  166. * @todo rename to addToArray?
  167. */
  168. public function addArray($values)
  169. {
  170. if ($this->mytype == 0) {
  171. $this->mytype = static::$xmlrpcTypes['array'];
  172. $this->me['array'] = $values;
  173. return 1;
  174. } elseif ($this->mytype == 2) {
  175. // we're adding to an array here
  176. $this->me['array'] = array_merge($this->me['array'], $values);
  177. return 1;
  178. } else {
  179. $this->getLogger()->error('XML-RPC: ' . __METHOD__ . ': already initialized as a [' . $this->kindOf() . ']');
  180. return 0;
  181. }
  182. }
  183. /**
  184. * Merges an array of named xml-rpc value objects into an xml-rpc value.
  185. *
  186. * If the xml-rpc value is a struct, the elements are merged with the existing ones (overwriting existing ones).
  187. * If the xml-rpc value is empty (uninitialized), this method makes it a struct value, and sets that value.
  188. * Fails otherwise.
  189. *
  190. * @param Value[] $values
  191. * @return int 1 or 0 on failure
  192. *
  193. * @todo add some checking for $values to be an array of xml-rpc values?
  194. * @todo rename to addToStruct?
  195. */
  196. public function addStruct($values)
  197. {
  198. if ($this->mytype == 0) {
  199. $this->mytype = static::$xmlrpcTypes['struct'];
  200. $this->me['struct'] = $values;
  201. return 1;
  202. } elseif ($this->mytype == 3) {
  203. // we're adding to a struct here
  204. $this->me['struct'] = array_merge($this->me['struct'], $values);
  205. return 1;
  206. } else {
  207. $this->getLogger()->error('XML-RPC: ' . __METHOD__ . ': already initialized as a [' . $this->kindOf() . ']');
  208. return 0;
  209. }
  210. }
  211. /**
  212. * Returns a string describing the base type of the value.
  213. *
  214. * @return string either "struct", "array", "scalar" or "undef"
  215. */
  216. public function kindOf()
  217. {
  218. switch ($this->mytype) {
  219. case 3:
  220. return 'struct';
  221. case 2:
  222. return 'array';
  223. case 1:
  224. return 'scalar';
  225. default:
  226. return 'undef';
  227. }
  228. }
  229. /**
  230. * Returns the value of a scalar xml-rpc value (base 64 decoding is automatically handled here)
  231. *
  232. * @return mixed
  233. */
  234. public function scalarVal()
  235. {
  236. $b = reset($this->me);
  237. return $b;
  238. }
  239. /**
  240. * Returns the type of the xml-rpc value.
  241. *
  242. * @return string For integers, 'int' is always returned in place of 'i4'. 'i8' is considered a separate type and
  243. * returned as such
  244. */
  245. public function scalarTyp()
  246. {
  247. reset($this->me);
  248. $a = key($this->me);
  249. if ($a == static::$xmlrpcI4) {
  250. $a = static::$xmlrpcInt;
  251. }
  252. return $a;
  253. }
  254. /**
  255. * Returns the xml representation of the value. XML prologue not included.
  256. *
  257. * @param string $charsetEncoding the charset to be used for serialization. If null, US-ASCII is assumed
  258. * @return string
  259. */
  260. public function serialize($charsetEncoding = '')
  261. {
  262. $val = reset($this->me);
  263. $typ = key($this->me);
  264. return '<value>' . $this->serializeData($typ, $val, $charsetEncoding) . "</value>\n";
  265. }
  266. /**
  267. * @param string $typ
  268. * @param Value[]|mixed $val
  269. * @param string $charsetEncoding
  270. * @return string
  271. *
  272. * @deprecated this should be folded back into serialize()
  273. */
  274. protected function serializeData($typ, $val, $charsetEncoding = '')
  275. {
  276. $this->logDeprecationUnlessCalledBy('serialize');
  277. if (!isset(static::$xmlrpcTypes[$typ])) {
  278. return '';
  279. }
  280. switch (static::$xmlrpcTypes[$typ]) {
  281. case 1:
  282. switch ($typ) {
  283. case static::$xmlrpcBase64:
  284. $rs = "<{$typ}>" . base64_encode($val) . "</{$typ}>";
  285. break;
  286. case static::$xmlrpcBoolean:
  287. $rs = "<{$typ}>" . ($val ? '1' : '0') . "</{$typ}>";
  288. break;
  289. case static::$xmlrpcString:
  290. // Do NOT use htmlentities, since it will produce named html entities, which are invalid xml
  291. $rs = "<{$typ}>" . $this->getCharsetEncoder()->encodeEntities($val, PhpXmlRpc::$xmlrpc_internalencoding, $charsetEncoding) . "</{$typ}>";
  292. break;
  293. case static::$xmlrpcInt:
  294. case static::$xmlrpcI4:
  295. case static::$xmlrpcI8:
  296. $rs = "<{$typ}>" . (int)$val . "</{$typ}>";
  297. break;
  298. case static::$xmlrpcDouble:
  299. // avoid using standard conversion of float to string because it is locale-dependent,
  300. // and also because the xml-rpc spec forbids exponential notation.
  301. // sprintf('%F') could be most likely ok, but it fails e.g. on 2e-14.
  302. // The code below tries its best at keeping max precision while avoiding exp notation,
  303. // but there is of course no limit in the number of decimal places to be used...
  304. $rs = "<{$typ}>" . preg_replace('/\\.?0+$/', '', number_format((double)$val, PhpXmlRpc::$xmlpc_double_precision, '.', '')) . "</{$typ}>";
  305. break;
  306. case static::$xmlrpcDateTime:
  307. if (is_string($val)) {
  308. $rs = "<{$typ}>{$val}</{$typ}>";
  309. // DateTimeInterface is not present in php 5.4...
  310. } elseif (is_a($val, 'DateTimeInterface') || is_a($val, 'DateTime')) {
  311. $rs = "<{$typ}>" . $val->format('Ymd\TH:i:s') . "</{$typ}>";
  312. } elseif (is_int($val)) {
  313. $rs = "<{$typ}>" . date('Ymd\TH:i:s', $val) . "</{$typ}>";
  314. } else {
  315. // not really a good idea here: but what should we output anyway? left for backward compat...
  316. $rs = "<{$typ}>{$val}</{$typ}>";
  317. }
  318. break;
  319. case static::$xmlrpcNull:
  320. if (PhpXmlRpc::$xmlrpc_null_apache_encoding) {
  321. $rs = "<ex:nil/>";
  322. } else {
  323. $rs = "<nil/>";
  324. }
  325. break;
  326. default:
  327. // no standard type value should arrive here, but provide a possibility
  328. // for xml-rpc values of unknown type...
  329. $rs = "<{$typ}>{$val}</{$typ}>";
  330. }
  331. break;
  332. case 3:
  333. // struct
  334. if ($this->_php_class) {
  335. $rs = '<struct php_class="' . $this->_php_class . "\">\n";
  336. } else {
  337. $rs = "<struct>\n";
  338. }
  339. $charsetEncoder = $this->getCharsetEncoder();
  340. /** @var Value $val2 */
  341. foreach ($val as $key2 => $val2) {
  342. $rs .= '<member><name>' . $charsetEncoder->encodeEntities($key2, PhpXmlRpc::$xmlrpc_internalencoding, $charsetEncoding) . "</name>\n";
  343. $rs .= $val2->serialize($charsetEncoding);
  344. $rs .= "</member>\n";
  345. }
  346. $rs .= '</struct>';
  347. break;
  348. case 2:
  349. // array
  350. $rs = "<array>\n<data>\n";
  351. /** @var Value $element */
  352. foreach ($val as $element) {
  353. $rs .= $element->serialize($charsetEncoding);
  354. }
  355. $rs .= "</data>\n</array>";
  356. break;
  357. default:
  358. /// @todo log a warning?
  359. $rs = '';
  360. break;
  361. }
  362. return $rs;
  363. }
  364. /**
  365. * Returns the number of members in an xml-rpc value:
  366. * - 0 for uninitialized values
  367. * - 1 for scalar values
  368. * - the number of elements for struct and array values
  369. *
  370. * @return integer
  371. */
  372. #[\ReturnTypeWillChange]
  373. public function count()
  374. {
  375. switch ($this->mytype) {
  376. case 3:
  377. return count($this->me['struct']);
  378. case 2:
  379. return count($this->me['array']);
  380. case 1:
  381. return 1;
  382. default:
  383. return 0;
  384. }
  385. }
  386. /**
  387. * Implements the IteratorAggregate interface
  388. * @internal required to be public to implement an Interface
  389. *
  390. * @return \ArrayIterator
  391. */
  392. #[\ReturnTypeWillChange]
  393. public function getIterator()
  394. {
  395. switch ($this->mytype) {
  396. case 3:
  397. return new \ArrayIterator($this->me['struct']);
  398. case 2:
  399. return new \ArrayIterator($this->me['array']);
  400. case 1:
  401. return new \ArrayIterator($this->me);
  402. default:
  403. return new \ArrayIterator();
  404. }
  405. }
  406. /**
  407. * @internal required to be public to implement an Interface
  408. *
  409. * @param mixed $offset
  410. * @param mixed $value
  411. * @return void
  412. * @throws ValueErrorException|TypeErrorException
  413. */
  414. #[\ReturnTypeWillChange]
  415. public function offsetSet($offset, $value)
  416. {
  417. switch ($this->mytype) {
  418. case 3:
  419. if (!($value instanceof Value)) {
  420. throw new TypeErrorException('It is only possible to add Value objects to an XML-RPC Struct');
  421. }
  422. if (is_null($offset)) {
  423. // disallow struct members with empty names
  424. throw new ValueErrorException('It is not possible to add anonymous members to an XML-RPC Struct');
  425. } else {
  426. $this->me['struct'][$offset] = $value;
  427. }
  428. return;
  429. case 2:
  430. if (!($value instanceof Value)) {
  431. throw new TypeErrorException('It is only possible to add Value objects to an XML-RPC Array');
  432. }
  433. if (is_null($offset)) {
  434. $this->me['array'][] = $value;
  435. } else {
  436. // nb: we are not checking that $offset is above the existing array range...
  437. $this->me['array'][$offset] = $value;
  438. }
  439. return;
  440. case 1:
  441. /// @todo: should we handle usage of i4 to retrieve int (in both set/unset/isset)? After all we consider
  442. /// 'int' to be the preferred form, as evidenced in scalarTyp()
  443. reset($this->me);
  444. $type = key($this->me);
  445. if ($type != $offset && ($type != 'i4' || $offset != 'int')) {
  446. throw new ValueErrorException('...');
  447. }
  448. $this->me[$type] = $value;
  449. return;
  450. default:
  451. // it would be nice to allow empty values to be turned into non-empty ones this way, but we miss info to do so
  452. throw new ValueErrorException("XML-RPC Value is of type 'undef' and its value can not be set using array index");
  453. }
  454. }
  455. /**
  456. * @internal required to be public to implement an Interface
  457. *
  458. * @param mixed $offset
  459. * @return bool
  460. */
  461. #[\ReturnTypeWillChange]
  462. public function offsetExists($offset)
  463. {
  464. switch ($this->mytype) {
  465. case 3:
  466. return isset($this->me['struct'][$offset]);
  467. case 2:
  468. return isset($this->me['array'][$offset]);
  469. case 1:
  470. // handle i4 vs int
  471. if ($offset == 'i4') {
  472. // to be consistent with set and unset, we disallow usage of i4 to check for int
  473. reset($this->me);
  474. return $offset == key($this->me);
  475. } else {
  476. return $offset == $this->scalarTyp();
  477. }
  478. default:
  479. return false;
  480. }
  481. }
  482. /**
  483. * @internal required to be public to implement an Interface
  484. *
  485. * @param mixed $offset
  486. * @return void
  487. * @throws ValueErrorException|StateErrorException
  488. */
  489. #[\ReturnTypeWillChange]
  490. public function offsetUnset($offset)
  491. {
  492. switch ($this->mytype) {
  493. case 3:
  494. unset($this->me['struct'][$offset]);
  495. return;
  496. case 2:
  497. unset($this->me['array'][$offset]);
  498. return;
  499. case 1:
  500. // can not remove value from a scalar
  501. /// @todo feature creep - allow this to move back the value to 'undef' state?
  502. throw new StateErrorException("XML-RPC Value is of type 'scalar' and its value can not be unset using array index");
  503. default:
  504. throw new StateErrorException("XML-RPC Value is of type 'undef' and its value can not be unset using array index");
  505. }
  506. }
  507. /**
  508. * @internal required to be public to implement an Interface
  509. *
  510. * @param mixed $offset
  511. * @return mixed|Value|null
  512. * @throws StateErrorException
  513. */
  514. #[\ReturnTypeWillChange]
  515. public function offsetGet($offset)
  516. {
  517. switch ($this->mytype) {
  518. case 3:
  519. return isset($this->me['struct'][$offset]) ? $this->me['struct'][$offset] : null;
  520. case 2:
  521. return isset($this->me['array'][$offset]) ? $this->me['array'][$offset] : null;
  522. case 1:
  523. /// @todo what to return on bad type: null or exception?
  524. $value = reset($this->me);
  525. $type = key($this->me);
  526. return $type == $offset ? $value : (($type == 'i4' && $offset == 'int') ? $value : null);
  527. default:
  528. // return null or exception?
  529. throw new StateErrorException("XML-RPC Value is of type 'undef' and can not be accessed using array index");
  530. }
  531. }
  532. // *** BC layer ***
  533. /**
  534. * Checks whether a struct member with a given name is present.
  535. *
  536. * Works only on xml-rpc values of type struct.
  537. *
  538. * @param string $key the name of the struct member to be looked up
  539. * @return boolean
  540. *
  541. * @deprecated use array access, e.g. isset($val[$key])
  542. */
  543. public function structMemExists($key)
  544. {
  545. $this->logDeprecation('Method ' . __METHOD__ . ' is deprecated');
  546. return array_key_exists($key, $this->me['struct']);
  547. }
  548. /**
  549. * Returns the value of a given struct member (an xml-rpc value object in itself).
  550. * Will raise a php warning if struct member of given name does not exist.
  551. *
  552. * @param string $key the name of the struct member to be looked up
  553. * @return Value
  554. *
  555. * @deprecated use array access, e.g. $val[$key]
  556. */
  557. public function structMem($key)
  558. {
  559. $this->logDeprecation('Method ' . __METHOD__ . ' is deprecated');
  560. return $this->me['struct'][$key];
  561. }
  562. /**
  563. * Reset internal pointer for xml-rpc values of type struct.
  564. * @return void
  565. *
  566. * @deprecated iterate directly over the object using foreach instead
  567. */
  568. public function structReset()
  569. {
  570. $this->logDeprecation('Method ' . __METHOD__ . ' is deprecated');
  571. reset($this->me['struct']);
  572. }
  573. /**
  574. * Return next member element for xml-rpc values of type struct.
  575. *
  576. * @return array having the same format as PHP's `each` method
  577. *
  578. * @deprecated iterate directly over the object using foreach instead
  579. */
  580. public function structEach()
  581. {
  582. $this->logDeprecation('Method ' . __METHOD__ . ' is deprecated');
  583. $key = key($this->me['struct']);
  584. $value = current($this->me['struct']);
  585. next($this->me['struct']);
  586. return array(1 => $value, 'value' => $value, 0 => $key, 'key' => $key);
  587. }
  588. /**
  589. * Returns the n-th member of an xml-rpc value of array type.
  590. *
  591. * @param integer $key the index of the value to be retrieved (zero based)
  592. *
  593. * @return Value
  594. *
  595. * @deprecated use array access, e.g. $val[$key]
  596. */
  597. public function arrayMem($key)
  598. {
  599. $this->logDeprecation('Method ' . __METHOD__ . ' is deprecated');
  600. return $this->me['array'][$key];
  601. }
  602. /**
  603. * Returns the number of members in an xml-rpc value of array type.
  604. *
  605. * @return integer
  606. *
  607. * @deprecated use count() instead
  608. */
  609. public function arraySize()
  610. {
  611. $this->logDeprecation('Method ' . __METHOD__ . ' is deprecated');
  612. return count($this->me['array']);
  613. }
  614. /**
  615. * Returns the number of members in an xml-rpc value of struct type.
  616. *
  617. * @return integer
  618. *
  619. * @deprecated use count() instead
  620. */
  621. public function structSize()
  622. {
  623. $this->logDeprecation('Method ' . __METHOD__ . ' is deprecated');
  624. return count($this->me['struct']);
  625. }
  626. // we have to make this return by ref in order to allow calls such as `$resp->_cookies['name'] = ['value' => 'something'];`
  627. public function &__get($name)
  628. {
  629. switch ($name) {
  630. case 'me':
  631. case 'mytype':
  632. case '_php_class':
  633. $this->logDeprecation('Getting property Value::' . $name . ' is deprecated');
  634. return $this->$name;
  635. default:
  636. /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout...
  637. $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
  638. trigger_error('Undefined property via __get(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING);
  639. $result = null;
  640. return $result;
  641. }
  642. }
  643. public function __set($name, $value)
  644. {
  645. switch ($name) {
  646. case 'me':
  647. case 'mytype':
  648. case '_php_class':
  649. $this->logDeprecation('Setting property Value::' . $name . ' is deprecated');
  650. $this->$name = $value;
  651. break;
  652. default:
  653. /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout...
  654. $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
  655. trigger_error('Undefined property via __set(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING);
  656. }
  657. }
  658. public function __isset($name)
  659. {
  660. switch ($name) {
  661. case 'me':
  662. case 'mytype':
  663. case '_php_class':
  664. $this->logDeprecation('Checking property Value::' . $name . ' is deprecated');
  665. return isset($this->$name);
  666. default:
  667. return false;
  668. }
  669. }
  670. public function __unset($name)
  671. {
  672. switch ($name) {
  673. case 'me':
  674. case 'mytype':
  675. case '_php_class':
  676. $this->logDeprecation('Unsetting property Value::' . $name . ' is deprecated');
  677. unset($this->$name);
  678. break;
  679. default:
  680. /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout...
  681. $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
  682. trigger_error('Undefined property via __unset(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING);
  683. }
  684. }
  685. }