1<?php defined('SYSPATH') OR die('No direct access allowed.');
2/**
3 * Array helper class.
4 *
5 * $Id: arr.php 4346 2009-05-11 17:08:15Z zombor $
6 *
7 * @package    Core
8 * @author     Kohana Team
9 * @copyright  (c) 2007-2008 Kohana Team
10 * @license    http://kohanaphp.com/license.html
11 */
12class arr_Core {
13
14	/**
15	 * Return a callback array from a string, eg: limit[10,20] would become
16	 * array('limit', array('10', '20'))
17	 *
18	 * @param   string  callback string
19	 * @return  array
20	 */
21	public static function callback_string($str)
22	{
23		// command[param,param]
24		if (preg_match('/([^\[]*+)\[(.+)\]/', (string) $str, $match))
25		{
26			// command
27			$command = $match[1];
28
29			// param,param
30			$params = preg_split('/(?<!\\\\),/', $match[2]);
31			$params = str_replace('\,', ',', $params);
32		}
33		else
34		{
35			// command
36			$command = $str;
37
38			// No params
39			$params = NULL;
40		}
41
42		return array($command, $params);
43	}
44
45	/**
46	 * Rotates a 2D array clockwise.
47	 * Example, turns a 2x3 array into a 3x2 array.
48	 *
49	 * @param   array    array to rotate
50	 * @param   boolean  keep the keys in the final rotated array. the sub arrays of the source array need to have the same key values.
51	 *                   if your subkeys might not match, you need to pass FALSE here!
52	 * @return  array
53	 */
54	public static function rotate($source_array, $keep_keys = TRUE)
55	{
56		$new_array = array();
57		foreach ($source_array as $key => $value)
58		{
59			$value = ($keep_keys === TRUE) ? $value : array_values($value);
60			foreach ($value as $k => $v)
61			{
62				$new_array[$k][$key] = $v;
63			}
64		}
65
66		return $new_array;
67	}
68
69	/**
70	 * Removes a key from an array and returns the value.
71	 *
72	 * @param   string  key to return
73	 * @param   array   array to work on
74	 * @return  mixed   value of the requested array key
75	 */
76	public static function remove($key, & $array)
77	{
78		if ( ! array_key_exists($key, $array))
79			return NULL;
80
81		$val = $array[$key];
82		unset($array[$key]);
83
84		return $val;
85	}
86
87
88	/**
89	 * Extract one or more keys from an array. Each key given after the first
90	 * argument (the array) will be extracted. Keys that do not exist in the
91	 * search array will be NULL in the extracted data.
92	 *
93	 * @param   array   array to search
94	 * @param   string  key name
95	 * @return  array
96	 */
97	public static function extract(array $search, $keys)
98	{
99		// Get the keys, removing the $search array
100		$keys = array_slice(func_get_args(), 1);
101
102		$found = array();
103		foreach ($keys as $key)
104		{
105			if (isset($search[$key]))
106			{
107				$found[$key] = $search[$key];
108			}
109			else
110			{
111				$found[$key] = NULL;
112			}
113		}
114
115		return $found;
116	}
117
118	/**
119	 * Because PHP does not have this function.
120	 *
121	 * @param   array   array to unshift
122	 * @param   string  key to unshift
123	 * @param   mixed   value to unshift
124	 * @return  array
125	 */
126	public static function unshift_assoc( array & $array, $key, $val)
127	{
128		$array = array_reverse($array, TRUE);
129		$array[$key] = $val;
130		$array = array_reverse($array, TRUE);
131
132		return $array;
133	}
134
135	/**
136	 * Because PHP does not have this function, and array_walk_recursive creates
137	 * references in arrays and is not truly recursive.
138	 *
139	 * @param   mixed  callback to apply to each member of the array
140	 * @param   array  array to map to
141	 * @return  array
142	 */
143	public static function map_recursive($callback, array $array)
144	{
145		foreach ($array as $key => $val)
146		{
147			// Map the callback to the key
148			$array[$key] = is_array($val) ? arr::map_recursive($callback, $val) : call_user_func($callback, $val);
149		}
150
151		return $array;
152	}
153
154	/**
155	 * @param mixed $needle     the value to search for
156	 * @param array $haystack   an array of values to search in
157	 * @param boolean $sort     sort the array now
158	 * @return integer|FALSE    the index of the match or FALSE when not found
159	 */
160	public static function binary_search($needle, $haystack, $sort = FALSE)
161	{
162		if ($sort)
163		{
164			sort($haystack);
165		}
166
167		$high = count($haystack) - 1;
168		$low = 0;
169
170		while ($low <= $high)
171		{
172			$mid = ($low + $high) >> 1;
173
174			if ($haystack[$mid] < $needle)
175			{
176				$low = $mid + 1;
177			}
178			elseif ($haystack[$mid] > $needle)
179			{
180				$high = $mid - 1;
181			}
182			else
183			{
184				return $mid;
185			}
186		}
187
188		return FALSE;
189	}
190
191
192	/**
193	 * Emulates array_merge_recursive, but appends numeric keys and replaces
194	 * associative keys, instead of appending all keys.
195	 *
196	 * @param   array  any number of arrays
197	 * @return  array
198	 */
199	public static function merge()
200	{
201		$total = func_num_args();
202
203		$result = array();
204		for ($i = 0; $i < $total; $i++)
205		{
206			foreach (func_get_arg($i) as $key => $val)
207			{
208				if (isset($result[$key]))
209				{
210					if (is_array($val))
211					{
212						// Arrays are merged recursively
213						$result[$key] = arr::merge($result[$key], $val);
214					}
215					elseif (is_int($key))
216					{
217						// Indexed arrays are appended
218						array_push($result, $val);
219					}
220					else
221					{
222						// Associative arrays are replaced
223						$result[$key] = $val;
224					}
225				}
226				else
227				{
228					// New values are added
229					$result[$key] = $val;
230				}
231			}
232		}
233
234		return $result;
235	}
236
237	/**
238	 * Overwrites an array with values from input array(s).
239	 * Non-existing keys will not be appended!
240	 *
241	 * @param   array   key array
242	 * @param   array   input array(s) that will overwrite key array values
243	 * @return  array
244	 */
245	public static function overwrite($array1, $array2)
246	{
247		foreach (array_intersect_key($array2, $array1) as $key => $value)
248		{
249			$array1[$key] = $value;
250		}
251
252		if (func_num_args() > 2)
253		{
254			foreach (array_slice(func_get_args(), 2) as $array2)
255			{
256				foreach (array_intersect_key($array2, $array1) as $key => $value)
257				{
258					$array1[$key] = $value;
259				}
260			}
261		}
262
263		return $array1;
264	}
265
266	/**
267	 * Fill an array with a range of numbers.
268	 *
269	 * @param   integer  stepping
270	 * @param   integer  ending number
271	 * @return  array
272	 */
273	public static function range($step = 10, $max = 100)
274	{
275		if ($step < 1)
276			return array();
277
278		$array = array();
279		for ($i = $step; $i <= $max; $i += $step)
280		{
281			$array[$i] = $i;
282		}
283
284		return $array;
285	}
286
287	/**
288	 * Recursively convert an array to an object.
289	 *
290	 * @param   array   array to convert
291	 * @return  object
292	 */
293	public static function to_object(array $array, $class = 'stdClass')
294	{
295		$object = new $class;
296
297		foreach ($array as $key => $value)
298		{
299			if (is_array($value))
300			{
301				// Convert the array to an object
302				$value = arr::to_object($value, $class);
303			}
304
305			// Add the value to the object
306			$object->{$key} = $value;
307		}
308
309		return $object;
310	}
311
312} // End arr
313