Skip to content

Instantly share code, notes, and snippets.

@joshuaadickerson
Created March 25, 2014 15:50
Show Gist options
  • Select an option

  • Save joshuaadickerson/9764759 to your computer and use it in GitHub Desktop.

Select an option

Save joshuaadickerson/9764759 to your computer and use it in GitHub Desktop.
<?php
/**
* Every method is chainable
* Instead of throwing errors, it throws exceptions
* All exceptions should show the name of the method throwing it to make it easier to debug
*
* @todo throw exceptions if argument is not the appropriate type
*/
class ArrayChainable extends \ArrayObject
{
// parent::$container
/**
* @see array_change_key_case
* @link http://www.php.net/manual/en/function.array-change-key-case.php
*
* @param int $case CASE_UPPER or CASE_LOWER
* @return \ArrayChainable
*/
public function changeKeyCase($case)
{
$this->container = array_change_key_case($this->container, $case);
return $this;
}
/**
* @see array_chunk
* @link http://www.php.net/manual/en/function.array-chunk.php
*
* @param int $size
* @param bool $preserve_keys = false
* @return \ArrayChainable
* @throws ArrayException when $size is less than 1
*/
public function chunk($size, $preserve_keys = false)
{
if ($size < 1)
{
throw new ArrayException('ArrayChainable::chunk() $size must be greater than 0');
}
$this->container = array_chunk($this->container, (int) $size, (bool) $preserve_keys);
return $this;
}
//array array_column ( array $array , mixed $column_key [, mixed $index_key = null ] )
public function column($column_key, $index_key = null)
{
$this->container = array_column($this->container, $column_key, $index_key);
return $this;
}
// array array_combine ( array $keys , array $values )
public function combine(array $values)
{
$num_keys = count($this->container);
$num_values = count($values);
// The number of keys and values must match
if ($num_keys !== $num_values)
{
throw new ArrayException('ArrayChainable::combine() the number of elements in the keys array is ' . $num_keys . ' and the number of elements in the values array is ' . $num_values . '. They must be equal.');
}
$this->container = array_combine($this->container, $values);
return $this;
}
// @todo return an array or change $container?
// @todo throw an exception (meaning it requires going through it manually) or return E_WARNING?
// @todo allow for recursive?
public function count_values()
{
$count_values = array();
foreach ($this->container as $key => $value)
{
if (!is_int($value) || !is_string($value))
{
throw new ArrayException('ArrayChainable::count_values() the value at ' . $key . ' is not an integer or string.');
}
$count_values[$value]++;
}
$this->container = $count_values;
return $this;
}
public function diff_assoc()
{
if (func_num_args() < 1)
{
throw new ArrayException('ArrayChainable::diff_assoc() must have at least one argument.');
}
$arrays = func_get_args();
$this->container = call_user_func_array('array_diff_assoc', array_unshift($this->container, $arrays));
return $this;
}
public function diff_key()
{
if (func_num_args() < 1)
{
throw new ArrayException('ArrayChainable::diff_key() must have at least one argument.');
}
$arrays = func_get_args();
$this->container = call_user_func_array('array_diff_key', array_unshift($this->container, $arrays));
return $this;
}
// array array_diff_uassoc ( array $array1 , array $array2 [, array $... ], callable $key_compare_func )
// @todo ew, the argument order is ugly
public function diff_uassoc()
{
if (func_num_args() < 1)
{
throw new ArrayException('ArrayChainable::diff_uassoc() must have at least one argument.');
}
$arrays = func_get_args();
if (!is_callable(end($arrays)))
{
throw new ArrayException('The last argument must be a callback.');
}
$this->container = call_user_func_array('array_diff_uassoc', array_unshift($this->container, $arrays));
return $this;
}
// array array_diff_ukey ( array $array1 , array $array2 [, array $... ], callable $key_compare_func )
// @todo ew, the argument order is ugly
public function diff_ukey()
{
if (func_num_args() < 1)
{
throw new ArrayException('ArrayChainable::diff_ukey() must have at least one argument.');
}
$arrays = func_get_args();
if (!is_callable(end($arrays)))
{
throw new ArrayException('The last argument must be a callback.');
}
$this->container = call_user_func_array('array_diff_ukey', array_unshift($this->container, $arrays));
return $this;
}
public function diff()
{
if (func_num_args() < 1)
{
throw new ArrayException('ArrayChainable::diff() must have at least one argument.');
}
$arrays = func_get_args();
$this->container = call_user_func_array('array_diff', array_unshift($this->container, $arrays));
return $this;
}
public function fill_keys(array $keys, $value)
{
$this->container = array_fill_keys($keys, $value);
return $this;
}
// array array_fill ( int $start_index , int $num , mixed $value )
public function fill($start_index, $num, $value)
{
if ((int) $num < 1)
{
throw new ArrayException('ArrayChainable::fill() $num must be greater than 0; "' . $num . '" given.');
}
$this->container = array_fill((int) $start_index, (int) $num, $value);
return $this;
}
// array array_filter ( array $array [, callable $callback ] )
public function filter($callback = null)
{
$this->container = array_filter($this->container, $callback);
return $this;
}
public function flip()
{
$this->container = array_flip($this->container);
return $this;
}
// array array_intersect_assoc ( array $array1 , array $array2 [, array $... ] )
public function intersect_assoc()
{
if (func_num_args() < 1)
{
throw new ArrayException('ArrayChainable::intersect_assoc() must have at least one argument.');
}
$arrays = array_unshift($this->container, func_get_args());
$this->container = call_user_func_array('array_intersect_assoc', $arrays);
return $this;
}
// array array_intersect_assoc ( array $array1 , array $array2 [, array $... ] )
public function intersect_key()
{
if (func_num_args() < 1)
{
throw new ArrayException('ArrayChainable::intersect_key() must have at least one argument.');
}
$arrays = array_unshift($this->container, func_get_args());
$this->container = call_user_func_array('array_intersect_key', $arrays);
return $this;
}
public function intersect_uassoc()
{
if (func_num_args() < 1)
{
throw new ArrayException('ArrayChainable::intersect_uassoc() must have at least one argument.');
}
$arrays = func_get_args();
if (!is_callable(end($arrays)))
{
throw new ArrayException('The last argument must be a callback.');
}
$this->container = call_user_func_array('array_intersect_uassoc', array_unshift($this->container, $arrays));
return $this;
}
public function intersect_ukey()
{
if (func_num_args() < 1)
{
throw new ArrayException('ArrayChainable::intersect_ukey() must have at least one argument.');
}
$arrays = func_get_args();
if (!is_callable(end($arrays)))
{
throw new ArrayException('ArrayChainable::intersect_ukey() the last argument must be a callback.');
}
$this->container = call_user_func_array('array_intersect_ukey', array_unshift($this->container, $arrays));
return $this;
}
public function intersect()
{
if (func_num_args() < 1)
{
throw new ArrayException('ArrayChainable::intersect() must have at least one argument.');
}
$arrays = array_unshift($this->container, func_get_args());
$this->container = call_user_func_array('array_intersect', $arrays);
return $this;
}
// skip array_key_exists() as it is already done via ArrayObject::offsetExists()
public function keys($search_value = null, $strict = false)
{
$this->container = array_keys($this->container, $search_value, (bool) $strict);
return $this;
}
// array array_map ( callable $callback , array $array1 [, array $... ] )
public function map()
{
if (func_num_args() < 2)
{
throw new ArrayException('ArrayChainable::map() must have at least two arguments');
}
$args = func_get_args();
$callback = shift($args);
if (!is_callable($callback))
{
throw new ArrayException('ArrayChainable::map() the first argument must be a callback.');
}
$this->container = call_user_func_array('array_intersect_uassoc', array_merge(array($callback, $this->container), $args));
return $this;
}
// @todo even though array_merge_recursive() only requires one argument, maybe throw an exception if only one is given?
public function merge_recursive()
{
$arrays = array_unshift($this->container, func_get_args());
$this->container = call_user_func_array('array_merge_recursive', $arrays);
return $this;
}
// @todo even though array_merge() only requires one argument, maybe throw an exception if only one is given?
public function merge()
{
$arrays = array_unshift($this->container, func_get_args());
$this->container = call_user_func_array('array_merge', $arrays);
return $this;
}
public function multisort()
{
$arrays = array_unshift($this->container, func_get_args());
$result = call_user_func_array('array_multisort', $arrays);
if (!$result)
{
throw new ArrayException('ArrayChainable::multisort() failed to sort the array');
}
$this->container = $arrays[0];
return $this;
}
public function pad($size, $value)
{
$this->container = array_pad($this->container, (int) $size, $value);
return $this;
}
// skipping array_pop
public function push()
{
$this->container = array_merge($this->container, func_get_args());
return $this;
}
}
<?php
class ArrayException extends \Exception
{
}
<?php
class SuperArray extends ArrayChainable
{
public function pop()
{
return array_pop($this->container);
}
public function key_exists($key)
{
return array_key_exists($key, $this->container);
}
public function product()
{
return array_product($this->container);
}
public function push()
{
$this->container = array_merge($this->container, func_get_args());
return $this->count();
}
public function rand($num = 1)
{
$num = (int) $num;
$count = $this->count();
if ($num > $count)
{
throw new ArrayException('SuperArray::rand() $num cannot be greater than the number of elements in the array. Number of elements is ' . $count . ' and $num is ' . $num);
}
return array_rand($this->container, (int) $num);
}
public function reduce(callable $callback, $initial = null)
{
return array_reduce($this->container, $callback, $initial);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment