Last active
October 6, 2017 21:40
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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