| 
<?php
 /**
 * JSONPath implementation for PHP.
 *
 * @license https://github.com/SoftCreatR/JSONPath/blob/main/LICENSE  MIT License
 */
 
 declare(strict_types=1);
 
 namespace Flow\JSONPath;
 
 use ArrayAccess;
 
 use function abs;
 use function array_key_exists;
 use function array_keys;
 use function array_slice;
 use function array_values;
 use function get_object_vars;
 use function is_array;
 use function is_int;
 use function is_object;
 use function method_exists;
 use function property_exists;
 
 class AccessHelper
 {
 /**
 * @param array|ArrayAccess $collection
 */
 public static function collectionKeys($collection): array
 {
 if (is_object($collection)) {
 return array_keys(get_object_vars($collection));
 }
 
 return array_keys($collection);
 }
 
 /**
 * @param array|ArrayAccess $collection
 */
 public static function isCollectionType($collection): bool
 {
 return is_array($collection) || is_object($collection);
 }
 
 /**
 * @param array|ArrayAccess $collection
 */
 public static function keyExists($collection, $key, bool $magicIsAllowed = false): bool
 {
 if ($magicIsAllowed && is_object($collection) && method_exists($collection, '__get')) {
 return true;
 }
 
 if (is_int($key) && $key < 0) {
 $key = abs($key);
 }
 
 if (is_array($collection)) {
 return array_key_exists($key, $collection);
 }
 
 if ($collection instanceof ArrayAccess) {
 return $collection->offsetExists($key);
 }
 
 if (is_object($collection)) {
 return property_exists($collection, (string)$key);
 }
 
 return false;
 }
 
 /**
 * @todo Optimize conditions
 *
 * @param array|ArrayAccess $collection
 * @noinspection NotOptimalIfConditionsInspection
 */
 public static function getValue($collection, $key, bool $magicIsAllowed = false)
 {
 $return = null;
 
 if (
 $magicIsAllowed &&
 is_object($collection) &&
 !$collection instanceof ArrayAccess && method_exists($collection, '__get')
 ) {
 $return = $collection->__get($key);
 } elseif (is_object($collection) && !$collection instanceof ArrayAccess) {
 $return = $collection->$key;
 } elseif ($collection instanceof ArrayAccess) {
 $return = $collection->offsetGet($key);
 } elseif (is_array($collection)) {
 if (is_int($key) && $key < 0) {
 $return = array_slice($collection, $key, 1, false)[0];
 } else {
 $return = $collection[$key];
 }
 } elseif (is_int($key)) {
 $return = self::getValueByIndex($collection, $key);
 } else {
 $return = $collection[$key];
 }
 
 return $return;
 }
 
 /**
 * Find item in php collection by index
 * Written this way to handle instances ArrayAccess or Traversable objects
 *
 * @param array|ArrayAccess $collection
 *
 * @return mixed|null
 */
 private static function getValueByIndex($collection, $key)
 {
 $i = 0;
 
 foreach ($collection as $val) {
 if ($i === $key) {
 return $val;
 }
 
 ++$i;
 }
 
 if ($key < 0) {
 $total = $i;
 $i = 0;
 
 foreach ($collection as $val) {
 if ($i - $total === $key) {
 return $val;
 }
 
 ++$i;
 }
 }
 
 return null;
 }
 
 /**
 * @param array|ArrayAccess $collection
 */
 public static function setValue(&$collection, $key, $value)
 {
 if (is_object($collection) && !$collection instanceof ArrayAccess) {
 return $collection->$key = $value;
 }
 
 if ($collection instanceof ArrayAccess) {
 return $collection->offsetSet($key, $value);
 }
 
 return $collection[$key] = $value;
 }
 
 /**
 * @param array|ArrayAccess $collection
 */
 public static function unsetValue(&$collection, $key): void
 {
 if (is_object($collection) && !$collection instanceof ArrayAccess) {
 unset($collection->$key);
 }
 
 if ($collection instanceof ArrayAccess) {
 $collection->offsetUnset($key);
 }
 
 if (is_array($collection)) {
 unset($collection[$key]);
 }
 }
 
 /**
 * @param array|ArrayAccess $collection
 *
 * @throws JSONPathException
 */
 public static function arrayValues($collection): array
 {
 if (is_array($collection)) {
 return array_values($collection);
 }
 
 if (is_object($collection)) {
 return array_values((array)$collection);
 }
 
 throw new JSONPathException("Invalid variable type for arrayValues");
 }
 }
 
 |