Chris@0: 0;
Chris@0: }
Chris@0:
Chris@0: /**
Chris@0: * Test whether an array contains one or more integer keys
Chris@0: *
Chris@0: * @param mixed $value
Chris@0: * @param bool $allowEmpty Should an empty array() return true
Chris@0: * @return bool
Chris@0: */
Chris@0: public static function hasIntegerKeys($value, $allowEmpty = false)
Chris@0: {
Chris@12: if (! is_array($value)) {
Chris@0: return false;
Chris@0: }
Chris@0:
Chris@12: if (! $value) {
Chris@0: return $allowEmpty;
Chris@0: }
Chris@0:
Chris@0: return count(array_filter(array_keys($value), 'is_int')) > 0;
Chris@0: }
Chris@0:
Chris@0: /**
Chris@0: * Test whether an array contains one or more numeric keys.
Chris@0: *
Chris@0: * A numeric key can be one of the following:
Chris@0: * - an integer 1,
Chris@0: * - a string with a number '20'
Chris@0: * - a string with negative number: '-1000'
Chris@0: * - a float: 2.2120, -78.150999
Chris@0: * - a string with float: '4000.99999', '-10.10'
Chris@0: *
Chris@0: * @param mixed $value
Chris@0: * @param bool $allowEmpty Should an empty array() return true
Chris@0: * @return bool
Chris@0: */
Chris@0: public static function hasNumericKeys($value, $allowEmpty = false)
Chris@0: {
Chris@12: if (! is_array($value)) {
Chris@0: return false;
Chris@0: }
Chris@0:
Chris@12: if (! $value) {
Chris@0: return $allowEmpty;
Chris@0: }
Chris@0:
Chris@0: return count(array_filter(array_keys($value), 'is_numeric')) > 0;
Chris@0: }
Chris@0:
Chris@0: /**
Chris@0: * Test whether an array is a list
Chris@0: *
Chris@0: * A list is a collection of values assigned to continuous integer keys
Chris@0: * starting at 0 and ending at count() - 1.
Chris@0: *
Chris@0: * For example:
Chris@0: *
Chris@0: * $list = array('a', 'b', 'c', 'd');
Chris@0: * $list = array(
Chris@0: * 0 => 'foo',
Chris@0: * 1 => 'bar',
Chris@0: * 2 => array('foo' => 'baz'),
Chris@0: * );
Chris@0: *
Chris@0: *
Chris@0: * @param mixed $value
Chris@0: * @param bool $allowEmpty Is an empty list a valid list?
Chris@0: * @return bool
Chris@0: */
Chris@0: public static function isList($value, $allowEmpty = false)
Chris@0: {
Chris@12: if (! is_array($value)) {
Chris@0: return false;
Chris@0: }
Chris@0:
Chris@12: if (! $value) {
Chris@0: return $allowEmpty;
Chris@0: }
Chris@0:
Chris@0: return (array_values($value) === $value);
Chris@0: }
Chris@0:
Chris@0: /**
Chris@0: * Test whether an array is a hash table.
Chris@0: *
Chris@0: * An array is a hash table if:
Chris@0: *
Chris@0: * 1. Contains one or more non-integer keys, or
Chris@0: * 2. Integer keys are non-continuous or misaligned (not starting with 0)
Chris@0: *
Chris@0: * For example:
Chris@0: *
Chris@0: * $hash = array(
Chris@0: * 'foo' => 15,
Chris@0: * 'bar' => false,
Chris@0: * );
Chris@0: * $hash = array(
Chris@0: * 1995 => 'Birth of PHP',
Chris@0: * 2009 => 'PHP 5.3.0',
Chris@0: * 2012 => 'PHP 5.4.0',
Chris@0: * );
Chris@0: * $hash = array(
Chris@0: * 'formElement,
Chris@0: * 'options' => array( 'debug' => true ),
Chris@0: * );
Chris@0: *
Chris@0: *
Chris@0: * @param mixed $value
Chris@0: * @param bool $allowEmpty Is an empty array() a valid hash table?
Chris@0: * @return bool
Chris@0: */
Chris@0: public static function isHashTable($value, $allowEmpty = false)
Chris@0: {
Chris@12: if (! is_array($value)) {
Chris@0: return false;
Chris@0: }
Chris@0:
Chris@12: if (! $value) {
Chris@0: return $allowEmpty;
Chris@0: }
Chris@0:
Chris@0: return (array_values($value) !== $value);
Chris@0: }
Chris@0:
Chris@0: /**
Chris@0: * Checks if a value exists in an array.
Chris@0: *
Chris@0: * Due to "foo" == 0 === TRUE with in_array when strict = false, an option
Chris@0: * has been added to prevent this. When $strict = 0/false, the most secure
Chris@0: * non-strict check is implemented. if $strict = -1, the default in_array
Chris@0: * non-strict behaviour is used.
Chris@0: *
Chris@0: * @param mixed $needle
Chris@0: * @param array $haystack
Chris@0: * @param int|bool $strict
Chris@0: * @return bool
Chris@0: */
Chris@0: public static function inArray($needle, array $haystack, $strict = false)
Chris@0: {
Chris@12: if (! $strict) {
Chris@0: if (is_int($needle) || is_float($needle)) {
Chris@0: $needle = (string) $needle;
Chris@0: }
Chris@0: if (is_string($needle)) {
Chris@0: foreach ($haystack as &$h) {
Chris@0: if (is_int($h) || is_float($h)) {
Chris@0: $h = (string) $h;
Chris@0: }
Chris@0: }
Chris@0: }
Chris@0: }
Chris@0: return in_array($needle, $haystack, $strict);
Chris@0: }
Chris@0:
Chris@0: /**
Chris@0: * Convert an iterator to an array.
Chris@0: *
Chris@0: * Converts an iterator to an array. The $recursive flag, on by default,
Chris@0: * hints whether or not you want to do so recursively.
Chris@0: *
Chris@0: * @param array|Traversable $iterator The array or Traversable object to convert
Chris@0: * @param bool $recursive Recursively check all nested structures
Chris@0: * @throws Exception\InvalidArgumentException if $iterator is not an array or a Traversable object
Chris@0: * @return array
Chris@0: */
Chris@0: public static function iteratorToArray($iterator, $recursive = true)
Chris@0: {
Chris@12: if (! is_array($iterator) && ! $iterator instanceof Traversable) {
Chris@0: throw new Exception\InvalidArgumentException(__METHOD__ . ' expects an array or Traversable object');
Chris@0: }
Chris@0:
Chris@12: if (! $recursive) {
Chris@0: if (is_array($iterator)) {
Chris@0: return $iterator;
Chris@0: }
Chris@0:
Chris@0: return iterator_to_array($iterator);
Chris@0: }
Chris@0:
Chris@0: if (method_exists($iterator, 'toArray')) {
Chris@0: return $iterator->toArray();
Chris@0: }
Chris@0:
Chris@0: $array = [];
Chris@0: foreach ($iterator as $key => $value) {
Chris@0: if (is_scalar($value)) {
Chris@0: $array[$key] = $value;
Chris@0: continue;
Chris@0: }
Chris@0:
Chris@0: if ($value instanceof Traversable) {
Chris@0: $array[$key] = static::iteratorToArray($value, $recursive);
Chris@0: continue;
Chris@0: }
Chris@0:
Chris@0: if (is_array($value)) {
Chris@0: $array[$key] = static::iteratorToArray($value, $recursive);
Chris@0: continue;
Chris@0: }
Chris@0:
Chris@0: $array[$key] = $value;
Chris@0: }
Chris@0:
Chris@0: return $array;
Chris@0: }
Chris@0:
Chris@0: /**
Chris@0: * Merge two arrays together.
Chris@0: *
Chris@0: * If an integer key exists in both arrays and preserveNumericKeys is false, the value
Chris@0: * from the second array will be appended to the first array. If both values are arrays, they
Chris@0: * are merged together, else the value of the second array overwrites the one of the first array.
Chris@0: *
Chris@0: * @param array $a
Chris@0: * @param array $b
Chris@0: * @param bool $preserveNumericKeys
Chris@0: * @return array
Chris@0: */
Chris@0: public static function merge(array $a, array $b, $preserveNumericKeys = false)
Chris@0: {
Chris@0: foreach ($b as $key => $value) {
Chris@0: if ($value instanceof MergeReplaceKeyInterface) {
Chris@0: $a[$key] = $value->getData();
Chris@0: } elseif (isset($a[$key]) || array_key_exists($key, $a)) {
Chris@0: if ($value instanceof MergeRemoveKey) {
Chris@0: unset($a[$key]);
Chris@12: } elseif (! $preserveNumericKeys && is_int($key)) {
Chris@0: $a[] = $value;
Chris@0: } elseif (is_array($value) && is_array($a[$key])) {
Chris@0: $a[$key] = static::merge($a[$key], $value, $preserveNumericKeys);
Chris@0: } else {
Chris@0: $a[$key] = $value;
Chris@0: }
Chris@0: } else {
Chris@12: if (! $value instanceof MergeRemoveKey) {
Chris@0: $a[$key] = $value;
Chris@0: }
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: return $a;
Chris@0: }
Chris@0:
Chris@0: /**
Chris@16: * @deprecated Since 3.2.0; use the native array_filter methods
Chris@0: *
Chris@0: * @param array $data
Chris@0: * @param callable $callback
Chris@0: * @param null|int $flag
Chris@0: * @return array
Chris@16: * @throws Exception\InvalidArgumentException
Chris@0: */
Chris@0: public static function filter(array $data, $callback, $flag = null)
Chris@0: {
Chris@0: if (! is_callable($callback)) {
Chris@0: throw new Exception\InvalidArgumentException(sprintf(
Chris@0: 'Second parameter of %s must be callable',
Chris@0: __METHOD__
Chris@0: ));
Chris@0: }
Chris@0:
Chris@16: return array_filter($data, $callback, $flag);
Chris@0: }
Chris@0: }