493 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			493 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
namespace nur;
 | 
						|
 | 
						|
use ArrayAccess;
 | 
						|
use nur\b\coll\IArray;
 | 
						|
use Traversable;
 | 
						|
 | 
						|
/**
 | 
						|
 * Class SL: gestion de tableau de valeurs scalaires
 | 
						|
 */
 | 
						|
class SL {
 | 
						|
  /** retourner un array non null à partir de $array */
 | 
						|
  static final function with($array): array {
 | 
						|
    if (is_array($array)) return $array;
 | 
						|
    elseif ($array === null || $array === false) return [];
 | 
						|
    elseif ($array instanceof IArray) return $array->array();
 | 
						|
    elseif ($array instanceof Traversable) return iterator_to_array($array);
 | 
						|
    else return [$array];
 | 
						|
  }
 | 
						|
 | 
						|
  /** retourner un array à partir de $array, ou null */
 | 
						|
  static final function withn($array): ?array {
 | 
						|
    if (is_array($array)) return $array;
 | 
						|
    elseif ($array === null || $array === false) return null;
 | 
						|
    elseif ($array instanceof IArray) return $array->array();
 | 
						|
    elseif ($array instanceof Traversable) return iterator_to_array($array);
 | 
						|
    else return [$array];
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * s'assurer que $array est un array non null. retourner true si $array n'a
 | 
						|
   * pas été modifié (s'il était déjà un array), false sinon.
 | 
						|
   */
 | 
						|
  static final function ensure_array(&$array): bool {
 | 
						|
    if (is_array($array)) return true;
 | 
						|
    elseif ($array === null || $array === false) $array = [];
 | 
						|
    elseif ($array instanceof IArray) $array = $array->array();
 | 
						|
    elseif ($array instanceof Traversable) $array =  iterator_to_array($array);
 | 
						|
    else $array = [$array];
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * s'assurer que $array est un array s'il est non null. retourner true si
 | 
						|
   * $array n'a pas été modifié (s'il était déjà un array ou s'il valait null).
 | 
						|
   */
 | 
						|
  static final function ensure_narray(&$array): bool {
 | 
						|
    if ($array === null || is_array($array)) return true;
 | 
						|
    elseif ($array === false) $array = [];
 | 
						|
    elseif ($array instanceof IArray) $array = $array->array();
 | 
						|
    elseif ($array instanceof Traversable) $array =  iterator_to_array($array);
 | 
						|
    else $array = [$array];
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * tester si $array contient la clé $key
 | 
						|
   *
 | 
						|
   * @param array|ArrayAccess $array
 | 
						|
   */
 | 
						|
  static final function has($array, $key): bool {
 | 
						|
    if (is_array($array)) {
 | 
						|
      return array_key_exists($key, $array);
 | 
						|
    } elseif ($array instanceof ArrayAccess) {
 | 
						|
      return $array->offsetExists($key);
 | 
						|
    }
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * retourner $array[$key] ou $default si la clé n'existe pas
 | 
						|
   *
 | 
						|
   * @param array|ArrayAccess $array
 | 
						|
   */
 | 
						|
  static final function get($array, $key, $default=null) {
 | 
						|
    if (is_array($array)) {
 | 
						|
      if (array_key_exists($key, $array)) return $array[$key];
 | 
						|
    } elseif ($array instanceof ArrayAccess) {
 | 
						|
      if ($array->offsetExists($key)) return $array->offsetGet($key);
 | 
						|
    }
 | 
						|
    return $default;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * si $array est un array ou une instance de ArrayAccess, créer ou modifier
 | 
						|
   * l'élément dont la clé est $key
 | 
						|
   *
 | 
						|
   * @param array|ArrayAccess $array
 | 
						|
   */
 | 
						|
  static final function set(&$array, $key, $value): void {
 | 
						|
    if (is_array($array) || $array === null) {
 | 
						|
      if ($key === null) $array[] = $value;
 | 
						|
      else $array[$key] = $value;
 | 
						|
    } elseif ($array instanceof ArrayAccess) {
 | 
						|
      $array->offsetSet($key, $value);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * si $array est un array ou une instance de ArrayAccess, supprimer l'élément
 | 
						|
   * dont la clé est $key
 | 
						|
   *
 | 
						|
   * @param array|ArrayAccess $array
 | 
						|
   */
 | 
						|
  static final function del(&$array, $key): void {
 | 
						|
    if (is_array($array)) {
 | 
						|
      unset($array[$key]);
 | 
						|
    } elseif ($array instanceof ArrayAccess) {
 | 
						|
      $array->offsetUnset($key);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  /** retourner le nombre d'éléments de $array */
 | 
						|
  static final function count(?array $array): int {
 | 
						|
    return $array !== null? count($array): 0;
 | 
						|
  }
 | 
						|
 | 
						|
  /** retourner la liste des clés de $array */
 | 
						|
  static final function keys(?array $array): array {
 | 
						|
    return $array !== null? array_keys($array): [];
 | 
						|
  }
 | 
						|
 | 
						|
  #############################################################################
 | 
						|
 | 
						|
  /**
 | 
						|
   * Fusionner tous les tableaux spécifiés. Les valeurs null sont ignorées.
 | 
						|
   * Retourner null si aucun tableau n'est fourni ou s'ils étaient tous null.
 | 
						|
   */
 | 
						|
  static final function merge(...$arrays): ?array {
 | 
						|
    $merges = [];
 | 
						|
    foreach ($arrays as $array) {
 | 
						|
      self::ensure_narray($array);
 | 
						|
      if ($array !== null) $merges[] = $array;
 | 
						|
    }
 | 
						|
    return $merges? array_merge(...$merges): null;
 | 
						|
  }
 | 
						|
 | 
						|
  #############################################################################
 | 
						|
 | 
						|
  /**
 | 
						|
   * vérifier que le chemin $keys fourni sous forme de tableau existe dans le
 | 
						|
   * tableau $array
 | 
						|
   *
 | 
						|
   * si $keys est vide ou null, retourner true
 | 
						|
   */
 | 
						|
  static final function phas_a($array, ?array $pkey): bool {
 | 
						|
    if (!$pkey) return true;
 | 
						|
    $first = true;
 | 
						|
    foreach($pkey as $key) {
 | 
						|
      if ($key === "" && $first) {
 | 
						|
        # une chaine vide en première position est ignorée
 | 
						|
        continue;
 | 
						|
      } elseif (is_array($array)) {
 | 
						|
        if (!array_key_exists($key, $array)) return false;
 | 
						|
        $array = $array[$key];
 | 
						|
      } elseif ($array instanceof ArrayAccess) {
 | 
						|
        if (!$array->offsetExists($key)) return false;
 | 
						|
        $array = $array->offsetGet($key);
 | 
						|
      } else {
 | 
						|
        return false;
 | 
						|
      }
 | 
						|
      $first = false;
 | 
						|
    }
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  /** vérifier que le chemin $keys existe dans le tableau $array */
 | 
						|
  static final function phas($array, $pkey): bool {
 | 
						|
    if ($pkey !== null && !is_array($pkey)) {
 | 
						|
      $pkey = explode(".", strval($pkey));
 | 
						|
    }
 | 
						|
    return self::phas_a($array, $pkey);
 | 
						|
  }
 | 
						|
 | 
						|
  static final function each_phas($array, ?array $pkeys): array {
 | 
						|
    $result = [];
 | 
						|
    if ($pkeys !== null) {
 | 
						|
      foreach ($pkeys as $pkey) {
 | 
						|
        $result[] = self::phas($array, $pkey);
 | 
						|
      }
 | 
						|
    }
 | 
						|
    return $result;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Parcourir les enfants de $array avec le chemin $keys fourni sous forme de
 | 
						|
   * tableau et retourner la valeur correspondante
 | 
						|
   *
 | 
						|
   * si $keys est vide ou null, retourner $default
 | 
						|
   */
 | 
						|
  static final function pget_a($array, ?array $pkey, $default=null) {
 | 
						|
    if (!$pkey) return $default;
 | 
						|
    $value = $array;
 | 
						|
    $first = true;
 | 
						|
    foreach($pkey as $key) {
 | 
						|
      if ($key === "" && $first) {
 | 
						|
        # une chaine vide en première position est ignorée
 | 
						|
        continue;
 | 
						|
      } elseif (is_array($value)) {
 | 
						|
        if (!array_key_exists($key, $value)) return $default;
 | 
						|
        $value = $value[$key];
 | 
						|
      } elseif ($value instanceof ArrayAccess) {
 | 
						|
        if (!$value->offsetExists($key)) return $default;
 | 
						|
        $value = $value->offsetGet($key);
 | 
						|
      } else {
 | 
						|
        return $default;
 | 
						|
      }
 | 
						|
      $first = false;
 | 
						|
    }
 | 
						|
    return $value;
 | 
						|
  }
 | 
						|
 | 
						|
  /** obtenir la valeur correspondant au chemin $keys dans $array */
 | 
						|
  static final function pget($array, $pkey, $default=null) {
 | 
						|
    if ($pkey !== null && !is_array($pkey)) {
 | 
						|
      $pkey = explode(".", strval($pkey));
 | 
						|
    }
 | 
						|
    return self::pget_a($array, $pkey, $default);
 | 
						|
  }
 | 
						|
 | 
						|
  static final function each_pget($array, ?array $pkeys): array {
 | 
						|
    $result = [];
 | 
						|
    if ($pkeys !== null) {
 | 
						|
      foreach ($pkeys as $key => $pkey) {
 | 
						|
        $result[$key] = self::pget($array, $pkey);
 | 
						|
      }
 | 
						|
    }
 | 
						|
    return $result;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * retourner un tableau construit à partir des chemins de clé de $pkeys
 | 
						|
   * ces chemins peuvent être exprimés de plusieurs façon:
 | 
						|
   * - [$key => $pkey] --> $dest[$key] = SL::pget($array, $pkey)
 | 
						|
   * - [$key => null]  --> $dest[$key] = null
 | 
						|
   * - [$key]          --> $dest[$key] = SL::pget($array, $key)
 | 
						|
   */
 | 
						|
  static final function pselect($array, ?array $pkeys): array {
 | 
						|
    $dest = [];
 | 
						|
    $index = 0;
 | 
						|
    foreach ($pkeys as $key => $pkey) {
 | 
						|
      if ($key === $index) {
 | 
						|
        $index++;
 | 
						|
        if (is_array($pkey)) $key = implode(".", $pkey);
 | 
						|
        else $key = strval($pkey);
 | 
						|
        $value = self::pget($array, $pkey);
 | 
						|
      } else {
 | 
						|
        if ($pkey === null) $value = null;
 | 
						|
        else $value = self::pget($array, $pkey);
 | 
						|
      }
 | 
						|
      $dest[$key] = $value;
 | 
						|
    }
 | 
						|
    return $dest;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Modifier la valeur au chemin $keys fourni sous forme de tableau
 | 
						|
   *
 | 
						|
   * utiliser la clé "" (chaine vide) en dernière position pour rajouter à la fin, e.g
 | 
						|
   * - _pset($array, [""], $value) est équivalent à $array[] = $value
 | 
						|
   * - _pset($array, ["a", "b", ""], $value) est équivalent à $array["a"]["b"][] = $value
 | 
						|
   * la clé "" n'a pas de propriété particulière quand elle n'est pas en dernière position
 | 
						|
   *
 | 
						|
   * si $keys est vide ou null, $array est remplacé par $value
 | 
						|
   */
 | 
						|
  static final function pset_a(&$array, ?array $pkey, $value): void {
 | 
						|
    if (!$pkey) {
 | 
						|
      $array = $value;
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    self::ensure_array($array);
 | 
						|
    $current =& $array;
 | 
						|
    $last = count($pkey) - 1;
 | 
						|
    $i = 0;
 | 
						|
    foreach ($pkey as $key) {
 | 
						|
      if ($i == $last) break;
 | 
						|
      if ($current instanceof ArrayAccess) {
 | 
						|
        if (!$current->offsetExists($key)) $current->offsetSet($key, []);
 | 
						|
        $current =& $current->offsetGet($key);
 | 
						|
        if ($current === null) {
 | 
						|
          $current = [];
 | 
						|
        } elseif (!is_array($current) && !($current instanceof ArrayAccess)) {
 | 
						|
          $current = [$current];
 | 
						|
        }
 | 
						|
      } else {
 | 
						|
        self::ensure_array($current[$key]);
 | 
						|
        $current =& $current[$key];
 | 
						|
      }
 | 
						|
      $i++;
 | 
						|
    }
 | 
						|
    if ($key === "") $current[] = $value;
 | 
						|
    else $current[$key] = $value;
 | 
						|
  }
 | 
						|
 | 
						|
  /** modifier la valeur au chemin de clé $keys dans le tableau $array */
 | 
						|
  static final function pset(&$array, $pkey, $value): void {
 | 
						|
    if ($pkey !== null && !is_array($pkey)) {
 | 
						|
      $pkey = explode(".", strval($pkey));
 | 
						|
    }
 | 
						|
    self::pset_a($array, $pkey, $value);
 | 
						|
  }
 | 
						|
 | 
						|
  static final function each_pset(&$array, ?array $values): void {
 | 
						|
    if ($values !== null) {
 | 
						|
      foreach ($values as $pkey => $value) {
 | 
						|
        self::pset($array, $pkey, $value);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * supprimer la valeur au chemin $keys fourni sous forme de tableau
 | 
						|
   *
 | 
						|
   * si $array vaut null ou false, sa valeur est inchangée.
 | 
						|
   * $keys est vide ou null, $array devient null
 | 
						|
   */
 | 
						|
  static final function pdel_a(&$array, ?array $pkey): void {
 | 
						|
    if ($array === false || $array === null) return;
 | 
						|
    if (!$pkey) {
 | 
						|
      $array = null;
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    self::ensure_array($array);
 | 
						|
    $current =& $array;
 | 
						|
    $last = count($pkey) - 1;
 | 
						|
    $i = 0;
 | 
						|
    foreach ($pkey as $key) {
 | 
						|
      if ($i == $last) break;
 | 
						|
      if ($current instanceof ArrayAccess) {
 | 
						|
        if (!$current->offsetExists($key)) break;
 | 
						|
      } elseif (is_array($current)) {
 | 
						|
        if (!array_key_exists($key, $current)) break;
 | 
						|
      } else {
 | 
						|
        break;
 | 
						|
      }
 | 
						|
      $current =& $current[$key];
 | 
						|
      $i++;
 | 
						|
    }
 | 
						|
    if ($i == $last) {
 | 
						|
      if ($current instanceof ArrayAccess) {
 | 
						|
        $current->offsetUnset($key);
 | 
						|
      } elseif (is_array($current)) {
 | 
						|
        unset($current[$key]);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  /** supprimer la valeur au chemin de clé $keys dans $array */
 | 
						|
  static final function pdel(&$array, $pkey): void {
 | 
						|
    if ($pkey !== null && !is_array($pkey)) {
 | 
						|
      $pkey = explode(".", strval($pkey));
 | 
						|
    }
 | 
						|
    self::pdel_a($array, $pkey);
 | 
						|
  }
 | 
						|
 | 
						|
  static final function each_pdel(&$array, ?array $pkeys): void {
 | 
						|
    if ($pkeys !== null) {
 | 
						|
      foreach ($pkeys as $pkey) {
 | 
						|
        self::pdel($array, $pkey);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  #############################################################################
 | 
						|
 | 
						|
  /**
 | 
						|
   * retourner le tableau $array en "renommant" les clés selon le tableau
 | 
						|
   * $mappings qui contient des associations de la forme [$from => $to]
 | 
						|
   */
 | 
						|
  static function rekey(?array $array, ?array $mappings): ?array {
 | 
						|
    if ($array === null || $mappings === null) return $array;
 | 
						|
    $mapped = [];
 | 
						|
    foreach ($array as $key => $value) {
 | 
						|
      if (array_key_exists($key, $mappings)) $key = $mappings[$key];
 | 
						|
      $mapped[$key] = $value;
 | 
						|
    }
 | 
						|
    return $mapped;
 | 
						|
  }
 | 
						|
 | 
						|
  #############################################################################
 | 
						|
 | 
						|
  /** tester si tous les éléments du tableau satisfont la condition */
 | 
						|
  static final function all_if(?array $array, callable $cond): bool {
 | 
						|
    if ($array !== null) {
 | 
						|
      foreach ($array as $value) {
 | 
						|
        if (!$cond($value)) return false;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  static final function all_z(?array $array): bool { return self::all_if($array, [SV::class, "z"]);}
 | 
						|
  static final function all_nz(?array $array): bool { return self::all_if($array, [SV::class, "nz"]);}
 | 
						|
  static final function all_n(?array $array): bool { return self::all_if($array, [SV::class, "n"]);}
 | 
						|
  static final function all_nn(?array $array): bool { return self::all_if($array, [SV::class, "nn"]);}
 | 
						|
  static final function all_t(?array $array): bool { return self::all_if($array, [SV::class, "t"]);}
 | 
						|
  static final function all_f(?array $array): bool { return self::all_if($array, [SV::class, "f"]);}
 | 
						|
  static final function all_pt(?array $array): bool { return self::all_if($array, [SV::class, "pt"]);}
 | 
						|
  static final function all_pf(?array $array): bool { return self::all_if($array, [SV::class, "pf"]);}
 | 
						|
  static final function all_equals(?array $array, $value): bool { return self::all_if($array, SV::equals($value)); }
 | 
						|
  static final function all_not_equals(?array $array, $value): bool { return self::all_if($array, SV::not_equals($value)); }
 | 
						|
  static final function all_same(?array $array, $value): bool { return self::all_if($array, SV::same($value)); }
 | 
						|
  static final function all_not_same(?array $array, $value): bool { return self::all_if($array, SV::not_same($value)); }
 | 
						|
 | 
						|
  #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | 
						|
 | 
						|
  /** tester si au moins un élément du tableau satisfait la condition */
 | 
						|
  static final function any_if(?array $array, callable $cond): bool {
 | 
						|
    if ($array !== null) {
 | 
						|
      foreach ($array as $value) {
 | 
						|
        if ($cond($value)) return true;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  static final function any_z(?array $array): bool { return self::any_if($array, [SV::class, "z"]);}
 | 
						|
  static final function any_nz(?array $array): bool { return self::any_if($array, [SV::class, "nz"]);}
 | 
						|
  static final function any_n(?array $array): bool { return self::any_if($array, [SV::class, "n"]);}
 | 
						|
  static final function any_nn(?array $array): bool { return self::any_if($array, [SV::class, "nn"]);}
 | 
						|
  static final function any_t(?array $array): bool { return self::any_if($array, [SV::class, "t"]);}
 | 
						|
  static final function any_f(?array $array): bool { return self::any_if($array, [SV::class, "f"]);}
 | 
						|
  static final function any_pt(?array $array): bool { return self::any_if($array, [SV::class, "pt"]);}
 | 
						|
  static final function any_pf(?array $array): bool { return self::any_if($array, [SV::class, "pf"]);}
 | 
						|
  static final function any_equals(?array $array, $value): bool { return self::any_if($array, SV::equals($value)); }
 | 
						|
  static final function any_not_equals(?array $array, $value): bool { return self::any_if($array, SV::not_equals($value)); }
 | 
						|
  static final function any_same(?array $array, $value): bool { return self::any_if($array, SV::same($value)); }
 | 
						|
  static final function any_not_same(?array $array, $value): bool { return self::any_if($array, SV::not_same($value)); }
 | 
						|
 | 
						|
  #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | 
						|
  
 | 
						|
  static final function filter_if(?array $array, callable $cond): ?array {
 | 
						|
    if ($array === null) return null;
 | 
						|
    $filtered = [];
 | 
						|
    $index = 0;
 | 
						|
    foreach ($array as $key => $value) {
 | 
						|
      if (!$cond($value)) {
 | 
						|
        if ($key === $index) {
 | 
						|
          $index++;
 | 
						|
          $filtered[] = $value;
 | 
						|
        } else {
 | 
						|
          $filtered[$key] = $value;
 | 
						|
        }
 | 
						|
      } elseif ($key === $index) {
 | 
						|
        $index++;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    return $filtered;
 | 
						|
  }
 | 
						|
 | 
						|
  static final function filter_z(?array $array): ?array { return self::filter_if($array, [SV::class, "z"]);}
 | 
						|
  static final function filter_nz(?array $array): ?array { return self::filter_if($array, [SV::class, "nz"]);}
 | 
						|
  static final function filter_n(?array $array): ?array { return self::filter_if($array, [SV::class, "n"]);}
 | 
						|
  static final function filter_nn(?array $array): ?array { return self::filter_if($array, [SV::class, "nn"]);}
 | 
						|
  static final function filter_t(?array $array): ?array { return self::filter_if($array, [SV::class, "t"]);}
 | 
						|
  static final function filter_f(?array $array): ?array { return self::filter_if($array, [SV::class, "f"]);}
 | 
						|
  static final function filter_pt(?array $array): ?array { return self::filter_if($array, [SV::class, "pt"]);}
 | 
						|
  static final function filter_pf(?array $array): ?array { return self::filter_if($array, [SV::class, "pf"]);}
 | 
						|
  static final function filter_equals(?array $array, $value): ?array { return self::filter_if($array, SV::equals($value)); }
 | 
						|
  static final function filter_not_equals(?array $array, $value): ?array { return self::filter_if($array, SV::not_equals($value)); }
 | 
						|
  static final function filter_same(?array $array, $value): ?array { return self::filter_if($array, SV::same($value)); }
 | 
						|
  static final function filter_not_same(?array $array, $value): ?array { return self::filter_if($array, SV::not_same($value)); }
 | 
						|
 | 
						|
  #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | 
						|
 | 
						|
  #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | 
						|
 | 
						|
  #############################################################################
 | 
						|
 | 
						|
  static final function sorted(?array $array, int $flags=SORT_REGULAR): ?array {
 | 
						|
    if ($array === null) return null;
 | 
						|
    sort($array, $flags);
 | 
						|
    return $array;
 | 
						|
  }
 | 
						|
 | 
						|
  /** retourner une fonction permettant de trier un tableau sur les clés spécifiées */
 | 
						|
  static final function compare(array $keys): callable {
 | 
						|
    return function ($a, $b) use ($keys) {
 | 
						|
      foreach ($keys as $key) {
 | 
						|
        if (str::del_prefix($key, "+")) $w = 1;
 | 
						|
        elseif (str::del_prefix($key, "-")) $w = -1;
 | 
						|
        elseif (str::del_suffix($key, "|asc")) $w = 1;
 | 
						|
        elseif (str::del_suffix($key, "|desc")) $w = -1;
 | 
						|
        else $w = 1;
 | 
						|
        if ($c = $w * SV::compare(A::get($a, $key), A::get($b, $key))) {
 | 
						|
          return $c;
 | 
						|
        }
 | 
						|
      }
 | 
						|
      return 0;
 | 
						|
    };
 | 
						|
  }
 | 
						|
}
 |