<?php 
/** 
 * Allows to use FP-like features for arrays, strings, SPL iterators and even results 
 * returned from callbacks 
 * 
 * This class adds a lot of syntax sugar to your recordset processing routines or other 
 * similar tasks when you don't want to write a loop construct. You will never see the 
 * calls of FuncUtility methods in the Frontier's core. It uses call_user_func(), 
 * which is slow. But I hope, it's performance will be improved someday though. 
 * 
 * @author Stanis Shramko <[email protected]> 
 */ 
class FuncUtility 
{ 
 
  /** 
   * Filters all elements of $set using the $callback 
   * 
   * @return array 
   * @throws InvalidArgumentException 
   */ 
  public static function filter($callback, $set) 
  { 
    if (!is_callable($callback)) 
    { 
      throw new InvalidArgumentException( 
        'The first argument is not callable'); 
    } 
    $values = array(); 
    if (is_callable($set)) 
    { 
      while ($value = call_user_func($set)) 
      { 
        if (call_user_func($callback, $value)) 
        { 
          $values[] = $value; 
        } 
      } 
    } 
    else 
    { 
      foreach (($set = self::prepareIterable($set)) as $value) 
      { 
        if (call_user_func($callback, $value)) 
          $values[] = $value; 
      } 
    } 
    return $values; 
  } 
 
  /** 
   * Applies the $callback to all elements of $set 
   * 
   * @return void 
   * @throws InvalidArgumentException 
   */ 
  public static function each($callback, $set) 
  { 
    if (!is_callable($callback)) 
    { 
      throw new InvalidArgumentException( 
        'The first argument is not callable'); 
    } 
    if (is_callable($set)) 
    { 
      while ($value = call_user_func($set)) 
      { 
        call_user_func($callback, $value); 
      } 
    } 
    else 
    { 
      foreach (($set = self::prepareIterable($set)) as $value) 
      { 
        call_user_func($callback, $value); 
      } 
    } 
  } 
 
  /** 
   * Applies the $callback to all elements of $set 
   * 
   * @return array 
   * @throws InvalidArgumentException 
   */ 
  public static function map($callback, $set) 
  { 
    if (!is_callable($callback)) 
    { 
      throw new InvalidArgumentException( 
        'The first argument is not callable'); 
    } 
    $values = array(); 
    if (is_callable($set)) 
    { 
      while ($value = call_user_func($set)) 
      { 
        $values[] = call_user_func($callback, $value); 
      } 
    } 
    else 
    { 
      foreach (($set = self::prepareIterable($set)) as $value) 
      { 
        $values[] = call_user_func($callback, $value); 
      } 
    } 
    return $values; 
  } 
 
  /** 
   * Reduces the $set using $result 
   * 
   * @return array 
   * @throws InvalidArgumentException 
   */ 
  public static function reduce($callback, $set) 
  { 
    if (!is_callable($callback)) 
    { 
      throw new InvalidArgumentException( 
        'The first argument is not callable'); 
    } 
    if (is_callable($set)) 
    { 
      $result = call_user_func($set); 
      while ($value = call_user_func($set)) 
      { 
        $result = call_user_func($callback, $result, $value); 
      } 
    } 
    else 
    { 
      $first = true; 
      foreach (($set = self::prepareIterable($set)) as $value) 
      { 
        if (!$first) 
        { 
          $result = call_user_func($callback, $result, 
            $value); 
        } 
        else 
        { 
          $result = $value; 
          $first = false; 
        } 
      } 
    } 
    return $result; 
  } 
 
  /** 
   * Prepares "something iterable" 
   * 
   * @param mixed $set 
   * @return mixed array or Iterator 
   */ 
  protected static function prepareIterable($set) 
  { 
    if (is_array($set) || $set instanceof Iterator) 
    { 
      return $set; 
    } 
    if (is_string($set)) 
    { 
      return str_split($set); 
    } 
    throw new InvalidArgumentException('The second argument is not iterable'); 
  } 
 
} 
 
 |