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;
}
}