contentserialize-8.x-1.x-dev/src/Traversables.php
src/Traversables.php
<?php namespace Drupal\contentserialize; /** * Helper functions for dealing with generators and traversables. * * If autoloading wasn't an issue they wouldn't be in a class. */ class Traversables { /** * Split the source into chunks. * * Chunks the source into arrays with size elements. The last chunk may * contain less than size elements. * * @param mixed $source * The source generator, traversable or array. * @param int $size * The size of each chunk. * @param bool $preserve_keys * When set to TRUE keys will be preserved. Default is FALSE which will * reindex the chunk numerically * * @return \Generator */ public static function chunk($source, $size, $preserve_keys = FALSE) { $batch = []; $i = 0; // Use foreach to be compatible with arrays, generators and traversables. foreach ($source as $key => $value) { $batch[$preserve_keys ? $key : $i] = $value; $i++; if ($i == $size) { $i = 0; yield $batch; $batch = []; } } // Unless the number of elements is a multiple of the batch size there will // be leftovers. if ($batch) { yield $batch; } } /** * Ensures the output never returns the same key twice. * * It keeps a cache of seen keys so memory usage increases with unique key * count. * * @param mixed $source * The source generator, traversable or array. * * @return \Generator */ public static function uniqueByKey($source) { $ids = []; foreach ($source as $key => $value) { if (empty($ids[$key])) { yield $key => $value; $ids[$key] = TRUE; } } } /** * Return a limited number of elements from a source. * * @param mixed $source * A generator/traversable. * @param int $count * The maximum number of elements to yield. * @return \Generator * Up to $count elements from $source. */ public static function truncate($source, $count) { $yielded = 0; foreach ($source as $key => $value) { if ($yielded == $count) { return; } yield $key => $value; $yielded++; } } /** * Filters elements of a generator/traversable using a callback function. * * Iterates over each value in $input passing them to the callback function. * If the callback function returns true, the value is yielded. * * @param $input * The generator/traversable to iterate over. * @param callable|null $callback * (optional) The callback function to use; if no callback is supplied, all * elements equal (==) to FALSE will be removed. * @param int $flag * (optional) Flag determining what arguments are sent to callback: * - ARRAY_FILTER_USE_KEY: pass key as the only argument to callback instead * of the value. * - ARRAY_FILTER_USE_BOTH: pass both value and key as arguments to callback * instead of the value. * It defaults to passing just the value to the callback. * * @return \Generator * Elements of $input that haven't been filtered out. * * @throws \InvalidArgumentException * If an invalid flag is passed. */ public static function filter($input, callable $callback = NULL, $flag = 0) { foreach ($input as $key => $value) { if ($callback) { switch ($flag) { case 0: $result = $callback($value); break; case ARRAY_FILTER_USE_BOTH: $result = $callback($value, $key); break; case ARRAY_FILTER_USE_KEY: $result = $callback($key); break; default: throw new \InvalidArgumentException("Invalid flag passed: $flag"); } } else { $result = $value; } if ($result) { yield $key => $value; } } } /** * Merge multiple generators/traversables into a single source. * * It doesn't compare keys, it just appends the sources together. * * @param ...$sources * Generators/traversables to merge together. * * @return \Generator */ public static function merge(...$sources) { foreach ($sources as $source) { yield from $source; } } }