Skip to content

Instantly share code, notes, and snippets.

@lgedeon
Last active October 6, 2017 21:40
Show Gist options
  • Save lgedeon/63816ec49770cd7c145aa1eb81fedd3f to your computer and use it in GitHub Desktop.
Save lgedeon/63816ec49770cd7c145aa1eb81fedd3f to your computer and use it in GitHub Desktop.
Call a function on each combination of the values of multiple arrays. When array_map etc. isn't enough.
<?php
/**
* Call a function on each combination of the values of multiple arrays.
*
* First parameter should by a callable function name or an array with the
* following key value pairs:
*
* 'callback' string A callable function or method name.
* 'break_early' boolean True if function can quit early.
* 'break_on' mixed Value that if returned by callback will short-circuit iteration.
*
* The second and following parameters should be arrays of values to be passed into the
* callback function.
*
* Example:
* do_with_arrays( 'printf', '%s %s, ', array('red','green','yellow'),array('apples','peppers'));
*
* Prints: red apples, red peppers, green apples, green peppers, yellow apples, yellow peppers,
*
* @return mixed An nested array of values returned from callback or the break_on value.
*/
function do_with_arrays() {
// Function accepts multiple arrays to iterate through.
$arrays = func_get_args();
$args = array();
/**
* The first argument is either the function we call on each combination of values
* requested or an array of additional arguments.
*/
$first_arg = array_shift( $arrays );
if ( is_callable( $first_arg ) ) {
$args['callback'] = $first_arg;
} elseif ( isset( $first_arg['callback'] ) && is_callable( $args['callback'] ) ) {
$args = $first_arg;
} else {
return false;
}
// Set defaults for breaking early.
$args = array_merge( array(
'break_early' => false,
'break_on' => false,
), $args );
// Values are set up, now start doing the real work.
return _private_do_with_arrays( $args, $arrays );
}
/**
* Not intended to be called directly. Parameters are set up inside do_with_arrays
* so that this function can focus on recursion.
*
*/
function _private_do_with_arrays( $args, $arrays ) {
$results = array();
foreach ( $arrays as $position => $array ) {
if ( is_array( $array ) ) {
// Replace the first array we find with each of its values and recurse.
foreach ( $array as $key => $value ) {
$arrays[ $position ] = $value;
// Call this function again to loop through the next array.
$results[ $key ] = _private_do_with_arrays( $args, $arrays );
// If we allow breaking early and have found break-on value, return.
if ( $args['break_early'] && $args['break_on'] === $results[ $key ] ) {
return $results[ $key ];
}
}
return $results;
}
}
/**
* If we haven't returned yet, none of the values in $arrays are really arrays and
* we can finally do what we were created to do.
*/
return call_user_func_array( $args['callback'], $arrays );
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment