3 * Zend Framework (http://framework.zend.com/)
5 * @link http://github.com/zendframework/zf2 for the canonical source repository
6 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
7 * @license http://framework.zend.com/license/new-bsd New BSD License
10 namespace Zend\Stdlib;
13 use Zend\Stdlib\ArrayUtils\MergeRemoveKey;
14 use Zend\Stdlib\ArrayUtils\MergeReplaceKeyInterface;
17 * Utility class for testing and manipulation of PHP arrays.
19 * Declared abstract, as we have no need for instantiation.
21 abstract class ArrayUtils
24 * Compatibility Flag for ArrayUtils::filter
26 const ARRAY_FILTER_USE_BOTH = 1;
29 * Compatibility Flag for ArrayUtils::filter
31 const ARRAY_FILTER_USE_KEY = 2;
34 * Test whether an array contains one or more string keys
37 * @param bool $allowEmpty Should an empty array() return true
40 public static function hasStringKeys($value, $allowEmpty = false)
42 if (! is_array($value)) {
50 return count(array_filter(array_keys($value), 'is_string')) > 0;
54 * Test whether an array contains one or more integer keys
57 * @param bool $allowEmpty Should an empty array() return true
60 public static function hasIntegerKeys($value, $allowEmpty = false)
62 if (! is_array($value)) {
70 return count(array_filter(array_keys($value), 'is_int')) > 0;
74 * Test whether an array contains one or more numeric keys.
76 * A numeric key can be one of the following:
78 * - a string with a number '20'
79 * - a string with negative number: '-1000'
80 * - a float: 2.2120, -78.150999
81 * - a string with float: '4000.99999', '-10.10'
84 * @param bool $allowEmpty Should an empty array() return true
87 public static function hasNumericKeys($value, $allowEmpty = false)
89 if (! is_array($value)) {
97 return count(array_filter(array_keys($value), 'is_numeric')) > 0;
101 * Test whether an array is a list
103 * A list is a collection of values assigned to continuous integer keys
104 * starting at 0 and ending at count() - 1.
108 * $list = array('a', 'b', 'c', 'd');
112 * 2 => array('foo' => 'baz'),
116 * @param mixed $value
117 * @param bool $allowEmpty Is an empty list a valid list?
120 public static function isList($value, $allowEmpty = false)
122 if (! is_array($value)) {
130 return (array_values($value) === $value);
134 * Test whether an array is a hash table.
136 * An array is a hash table if:
138 * 1. Contains one or more non-integer keys, or
139 * 2. Integer keys are non-continuous or misaligned (not starting with 0)
148 * 1995 => 'Birth of PHP',
149 * 2009 => 'PHP 5.3.0',
150 * 2012 => 'PHP 5.4.0',
154 * 'options' => array( 'debug' => true ),
158 * @param mixed $value
159 * @param bool $allowEmpty Is an empty array() a valid hash table?
162 public static function isHashTable($value, $allowEmpty = false)
164 if (! is_array($value)) {
172 return (array_values($value) !== $value);
176 * Checks if a value exists in an array.
178 * Due to "foo" == 0 === TRUE with in_array when strict = false, an option
179 * has been added to prevent this. When $strict = 0/false, the most secure
180 * non-strict check is implemented. if $strict = -1, the default in_array
181 * non-strict behaviour is used.
183 * @param mixed $needle
184 * @param array $haystack
185 * @param int|bool $strict
188 public static function inArray($needle, array $haystack, $strict = false)
191 if (is_int($needle) || is_float($needle)) {
192 $needle = (string) $needle;
194 if (is_string($needle)) {
195 foreach ($haystack as &$h) {
196 if (is_int($h) || is_float($h)) {
202 return in_array($needle, $haystack, $strict);
206 * Convert an iterator to an array.
208 * Converts an iterator to an array. The $recursive flag, on by default,
209 * hints whether or not you want to do so recursively.
211 * @param array|Traversable $iterator The array or Traversable object to convert
212 * @param bool $recursive Recursively check all nested structures
213 * @throws Exception\InvalidArgumentException if $iterator is not an array or a Traversable object
216 public static function iteratorToArray($iterator, $recursive = true)
218 if (! is_array($iterator) && ! $iterator instanceof Traversable) {
219 throw new Exception\InvalidArgumentException(__METHOD__ . ' expects an array or Traversable object');
223 if (is_array($iterator)) {
227 return iterator_to_array($iterator);
230 if (method_exists($iterator, 'toArray')) {
231 return $iterator->toArray();
235 foreach ($iterator as $key => $value) {
236 if (is_scalar($value)) {
237 $array[$key] = $value;
241 if ($value instanceof Traversable) {
242 $array[$key] = static::iteratorToArray($value, $recursive);
246 if (is_array($value)) {
247 $array[$key] = static::iteratorToArray($value, $recursive);
251 $array[$key] = $value;
258 * Merge two arrays together.
260 * If an integer key exists in both arrays and preserveNumericKeys is false, the value
261 * from the second array will be appended to the first array. If both values are arrays, they
262 * are merged together, else the value of the second array overwrites the one of the first array.
266 * @param bool $preserveNumericKeys
269 public static function merge(array $a, array $b, $preserveNumericKeys = false)
271 foreach ($b as $key => $value) {
272 if ($value instanceof MergeReplaceKeyInterface) {
273 $a[$key] = $value->getData();
274 } elseif (isset($a[$key]) || array_key_exists($key, $a)) {
275 if ($value instanceof MergeRemoveKey) {
277 } elseif (! $preserveNumericKeys && is_int($key)) {
279 } elseif (is_array($value) && is_array($a[$key])) {
280 $a[$key] = static::merge($a[$key], $value, $preserveNumericKeys);
285 if (! $value instanceof MergeRemoveKey) {
295 * @deprecated Since 3.2.0; use the native array_filter methods
298 * @param callable $callback
299 * @param null|int $flag
301 * @throws Exception\InvalidArgumentException
303 public static function filter(array $data, $callback, $flag = null)
305 if (! is_callable($callback)) {
306 throw new Exception\InvalidArgumentException(sprintf(
307 'Second parameter of %s must be callable',
312 return array_filter($data, $callback, $flag);