.uksort.php */ public static function uksort($array, callable $callback) { uksort($array, $callback); return $array; } /** * Recursively sort an array by keys and values. * * @param array $array * @param int $options * @param bool $desc * @return array */ public static function sortRecursive($array, $options = SORT_REGULAR, $desc = false) { foreach ($array as &$value) { if (is_array($value)) { $value = static::sortRecursive($value, $options, $desc); } } if (static::isAssoc($array)) { $desc ? krsort($array, $options) : ksort($array, $options); } else { $desc ? rsort($array, $options) : sort($array, $options); } return $array; } /** * Conditionally compile classes from an array into a CSS class list. * * @param array $array * @return string */ public static function toCssClasses($array) { $classList = static::wrap($array); $classes = []; foreach ($classList as $class => $constraint) { if (is_numeric($class)) { $classes[] = $constraint; } elseif ($constraint) { $classes[] = $class; } } return implode(' ', $classes); } /** * Transforms an array to \stdClass * @param array $array * @return \stdClass */ public static function toObject($array) { return StdObject::create($array); } /** * Filter the array using the given callback. * * @param array $array * @param callable $callback * @return array */ public static function where($array, callable $callback) { return array_filter($array, $callback, ARRAY_FILTER_USE_BOTH); } /** * Filter items where the value is not null. * * @param array $array * @return array */ public static function whereNotNull($array) { return static::where($array, function ($value) { return ! is_null($value); }); } /** * Filter items where the value is not null. * * @param array $array * @return array */ public static function whereNotTrue($array, $strict = false) { return static::where($array, function ($value) use ($strict) { return $strict ? $value === false : !$value; }); } /** * If the given value is not an array and not null, wrap it in one. * * @param mixed $value * @return array */ public static function wrap($value) { if (is_null($value)) { return []; } return is_array($value) ? $value : [$value]; } /** * Maps a function to all non-iterable elements of an array or an object. * * This is similar to `array_walk_recursive()` but acts upon objects too. * * @param mixed $value The array, object, or scalar. * @param callable $callback The function to map onto $value. * @see https://developer.wordpress.org/reference/functions/map_deep/ * * @return mixed The value with the callback applied to all non-arrays and non-objects inside it. */ public static function map($value, $callback) { return map_deep($value, $callback); } /** * Check if the value(s) exist in an array using "dot" notation. * * @param array $array * @param string|array $values * @return bool */ public static function contains(array $array, $values) { $result = []; $values = is_array($values) ? $values : [$values]; foreach ($values as $value) { if (in_array($value, $array)) { $result[] = $value; continue; } $segments = explode('.', $value); $value = array_pop($segments); $nested = (array) static::get($array, implode('.', $segments)); if ($nested && in_array($value, $nested)) { $result[] = $value; } } return count($result) === count($values); } /** * Check if the any value exist in an array using "dot" notation. * * @param array $array * @param string|array $values * @return bool */ public static function containsAny(array $array, $values) { $result = []; $values = is_array($values) ? $values : [$values]; foreach ($values as $value) { if (in_array($value, $array)) { return true; } $segments = explode('.', $value); $value = array_pop($segments); $nested = (array) static::get($array, implode('.', $segments)); if ($nested && in_array($value, $nested)) { return true; } } return false; } /** * Compare two nested arrays side by side * @param array $array1 * @param array $array2 * @param array $path * @return array */ public static function compare($array1, $array2, $path = []) { $differences = []; foreach ($array1 as $key => $value1) { // Check if the key exists in the second array if (!array_key_exists($key, $array2)) { $differences[implode('.', array_merge($path, [$key]))] = [ 'array_1' => $value1, 'array_2' => null, ]; } else { // If the value is an array, recursively compare if (is_array($value1) && is_array($array2[$key])) { $differences = array_merge($differences, static::compare( $value1, $array2[$key], array_merge($path, [$key]) )); } else { // Compare values if ($value1 !== $array2[$key]) { $differences[implode('.', array_merge($path, [$key]))] = [ 'array_1' => $value1, 'array_2' => $array2[$key], ]; } } } } // Check for keys in the second array that are not in the first array foreach ($array2 as $key => $value2) { if (!array_key_exists($key, $array1)) { $differences[implode('.', array_merge($path, [$key]))] = [ 'array_1' => null, 'array_2' => $value2, ]; } } return $differences; } /** * Merge the items from the first array into the * second array if the second array is missing it. * * @param array &$array1 * @param array &$array2 * @return array */ public static function mergeMissing(&$array1, &$array2) { foreach ($array1 as $key => $value1) { // If the key exists in the second array if (array_key_exists($key, $array2)) { // If the value is an array, recursively add missing items if (is_array($value1) && is_array($array2[$key])) { static::mergeMissing($value1, $array2[$key]); } } else { // If the key doesn't exist in the second array, // then add it with the corresponding value $array2[$key] = $value1; } } return $array2; } /** * Recursively merge the given array with defaults. * Overwrite $array with $defaults if only $array * contains null or empty values or doesn't exist. * * @param array $array * @param array $defaults * @return array */ public static function mergeMissingValues(array $array, array $defaults) { $merged = array_merge($defaults, $array); foreach ($merged as $key => $value) { if ( is_array($value) && isset($defaults[$key]) && is_array($defaults[$key]) ) { // Recursively merge arrays $merged[$key] = static::mergeMissingValues( $value, $defaults[$key] ); } elseif ( isset($defaults[$key]) && (is_null($value) || $value === '') ) { // Replace null or empty values $merged[$key] = $defaults[$key]; } } return $merged; } /** * Return matching items from array (similar to mysql's %LIKE%) * * @param string|regex $pattern * @param array $array * @return array|false */ public static function like($array, $pattern) { if (!preg_match('/^([\/#~]).*\1$/', $pattern)) { $pattern = '~'. preg_quote($pattern, '~') . '~i'; } return preg_grep($pattern, $array); } /** * Return non-matching items from array (similar to mysql's NOT %LIKE%) * * @param string|regex $pattern * @param array $array * @return array|false */ public static function notLike($array, $pattern) { if (!preg_match('/^([\/#~]).*\1$/', $pattern)) { $pattern = '~'. preg_quote($pattern, '~') . '~i'; } return preg_grep($pattern, $array, PREG_GREP_INVERT); } /** * Return matching starting of items from array (similar to mysql's %LIKE) * * @param string|regex $pattern * @param array $array * @return array|false */ public static function startsLike($array, $pattern) { if (!preg_match('/^([\/#~]).*\1$/', $pattern)) { $pattern = '~^'. preg_quote($pattern, '~') . '~i'; } return preg_grep($pattern, $array); } /** * Return non-matching starting of items from array (similar to mysql's NOT %LIKE) * * @param string|regex $pattern * @param array $array * @return array|false */ public static function DoesNotStartLike($array, $pattern) { if (!preg_match('/^([\/#~]).*\1$/', $pattern)) { $pattern = '~^(?!' . preg_quote($pattern, '~') . ')~i'; } return preg_grep($pattern, $array); } /** * Return matching ending of items from array (similar to mysql's LIKE%) * * @param string|regex $pattern * @param array $array * @return array|false */ public static function endsLike($array, $pattern) { if (!preg_match('/^([\/#~]).*\1$/', $pattern)) { $pattern = '~'. preg_quote($pattern, '~') . '$~i'; } return preg_grep($pattern, $array); } /** * Return non-matching ending of items from array (similar to mysql's NOT LIKE%) * * @param string|regex $pattern * @param array $array * @return array|false */ public static function DoesNotEndLike($array, $pattern) { if (!preg_match('/^([\/#~]).*\1$/', $pattern)) { $pattern = '~'. preg_quote($pattern, '~') . '$~i'; } return preg_grep($pattern, $array, PREG_GREP_INVERT); } /** * Return matching items from array by keys * * @param string|regex $pattern * @param array $array * @return array|false */ public static function keysLike($array, $pattern) { if (!preg_match('/^([\/#~]).*\1$/', $pattern)) { $pattern = '~'. preg_quote($pattern, '~') . '~i'; } $values = []; $keys = preg_grep($pattern, array_keys($array)); foreach ($keys as $key) { $values[$key] = $array[$key]; } return $values; } /** * Return non-matching items from array by keys * * @param string|regex $pattern * @param array $array * @return array|false */ public static function keysNotLike($array, $pattern) { if (!preg_match('/^([\/#~]).*\1$/', $pattern)) { $pattern = '~'. preg_quote($pattern, '~') . '~i'; } $values = []; $keys = preg_grep($pattern, array_keys($array), 1); foreach ($keys as $key) { $values[$key] = $array[$key]; } return $values; } /** * Return matching starting of items from array by keys * * @param string|regex $pattern * @param array $array * @return array|false */ public static function keysStartLike($array, $pattern) { if (!preg_match('/^([\/#~]).*\1$/', $pattern)) { $pattern = '~^'. preg_quote($pattern, '~') . '~i'; } $values = []; $keys = preg_grep($pattern, array_keys($array)); foreach ($keys as $key) { $values[$key] = $array[$key]; } return $values; } /** * Return non-matching starting of items from array by keys * * @param string|regex $pattern * @param array $array * @return array|false */ public static function keysDoesNotStartLike($array, $pattern) { if (!preg_match('/^([\/#~]).*\1$/', $pattern)) { $pattern = '~^(?!' . preg_quote($pattern, '~') . ')~i'; } $values = []; $keys = preg_grep($pattern, array_keys($array)); foreach ($keys as $key) { $values[$key] = $array[$key]; } return $values; } /** * Return matching ending of items from array by keys * * @param string|regex $pattern * @param array $array * @return array|false */ public static function keysEndLike($array, $pattern) { if (!preg_match('/^([\/#~]).*\1$/', $pattern)) { $pattern = '~'. preg_quote($pattern, '~') . '$~i'; } $values = []; $keys = preg_grep($pattern, array_keys($array)); foreach ($keys as $key) { $values[$key] = $array[$key]; } return $values; } /** * Return non-matching ending of items from array by keys * * @param string|regex $pattern * @param array $array * @return array|false */ public static function keysDoesNotEndLike($array, $pattern) { if (!preg_match('/^([\/#~]).*\1$/', $pattern)) { $pattern = '~'. preg_quote($pattern, '~') . '$~i'; } $values = []; $keys = preg_grep($pattern, array_keys($array), PREG_GREP_INVERT); foreach ($keys as $key) { $values[$key] = $array[$key]; } return $values; } /** * Insert a new item in the array at the given position. * * @param array $array * @param int $pos * @param mixed $newItem * @return array */ public static function insertAt($array, $pos, $newItem) { if (!isset($array[$pos])) { $array[] = $newItem; } else { $array = array_splice($array, $pos, 0, $newItem); } return $array; } /** * Inserts an item before the specified key in the given array. If the * key is not found, inserts the item at the beginning of the array. * * @param array $array * @param mixed $key * @param mixed $newKey * @param mixed $newValue * @return array $newArray */ public static function insertBefore($array, $key, $newKey, $newValue) { $newArray = []; $keyFound = false; foreach ($array as $k => $v) { if ($k === $key) { $newArray[$newKey] = $newValue; $keyFound = true; } $newArray[$k] = $v; } if (!$keyFound) { $newArray = [$newKey => $newValue] + $newArray; } return $newArray; } /** * Inserts an item after the specified key in the given array. If the * key is not found, inserts the item at the end of the array. * * @param array $array * @param mixed $key * @param mixed $newKey * @param mixed $newValue * @return array $newArray */ public static function insertAfter($array, $key, $newKey, $newValue): array { $newArray = []; $keyFound = false; foreach ($array as $k => $v) { $newArray[$k] = $v; if ($k === $key) { $newArray[$newKey] = $newValue; $keyFound = true; } } if (!$keyFound) { $newArray[$newKey] = $newValue; } return $newArray; } /** * Tests whether at least one element in the array passes * the test implemented by the provided callback. * * @param array $array * @param callable $callback * @return bool */ public static function some($array, callable $callback) { foreach ($array as $k => $v) { if ($callback($v, $k, $array)) { return true; } } return false; } /** * Tests whether all elements in the array pass the * test implemented by the provided callback. * * @param array $array * @param callable $callback * @return bool */ public static function every($array, callable $callback) { foreach ($array as $k => $v) { if (!$callback($v, $k, $array)) { return false; } } return true; } /** * Finds the first element in the array that satisfies the * condition implemented by the callback function. * * @param array $array * @param callable $callback * @return mixed */ public static function find($array, callable $callback, $findKey = false) { foreach ($array as $k => $v) { if ($callback($v, $k, $array)) { return $findKey ? $k : $v; } } return null; } /** * Finds the first key in the array that satisfies the * condition implemented by the callback function. * * @param array $array * @param callable $callback * @return mixed */ public static function findKey($array, callable $callback) { return static::find($array, $callback, true); } }