2015-08-17 17:00:26 -07:00
< ? php
/**
* Zend Framework ( http :// framework . zend . com / )
*
* @ link http :// github . com / zendframework / zf2 for the canonical source repository
* @ copyright Copyright ( c ) 2005 - 2015 Zend Technologies USA Inc . ( http :// www . zend . com )
* @ license http :// framework . zend . com / license / new - bsd New BSD License
*/
namespace Zend\Stdlib ;
use Traversable ;
use Zend\Stdlib\ArrayUtils\MergeRemoveKey ;
use Zend\Stdlib\ArrayUtils\MergeReplaceKeyInterface ;
/**
* Utility class for testing and manipulation of PHP arrays .
*
* Declared abstract , as we have no need for instantiation .
*/
abstract class ArrayUtils
{
/**
* Compatibility Flag for ArrayUtils :: filter
*/
const ARRAY_FILTER_USE_BOTH = 1 ;
/**
* Compatibility Flag for ArrayUtils :: filter
*/
const ARRAY_FILTER_USE_KEY = 2 ;
/**
* Test whether an array contains one or more string keys
*
* @ param mixed $value
* @ param bool $allowEmpty Should an empty array () return true
* @ return bool
*/
public static function hasStringKeys ( $value , $allowEmpty = false )
{
if ( ! is_array ( $value )) {
return false ;
}
if ( ! $value ) {
return $allowEmpty ;
}
return count ( array_filter ( array_keys ( $value ), 'is_string' )) > 0 ;
}
/**
* Test whether an array contains one or more integer keys
*
* @ param mixed $value
* @ param bool $allowEmpty Should an empty array () return true
* @ return bool
*/
public static function hasIntegerKeys ( $value , $allowEmpty = false )
{
if ( ! is_array ( $value )) {
return false ;
}
if ( ! $value ) {
return $allowEmpty ;
}
return count ( array_filter ( array_keys ( $value ), 'is_int' )) > 0 ;
}
/**
* Test whether an array contains one or more numeric keys .
*
* A numeric key can be one of the following :
* - an integer 1 ,
* - a string with a number '20'
* - a string with negative number : '-1000'
* - a float : 2.2120 , - 78.150999
* - a string with float : '4000.99999' , '-10.10'
*
* @ param mixed $value
* @ param bool $allowEmpty Should an empty array () return true
* @ return bool
*/
public static function hasNumericKeys ( $value , $allowEmpty = false )
{
if ( ! is_array ( $value )) {
return false ;
}
if ( ! $value ) {
return $allowEmpty ;
}
return count ( array_filter ( array_keys ( $value ), 'is_numeric' )) > 0 ;
}
/**
* Test whether an array is a list
*
* A list is a collection of values assigned to continuous integer keys
* starting at 0 and ending at count () - 1.
*
* For example :
* < code >
* $list = array ( 'a' , 'b' , 'c' , 'd' );
* $list = array (
* 0 => 'foo' ,
* 1 => 'bar' ,
* 2 => array ( 'foo' => 'baz' ),
* );
* </ code >
*
* @ param mixed $value
* @ param bool $allowEmpty Is an empty list a valid list ?
* @ return bool
*/
public static function isList ( $value , $allowEmpty = false )
{
if ( ! is_array ( $value )) {
return false ;
}
if ( ! $value ) {
return $allowEmpty ;
}
return ( array_values ( $value ) === $value );
}
/**
* Test whether an array is a hash table .
*
* An array is a hash table if :
*
* 1. Contains one or more non - integer keys , or
* 2. Integer keys are non - continuous or misaligned ( not starting with 0 )
*
* For example :
* < code >
* $hash = array (
* 'foo' => 15 ,
* 'bar' => false ,
* );
* $hash = array (
* 1995 => 'Birth of PHP' ,
* 2009 => 'PHP 5.3.0' ,
* 2012 => 'PHP 5.4.0' ,
* );
* $hash = array (
* ' formElement ,
* 'options' => array ( 'debug' => true ),
* );
* </ code >
*
* @ param mixed $value
* @ param bool $allowEmpty Is an empty array () a valid hash table ?
* @ return bool
*/
public static function isHashTable ( $value , $allowEmpty = false )
{
if ( ! is_array ( $value )) {
return false ;
}
if ( ! $value ) {
return $allowEmpty ;
}
return ( array_values ( $value ) !== $value );
}
/**
* Checks if a value exists in an array .
*
* Due to " foo " == 0 === TRUE with in_array when strict = false , an option
* has been added to prevent this . When $strict = 0 / false , the most secure
* non - strict check is implemented . if $strict = - 1 , the default in_array
* non - strict behaviour is used .
*
* @ param mixed $needle
* @ param array $haystack
* @ param int | bool $strict
* @ return bool
*/
public static function inArray ( $needle , array $haystack , $strict = false )
{
if ( ! $strict ) {
if ( is_int ( $needle ) || is_float ( $needle )) {
$needle = ( string ) $needle ;
}
if ( is_string ( $needle )) {
foreach ( $haystack as & $h ) {
if ( is_int ( $h ) || is_float ( $h )) {
$h = ( string ) $h ;
}
}
}
}
return in_array ( $needle , $haystack , $strict );
}
/**
* Convert an iterator to an array .
*
* Converts an iterator to an array . The $recursive flag , on by default ,
* hints whether or not you want to do so recursively .
*
* @ param array | Traversable $iterator The array or Traversable object to convert
* @ param bool $recursive Recursively check all nested structures
* @ throws Exception\InvalidArgumentException if $iterator is not an array or a Traversable object
* @ return array
*/
public static function iteratorToArray ( $iterator , $recursive = true )
{
if ( ! is_array ( $iterator ) && ! $iterator instanceof Traversable ) {
throw new Exception\InvalidArgumentException ( __METHOD__ . ' expects an array or Traversable object' );
}
if ( ! $recursive ) {
if ( is_array ( $iterator )) {
return $iterator ;
}
return iterator_to_array ( $iterator );
}
if ( method_exists ( $iterator , 'toArray' )) {
return $iterator -> toArray ();
}
2015-10-08 11:40:12 -07:00
$array = [];
2015-08-17 17:00:26 -07:00
foreach ( $iterator as $key => $value ) {
if ( is_scalar ( $value )) {
$array [ $key ] = $value ;
continue ;
}
if ( $value instanceof Traversable ) {
$array [ $key ] = static :: iteratorToArray ( $value , $recursive );
continue ;
}
if ( is_array ( $value )) {
$array [ $key ] = static :: iteratorToArray ( $value , $recursive );
continue ;
}
$array [ $key ] = $value ;
}
return $array ;
}
/**
* Merge two arrays together .
*
* If an integer key exists in both arrays and preserveNumericKeys is false , the value
* from the second array will be appended to the first array . If both values are arrays , they
* are merged together , else the value of the second array overwrites the one of the first array .
*
* @ param array $a
* @ param array $b
* @ param bool $preserveNumericKeys
* @ return array
*/
public static function merge ( array $a , array $b , $preserveNumericKeys = false )
{
foreach ( $b as $key => $value ) {
if ( $value instanceof MergeReplaceKeyInterface ) {
$a [ $key ] = $value -> getData ();
} elseif ( isset ( $a [ $key ]) || array_key_exists ( $key , $a )) {
if ( $value instanceof MergeRemoveKey ) {
unset ( $a [ $key ]);
} elseif ( ! $preserveNumericKeys && is_int ( $key )) {
$a [] = $value ;
} elseif ( is_array ( $value ) && is_array ( $a [ $key ])) {
$a [ $key ] = static :: merge ( $a [ $key ], $value , $preserveNumericKeys );
} else {
$a [ $key ] = $value ;
}
} else {
if ( ! $value instanceof MergeRemoveKey ) {
$a [ $key ] = $value ;
}
}
}
return $a ;
}
/**
* Compatibility Method for array_filter on < 5.6 systems
*
* @ param array $data
* @ param callable $callback
* @ param null | int $flag
* @ return array
*/
public static function filter ( array $data , $callback , $flag = null )
{
if ( ! is_callable ( $callback )) {
throw new Exception\InvalidArgumentException ( sprintf (
'Second parameter of %s must be callable' ,
__METHOD__
));
}
if ( version_compare ( PHP_VERSION , '5.6.0' ) >= 0 ) {
return array_filter ( $data , $callback , $flag );
}
2015-10-08 11:40:12 -07:00
$output = [];
2015-08-17 17:00:26 -07:00
foreach ( $data as $key => $value ) {
2015-10-08 11:40:12 -07:00
$params = [ $value ];
2015-08-17 17:00:26 -07:00
if ( $flag === static :: ARRAY_FILTER_USE_BOTH ) {
$params [] = $key ;
}
if ( $flag === static :: ARRAY_FILTER_USE_KEY ) {
2015-10-08 11:40:12 -07:00
$params = [ $key ];
2015-08-17 17:00:26 -07:00
}
$response = call_user_func_array ( $callback , $params );
if ( $response ) {
$output [ $key ] = $value ;
}
}
return $output ;
}
}