rence between the two arrays. */ public static function deep_assoc_array_diff( array $array1, array $array2, bool $strict = true ): array { return self::deep_compute_or_compare_array_diff( $array1, $array2, false, $strict ); } /** * Helper method to compare to compute difference between two arrays. Comparison is done recursively. * * @param array $array1 First array. * @param array $array2 Second array. * @param bool $compare Whether to compare the arrays. If true, then function will return false on first difference, in order to be slightly more efficient. * @param bool $strict Whether to do string comparison. * * @return array|bool The difference between the two arrays, or if array are same, depending upon $compare param. */ private static function deep_compute_or_compare_array_diff( array $array1, array $array2, bool $compare, bool $strict = true ) { $diff = array(); foreach ( $array1 as $key => $value ) { if ( is_array( $value ) ) { if ( ! array_key_exists( $key, $array2 ) || ! is_array( $array2[ $key ] ) ) { if ( $compare ) { return true; } $diff[ $key ] = $value; continue; } $new_diff = self::deep_assoc_array_diff( $value, $array2[ $key ], $strict ); if ( ! empty( $new_diff ) ) { if ( $compare ) { return true; } $diff[ $key ] = $new_diff; } } elseif ( $strict ) { if ( ! array_key_exists( $key, $array2 ) || $value !== $array2[ $key ] ) { if ( $compare ) { return true; } $diff[ $key ] = $value; } // phpcs:ignore Universal.Operators.StrictComparisons.LooseNotEqual -- Intentional when $strict is false. } elseif ( ! array_key_exists( $key, $array2 ) || $value != $array2[ $key ] ) { if ( $compare ) { return true; } $diff[ $key ] = $value; } } return $compare ? false : $diff; } /** * Push a value to an array, but only if the value isn't in the array already. * * @param array $items The array. * @param mixed $value The value to maybe push. * @return bool True if the value has been added to the array, false if the value was already in the array. */ public static function push_once( array &$items, $value ): bool { if ( in_array( $value, $items, true ) ) { return false; } $items[] = $value; return true; } /** * Ensure that an associative array has a given key, and if not, set the key to an empty array. * * @param array $items The array to check. * @param string $key The key to check. * @param bool $throw_if_existing_is_not_array If true, an exception will be thrown if the key already exists in the array but the value is not an array. * @return bool True if the key has been added to the array, false if not (the key already existed). * @throws \Exception The key already exists in the array but the value is not an array. */ public static function ensure_key_is_array( array &$items, string $key, bool $throw_if_existing_is_not_array = false ): bool { if ( ! isset( $items[ $key ] ) ) { $items[ $key ] = array(); return true; } if ( $throw_if_existing_is_not_array && ! is_array( $items[ $key ] ) ) { $type = is_object( $items[ $key ] ) ? get_class( $items[ $key ] ) : gettype( $items[ $key ] ); // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped throw new \Exception( "Array key exists but it's not an array, it's a {$type}" ); } return false; } /** * Given an array of associative arrays, all having a shared key name ("column"), generates a new array in which * keys are the distinct column values found, and values are arrays with all the matches found * (or only the last matching array found, if $single_values is true). * See ArrayUtilTest for examples. * * @param array $items The array to process. * @param string $column The name of the key to group by. * @param bool $single_values True to only return the last suitable array found for each column value. * @return array The grouped array. */ public static function group_by_column( array $items, string $column, bool $single_values = false ): array { if ( $single_values ) { return array_combine( array_column( $items, $column ), array_values( $items ) ); } $distinct_column_values = array_unique( array_column( $items, $column ), SORT_REGULAR ); $result = array_fill_keys( $distinct_column_values, array() ); foreach ( $items as $value ) { $result[ $value[ $column ] ][] = $value; } return $result; } }