1568 lines
50 KiB
PHP
1568 lines
50 KiB
PHP
|
<?php
|
||
|
namespace nur;
|
||
|
|
||
|
use ArrayAccess;
|
||
|
use nur\b\coll\BaseArray;
|
||
|
use nur\b\coll\Flattener;
|
||
|
use nur\b\coll\IArray;
|
||
|
use Traversable;
|
||
|
|
||
|
/**
|
||
|
* Class A: méthodes utilitaires pour gérer les array
|
||
|
*/
|
||
|
class A {
|
||
|
static final function with($array): array { return SL::with($array); }
|
||
|
static final function withn($array): ?array { return SL::withn($array); }
|
||
|
|
||
|
/**
|
||
|
* tester si $array est un tableau de type array, BaseArray ou Traversable.
|
||
|
* tous ces objets peuvent être transformés en array par {@link with()}
|
||
|
*
|
||
|
* pour être sûr de pouvoir les parcourir en lecture seule, il faut les
|
||
|
* transformer en array avec {@link with()}
|
||
|
*/
|
||
|
static final function is_array($array): bool {
|
||
|
if ($array === null || $array === false) return false;
|
||
|
return is_iterable($array) || $array instanceof BaseArray;
|
||
|
}
|
||
|
|
||
|
static final function ensure_array(&$array): bool { return SL::ensure_array($array); }
|
||
|
static final function ensure_narray(&$array): bool { return SL::ensure_narray($array); }
|
||
|
|
||
|
/**
|
||
|
* retourner une référence permettant de modifier $array en tant qu'array de
|
||
|
* préférence ou en tant qu'instance de ArrayAccess au pire.
|
||
|
*/
|
||
|
static final function &ensure_access(&$array) {
|
||
|
if (is_array($array)) return $array;
|
||
|
if ($array instanceof IArray) return $array->array();
|
||
|
if ($array instanceof ArrayAccess) return $array;
|
||
|
if ($array instanceof Traversable) $array = iterator_to_array($array);
|
||
|
elseif ($array === null || $array === false) $array = [];
|
||
|
else $array = [$array];
|
||
|
return $array;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* s'assurer que $array est un tableau de $size éléments, en complétant avec
|
||
|
* des occurrences de $default si nécessaire
|
||
|
*
|
||
|
* @return bool true si le tableau a été modifié, false sinon
|
||
|
*/
|
||
|
static final function ensure_size(?array &$array, int $size, $default=null): bool {
|
||
|
$modified = false;
|
||
|
if ($array === null) {
|
||
|
$array = [];
|
||
|
$modified = true;
|
||
|
}
|
||
|
if ($size < 0) return $modified;
|
||
|
$count = count($array);
|
||
|
if ($count == $size) return $modified;
|
||
|
if ($count < $size) {
|
||
|
# agrandir le tableau
|
||
|
while ($count++ < $size) {
|
||
|
$array[] = $default;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
# rétrécir le tableau
|
||
|
$tmparray = [];
|
||
|
foreach ($array as $key => $value) {
|
||
|
if ($size-- == 0) break;
|
||
|
$tmparray[$key] = $value;
|
||
|
}
|
||
|
$array = $tmparray;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/** tester si $array contient la clé $key */
|
||
|
static final function has(?array $array, $key): bool {
|
||
|
return $array !== null && array_key_exists($key, $array);
|
||
|
}
|
||
|
|
||
|
/** retourner $array[$key] ou $default si la clé n'existe pas */
|
||
|
static final function get(?array $array, $key, $default=null) {
|
||
|
if ($array === null) return $default;
|
||
|
elseif (array_key_exists($key, $array)) return $array[$key];
|
||
|
else return $default;
|
||
|
}
|
||
|
|
||
|
/** s'assurer que $array est un array puis spécifier $array[$key] */
|
||
|
static final function set(&$array, $key, $value): void {
|
||
|
self::ensure_array($array);
|
||
|
if ($key === null) $array[] = $value;
|
||
|
else $array[$key] = $value;
|
||
|
}
|
||
|
|
||
|
/** s'assurer que $array est un array puis supprimer $array[$key] */
|
||
|
static final function del(&$array, $key): void {
|
||
|
if ($array === null || $array === false) return;
|
||
|
self::ensure_array($array);
|
||
|
unset($array[$key]);
|
||
|
}
|
||
|
|
||
|
/** retourner le nombre d'éléments de $array */
|
||
|
static final function count(?array $array): int {
|
||
|
return $array === null? 0: count($array);
|
||
|
}
|
||
|
|
||
|
/** retourner la liste des clés de $array */
|
||
|
static final function keys(?array $array): array {
|
||
|
return $array === null? []: array_keys($array);
|
||
|
}
|
||
|
|
||
|
static final function join(?array $array, string $sep=" "): string {
|
||
|
return $array === null? "": implode($sep, $array);
|
||
|
}
|
||
|
|
||
|
#############################################################################
|
||
|
|
||
|
/**
|
||
|
* tester si $array est un tableau séquentiel.
|
||
|
*
|
||
|
* NB: un tableau vide est séquentiel
|
||
|
*/
|
||
|
static final function is_seq($array): bool {
|
||
|
if (!is_array($array)) return false;
|
||
|
$count = count($array);
|
||
|
if ($count == 0) return true;
|
||
|
return array_keys($array) === range(0, $count - 1);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* tester si $array est un tableau associatif.
|
||
|
*
|
||
|
* NB: un tableau vide est associatif
|
||
|
*/
|
||
|
static final function is_assoc($array): bool {
|
||
|
if (!is_array($array)) return false;
|
||
|
$count = count($array);
|
||
|
if ($count == 0) return true;
|
||
|
return array_keys($array) !== range(0, $count - 1);
|
||
|
}
|
||
|
|
||
|
#############################################################################
|
||
|
|
||
|
/**
|
||
|
* s'assurer que $array est un array puis y fusionner tous les autres tableaux
|
||
|
* avec array_merge(). les clés numériques sont réordonnées, et les clés du
|
||
|
* tableau destination sont écrasées par les clés correspondantes des tableaux
|
||
|
* entrants. par exemple:
|
||
|
* ~~~
|
||
|
* $a = [10 => "a", 15 => "b", "x" => "y"];
|
||
|
* $b = [ 15 => "c", 20 => "d", "x" => "z"];
|
||
|
* A::merge($a, $b);
|
||
|
* # $a vaut maintenant [0 => "a", 1 => "b", "x" => "z", 2 => "c", 3 => "d"]
|
||
|
* ~~~
|
||
|
*
|
||
|
* parmi les tableaux de $arrays, ignorer les occurrences de null et false
|
||
|
*
|
||
|
* NB: dans $arrays, les valeurs scalaires sont traitées comme un singleton
|
||
|
* [$value]. elles sont donc simplement ajoutées à $array comme avec la
|
||
|
* commande "$array[] = $value;"
|
||
|
*/
|
||
|
static final function merge(&$array, ...$arrays): void {
|
||
|
self::ensure_array($array);
|
||
|
if ($arrays) {
|
||
|
$merges = [$array];
|
||
|
foreach ($arrays as $merge) {
|
||
|
if ($merge === null || $merge === false) continue;
|
||
|
$merges[] = self::with($merge);
|
||
|
}
|
||
|
$array = array_merge(...$merges);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* s'assurer que $array est un array puis y fusionner tous les autres tableaux
|
||
|
* comme avec {@link merge()} mais sans réordonner les clés numériques. Cela
|
||
|
* ressemble au comportement de l'opérateur union de PHP, mais la différence
|
||
|
* est que les clés du tableau destination sont écrasées par les clés
|
||
|
* correspondantes des tableaux entrants. par exemple:
|
||
|
* ~~~
|
||
|
* $a = [10 => "a", 15 => "b", "x" => "y"];
|
||
|
* $b = [ 15 => "c", 20 => "d", "x" => "z"];
|
||
|
* A::merge2($a, $b);
|
||
|
* # $a vaut maintenant [10 => "a", 15 => "c", "x" => "z", 20 => "d"]
|
||
|
* ~~~
|
||
|
*
|
||
|
* parmi les tableaux de $arrays, ignorer les occurrences de null et false
|
||
|
*
|
||
|
* NB: dans $arrays, les valeurs scalaires sont traitées comme un singleton
|
||
|
* [$value]. elles écrasent donc la valeur à la clé '0' si celle-ci existe
|
||
|
* déjà dans le tableau destination
|
||
|
*/
|
||
|
static final function merge2(&$array, ...$arrays): void {
|
||
|
self::ensure_array($array);
|
||
|
foreach ($arrays as $merge) {
|
||
|
if ($merge === null || $merge === false) continue;
|
||
|
foreach (self::with($merge) as $key => $value) {
|
||
|
$array[$key] = $value;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* s'assurer que $array est un array puis y fusionner tous les autres tableaux
|
||
|
* un peu comme avec {@link merge()} mais en ne réordonnant *que* les clés
|
||
|
* séquentielles. par exemple:
|
||
|
* ~~~
|
||
|
* $a = ["1st", "2nd", 10 => "a", 15 => "b", "x" => "y"];
|
||
|
* $b = [ "3rd", "4th", 15 => "c", 20 => "d", "x" => "z"];
|
||
|
* A::merge3($a, $b);
|
||
|
* # $a vaut maintenant ["1st", "2nd", 10 => "a", 15 => "c", "x" => "z", "3rd", "4th", 20 => "d"]
|
||
|
* ~~~
|
||
|
*
|
||
|
* parmi les tableaux de $arrays, ignorer les occurrences de null et false
|
||
|
*/
|
||
|
static final function merge3(&$array, ...$arrays): void {
|
||
|
self::ensure_array($array);
|
||
|
$desti = 0;
|
||
|
foreach ($array as $key => $value) {
|
||
|
if ($key === $desti) {
|
||
|
$desti++;
|
||
|
}
|
||
|
}
|
||
|
foreach ($arrays as $merge) {
|
||
|
$srci = 0;
|
||
|
if ($merge === null || $merge === false) continue;
|
||
|
foreach (self::with($merge) as $key => $value) {
|
||
|
if ($key === $srci) {
|
||
|
$srci++;
|
||
|
$array[$desti++] = $value;
|
||
|
} else {
|
||
|
$array[$key] = $value;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* comme {@link merge()} mais dans chacun des tableaux sources, ceux de
|
||
|
* $arrays, ignorer les valeurs null.
|
||
|
*/
|
||
|
static final function merge_nn(&$array, ...$arrays): void {
|
||
|
self::ensure_array($array);
|
||
|
if ($arrays) {
|
||
|
$merges = [$array];
|
||
|
foreach ($arrays as $tmp) {
|
||
|
if ($tmp === false || $tmp === null) continue;
|
||
|
$merge = [];
|
||
|
foreach (self::with($tmp) as $key => $value) {
|
||
|
if ($value === null) continue;
|
||
|
$merge[$key] = $value;
|
||
|
}
|
||
|
$merges[] = $merge;
|
||
|
}
|
||
|
$array = array_merge(...$merges);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* comme {@link merge2()} mais dans chacun des tableaux sources, ceux de
|
||
|
* $arrays, ignorer les valeurs null.
|
||
|
*/
|
||
|
static final function merge_nn2(&$array, ...$arrays): void {
|
||
|
self::ensure_array($array);
|
||
|
foreach ($arrays as $merge) {
|
||
|
if ($merge === false || $merge === null) continue;
|
||
|
foreach (self::with($merge) as $key => $value) {
|
||
|
if ($value === null) continue;
|
||
|
$array[$key] = $value;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* comme {@link merge()} mais dans chacun des tableaux sources, ceux de
|
||
|
* $arrays, ignorer les valeurs null et false.
|
||
|
*/
|
||
|
static final function merge_nz(&$array, ...$arrays): void {
|
||
|
self::ensure_array($array);
|
||
|
if ($arrays) {
|
||
|
$merges = [$array];
|
||
|
foreach ($arrays as $tmp) {
|
||
|
if ($tmp === false || $tmp === null) continue;
|
||
|
$merge = [];
|
||
|
foreach (self::with($tmp) as $key => $value) {
|
||
|
if ($value === null || $value === false) continue;
|
||
|
$merge[$key] = $value;
|
||
|
}
|
||
|
$merges[] = $merge;
|
||
|
}
|
||
|
$array = array_merge(...$merges);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* comme {@link merge2()} mais dans chacun des tableaux sources, ceux de
|
||
|
* $arrays, ignorer les valeurs null et false.
|
||
|
*/
|
||
|
static final function merge_nz2(&$array, ...$arrays): void {
|
||
|
self::ensure_array($array);
|
||
|
foreach ($arrays as $merge) {
|
||
|
if ($merge === false || $merge === null) continue;
|
||
|
foreach (self::with($merge) as $key => $value) {
|
||
|
if ($value === null || $value === false) continue;
|
||
|
$array[$key] = $value;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* comme {@link merge()} mais pour chacun des tableaux sources, ceux de
|
||
|
* $arrays, ne fusionner les valeurs dans la destination $array que si la clé
|
||
|
* n'y existe pas
|
||
|
*/
|
||
|
static final function update_nx(&$array, ...$arrays): void {
|
||
|
self::ensure_array($array);
|
||
|
if ($arrays) {
|
||
|
$updates = [$array];
|
||
|
foreach ($arrays as $tmp) {
|
||
|
if ($tmp === false || $tmp === null) continue;
|
||
|
$update = [];
|
||
|
foreach (self::with($tmp) as $key => $value) {
|
||
|
if (!array_key_exists($key, $array)) {
|
||
|
$update[$key] = $value;
|
||
|
}
|
||
|
}
|
||
|
$updates[] = $update;
|
||
|
}
|
||
|
$array = array_merge(...$updates);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* comme {@link merge2()} mais pour chacun des tableaux sources, ceux de
|
||
|
* $arrays, ne fusionner les valeurs dans la destination $array que si la clé
|
||
|
* n'y existe pas
|
||
|
*
|
||
|
* NB: il s'agit de la définition du l'opérateur union. l'implémentation fait
|
||
|
* d'ailleurs usage de cet opérateur
|
||
|
*/
|
||
|
static final function update_nx2(&$array, ...$arrays): void {
|
||
|
self::ensure_array($array);
|
||
|
foreach ($arrays as $update) {
|
||
|
if ($update === null || $update === false) continue;
|
||
|
$array += self::with($update);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* comme {@link merge()} mais pour chacun des tableaux sources, ceux de
|
||
|
* $arrays, ne fusionner les valeurs dans la destination $array que si la clé
|
||
|
* n'y existe pas ou, si elle y existe, que la valeur y est null
|
||
|
*/
|
||
|
static final function update_n(&$array, ...$arrays): void {
|
||
|
self::ensure_array($array);
|
||
|
if ($arrays) {
|
||
|
$updates = [$array];
|
||
|
foreach ($arrays as $tmp) {
|
||
|
if ($tmp === false || $tmp === null) continue;
|
||
|
$update = [];
|
||
|
foreach (self::with($tmp) as $key => $value) {
|
||
|
if (!array_key_exists($key, $array)) {
|
||
|
$update[$key] = $value;
|
||
|
} elseif ($array[$key] === null) {
|
||
|
$update[$key] = $value;
|
||
|
}
|
||
|
}
|
||
|
$updates[] = $update;
|
||
|
}
|
||
|
$array = array_merge(...$updates);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* comme {@link merge2()} mais pour chacun des tableaux sources, ceux de
|
||
|
* $arrays, ne fusionner les valeurs dans la destination $array que si la clé
|
||
|
* n'y existe pas ou, si elle y existe, que la valeur y est null
|
||
|
*/
|
||
|
static final function update_n2(&$array, ...$arrays): void {
|
||
|
self::ensure_array($array);
|
||
|
foreach ($arrays as $update) {
|
||
|
if ($update === false || $update === null) continue;
|
||
|
foreach (self::with($update) as $key => $value) {
|
||
|
if (!array_key_exists($key, $array)) {
|
||
|
$array[$key] = $value;
|
||
|
} elseif ($array[$key] === null) {
|
||
|
$array[$key] = $value;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* comme {@link merge()} mais pour chacun des tableaux sources, ceux de
|
||
|
* $arrays, ne fusionner les valeurs dans la destination $array que si la clé
|
||
|
* n'y existe pas ou, si elle y existe, que la valeur y est null ou false
|
||
|
*/
|
||
|
static final function update_z(&$array, ...$arrays): void {
|
||
|
self::ensure_array($array);
|
||
|
if ($arrays) {
|
||
|
$updates = [$array];
|
||
|
foreach ($arrays as $tmp) {
|
||
|
if ($tmp === false || $tmp === null) continue;
|
||
|
$update = [];
|
||
|
foreach (self::with($tmp) as $key => $value) {
|
||
|
if (!array_key_exists($key, $array)) {
|
||
|
$update[$key] = $value;
|
||
|
} else {
|
||
|
$rvalue = $array[$key];
|
||
|
if ($rvalue === null || $rvalue === false) {
|
||
|
$update[$key] = $value;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
$updates[] = $update;
|
||
|
}
|
||
|
$array = array_merge(...$updates);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* comme {@link merge2()} mais pour chacun des tableaux sources, ceux de
|
||
|
* $arrays, ne fusionner les valeurs dans la destination $array que si la clé
|
||
|
* n'y existe pas ou, si elle y existe, que la valeur y est null ou false
|
||
|
*/
|
||
|
static final function update_z2(&$array, ...$arrays): void {
|
||
|
self::ensure_array($array);
|
||
|
foreach ($arrays as $tomerge) {
|
||
|
if ($tomerge === false || $tomerge === null) continue;
|
||
|
foreach (self::with($tomerge) as $key => $value) {
|
||
|
if (!array_key_exists($key, $array)) {
|
||
|
$array[$key] = $value;
|
||
|
} else {
|
||
|
$rvalue = $array[$key];
|
||
|
if ($rvalue === null || $rvalue === false) {
|
||
|
$array[$key] = $value;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#############################################################################
|
||
|
## get
|
||
|
|
||
|
/** obtenir le premier élément du tableau */
|
||
|
static final function first(?array $array, $default=null) {
|
||
|
if (!$array) return $default;
|
||
|
else return $array[array_key_first($array)];
|
||
|
}
|
||
|
|
||
|
/** obtenir le second élément du tableau */
|
||
|
static final function second(?array $array, $default=null) {
|
||
|
if (!$array) return $default;
|
||
|
$first = true;
|
||
|
foreach ($array as $value) {
|
||
|
if ($first) $first = false;
|
||
|
else return $value;
|
||
|
}
|
||
|
return $default;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* obtenir le n-ième élément du tableau, en commençant à 0 (i.e 0=premier,
|
||
|
* 1=second, etc.)
|
||
|
*/
|
||
|
static final function nth(?array $array, int $index, $default=null) {
|
||
|
if (!$array) return $default;
|
||
|
$i = 0;
|
||
|
foreach ($array as $value) {
|
||
|
if ($index == $i) return $value;
|
||
|
$i++;
|
||
|
}
|
||
|
return $default;
|
||
|
}
|
||
|
|
||
|
/** obtenir la première clé du tableau */
|
||
|
static final function first_key(?array $array, $default_key=null) {
|
||
|
if (!$array) return $default_key;
|
||
|
else return array_key_first($array);
|
||
|
}
|
||
|
|
||
|
/** obtenir la seconde clé du tableau */
|
||
|
static final function second_key(?array $array, $default_key=null) {
|
||
|
if (!$array) return $default_key;
|
||
|
$first = true;
|
||
|
foreach (array_keys($array) as $key) {
|
||
|
if ($first) $first = false;
|
||
|
else return $key;
|
||
|
}
|
||
|
return $default_key;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* obtenir la clé du n-ième élément du tableau, en commençant à 0 (i.e
|
||
|
* 0=premier, 1=second, etc.)
|
||
|
*/
|
||
|
static final function nth_key(?array $array, int $index, $default_key=null) {
|
||
|
if (!$array) return $default_key;
|
||
|
$i = 0;
|
||
|
foreach (array_keys($array) as $key) {
|
||
|
if ($index == $i) return $key;
|
||
|
$i++;
|
||
|
}
|
||
|
return $default_key;
|
||
|
}
|
||
|
|
||
|
/** obtenir le dernier élément du tableau */
|
||
|
static final function last(?array $array, $default=null) {
|
||
|
if (!$array) return $default;
|
||
|
else return $array[array_key_last($array)];
|
||
|
}
|
||
|
|
||
|
/** obtenir la dernière clé du tableau */
|
||
|
static final function last_key(?array $array, $default_key=null) {
|
||
|
if (!$array) return $default_key;
|
||
|
else return array_key_last($array);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* si $array est un tableau séquentiel avec un seul élément, retourner cet élément.
|
||
|
* si c'est un tableau vide ou null retourner $default
|
||
|
* sinon retourner le tableau inchangé
|
||
|
*/
|
||
|
static final function one_or_array(?array $array, $default=null) {
|
||
|
if (!$array) {
|
||
|
return $default;
|
||
|
} elseif (count($array) == 1 && array_key_exists(0, $array)) {
|
||
|
return $array[0];
|
||
|
} else {
|
||
|
return $array;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* retourner un tableau avec pour chaque tableau $array de $arrays, la valeur
|
||
|
* de get($array, $key, $default)
|
||
|
*/
|
||
|
static final function each_get(?array $arrays, $key, $default=null): array {
|
||
|
$values = [];
|
||
|
foreach ($arrays as $index => $array) {
|
||
|
$values[$index] = self::get($array, $key, $default);
|
||
|
}
|
||
|
return $values;
|
||
|
}
|
||
|
|
||
|
#############################################################################
|
||
|
## set
|
||
|
|
||
|
/**
|
||
|
* Mettre à jour la clé $key avec $value si $value !== null
|
||
|
*
|
||
|
* si aucune modification ne doit se faire, $array n'est pas modifié
|
||
|
*
|
||
|
* Retourner la valeur effective de la clé (qu'elle aie été mise à jour ou
|
||
|
* non)
|
||
|
*/
|
||
|
static final function set_nn(&$array, $key, $value) {
|
||
|
if ($value !== null) {
|
||
|
self::ensure_array($array);
|
||
|
self::set($array, $key, $value);
|
||
|
return $value;
|
||
|
} else {
|
||
|
return self::get($array, $key);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Mettre à jour la clé $key avec $array[$key_indirect] si cette valeur ne
|
||
|
* vaut pas null
|
||
|
*
|
||
|
* Retourner la valeur effective de la clé (qu'elle aie été mise à jour ou
|
||
|
* non)
|
||
|
*/
|
||
|
static final function set_nn_indirect(&$array, $key, $key_indirect) {
|
||
|
self::ensure_narray($array);
|
||
|
$value = self::get($array, $key_indirect);
|
||
|
return self::set_nn($array, $key, $value);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Mettre à jour la clé $key avec $value si $value ne vaut ni null ni false
|
||
|
*
|
||
|
* si aucune modification ne doit se faire, $array n'est pas modifié
|
||
|
*
|
||
|
* Retourner la valeur effective de la clé (qu'elle aie été mise à jour ou
|
||
|
* non)
|
||
|
*/
|
||
|
static final function set_nz(&$array, $key, $value) {
|
||
|
if ($value !== false && $value !== null) {
|
||
|
self::set($array, $key, $value);
|
||
|
return $value;
|
||
|
} else {
|
||
|
return self::get($array, $key);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Mettre à jour la clé $key avec $array[$key_indirect] si cette valeur ne
|
||
|
* vaut ni null ni false
|
||
|
*
|
||
|
* Retourner la valeur effective de la clé (qu'elle aie été mise à jour ou
|
||
|
* non)
|
||
|
*/
|
||
|
static final function set_nz_indirect(&$array, $key, $key_indirect) {
|
||
|
self::ensure_narray($array);
|
||
|
$value = self::get($array, $key_indirect);
|
||
|
return self::set_nz($array, $key, $value);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Ajouter la valeur avec la clé spécifiée si elle n'existe pas déjà
|
||
|
*
|
||
|
* si aucune modification ne doit se faire, $array n'est pas modifié
|
||
|
*
|
||
|
* Retourner la valeur effective de la clé (qu'elle aie été mise à jour ou
|
||
|
* non)
|
||
|
*/
|
||
|
static final function replace_nx(&$array, $key, $value) {
|
||
|
if (!is_array($array) || !array_key_exists($key, $array)) {
|
||
|
self::set($array, $key, $value);
|
||
|
return $value;
|
||
|
} else {
|
||
|
return self::get($array, $key);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Mettre à jour la clé $key avec $value si la clé $key n'existe pas ou si sa
|
||
|
* valeur actuelle est null.
|
||
|
*
|
||
|
* Retourner la valeur effective de la clé (qu'elle aie été mise à jour ou
|
||
|
* non)
|
||
|
*/
|
||
|
static final function replace_n(&$array, $key, $value) {
|
||
|
self::ensure_narray($array);
|
||
|
$rvalue = self::get($array, $key);
|
||
|
if ($rvalue === null) {
|
||
|
self::set($array, $key, $value);
|
||
|
$rvalue = $value;
|
||
|
}
|
||
|
return $rvalue;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Mettre à jour la clé $key avec $array[$key_indirect] si cette clé n'existe
|
||
|
* pas ou si sa valeur actuelle est null.
|
||
|
*
|
||
|
* Retourner la valeur effective de la clé (qu'elle aie été mise à jour ou
|
||
|
* non)
|
||
|
*/
|
||
|
static final function replace_n_indirect(&$array, $key, $key_indirect) {
|
||
|
self::ensure_narray($array);
|
||
|
$rvalue = self::get($array, $key);
|
||
|
if ($rvalue === null) {
|
||
|
$value = self::get($array, $key_indirect);
|
||
|
self::set($array, $key, $value);
|
||
|
$rvalue = $value;
|
||
|
}
|
||
|
return $rvalue;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Mettre à jour la clé $key avec $value si la clé $key n'existe pas ou si sa
|
||
|
* valeur actuelle est null ou false.
|
||
|
*
|
||
|
* Retourner la valeur effective de la clé (qu'elle aie été mise à jour ou
|
||
|
* non)
|
||
|
*/
|
||
|
static final function replace_z(&$array, $key, $value) {
|
||
|
self::ensure_narray($array);
|
||
|
$rvalue = self::get($array, $key);
|
||
|
if ($rvalue === false || $rvalue === null) {
|
||
|
self::set($array, $key, $value);
|
||
|
$rvalue = $value;
|
||
|
}
|
||
|
return $rvalue;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Mettre à jour la clé $key avec $array[$key_indirect] si cette clé n'existe
|
||
|
* pas ou si sa valeur actuelle est null ou false.
|
||
|
*
|
||
|
* Retourner la valeur effective de la clé (qu'elle aie été mise à jour ou
|
||
|
* non)
|
||
|
*/
|
||
|
static final function replace_z_indirect(&$array, $key, $key_indirect) {
|
||
|
self::ensure_narray($array);
|
||
|
$rvalue = self::get($array, $key);
|
||
|
if ($rvalue === false || $rvalue === null) {
|
||
|
$value = self::get($array, $key_indirect);
|
||
|
self::set($array, $key, $value);
|
||
|
$rvalue = $value;
|
||
|
}
|
||
|
return $rvalue;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Ajouter $value à la fin de $array
|
||
|
*
|
||
|
* Retourner la valeur ajoutée
|
||
|
*/
|
||
|
static final function append(&$array, $value) {
|
||
|
self::ensure_array($array);
|
||
|
$array[] = $value;
|
||
|
return $value;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Si $value n'est pas null, ajouter $value à la fin de $array
|
||
|
*
|
||
|
* si aucune modification ne doit se faire, $array n'est pas modifié
|
||
|
*
|
||
|
* Retourner la valeur ajoutée, ou null si la valeur n'a pas été ajoutée
|
||
|
*/
|
||
|
static final function append_nn(&$array, $value) {
|
||
|
if ($value !== null) {
|
||
|
self::ensure_array($array);
|
||
|
$array[] = $value;
|
||
|
return $value;
|
||
|
} else {
|
||
|
return null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Si $value ne vaut ni null ni false, ajouter $value à la fin de $array
|
||
|
*
|
||
|
* si aucune modification ne doit se faire, $array n'est pas modifié
|
||
|
*
|
||
|
* Retourner la valeur ajoutée, ou null si la valeur n'a pas été ajoutée
|
||
|
*/
|
||
|
static final function append_nz(&$array, $value) {
|
||
|
if (base::nz($value)) {
|
||
|
self::ensure_array($array);
|
||
|
$array[] = $value;
|
||
|
return $value;
|
||
|
} else {
|
||
|
return null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Insérer $value au début de $array
|
||
|
*
|
||
|
* Retourner la valeur insérée
|
||
|
*/
|
||
|
static final function prepend(&$array, $value) {
|
||
|
self::ensure_array($array);
|
||
|
array_unshift($array, $value);
|
||
|
return $value;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Si $value n'est pas null, insérer $value au début de $array
|
||
|
*
|
||
|
* si aucune modification ne doit se faire, $array n'est pas modifié
|
||
|
*
|
||
|
* Retourner la valeur ajoutée, ou null si la valeur n'a pas été ajoutée
|
||
|
*/
|
||
|
static final function prepend_nn(&$array, $value) {
|
||
|
if ($value !== null) {
|
||
|
self::ensure_array($array);
|
||
|
array_unshift($array, $value);
|
||
|
return $value;
|
||
|
} else {
|
||
|
return null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Si $value ne vaut ni null ni false, insérer $value au début de $array
|
||
|
*
|
||
|
* si aucune modification ne doit se faire, $array n'est pas modifié
|
||
|
*
|
||
|
* Retourner la valeur ajoutée, ou null si la valeur n'a pas été ajoutée
|
||
|
*/
|
||
|
static final function prepend_nz(&$array, $value) {
|
||
|
if (base::nz($value)) {
|
||
|
self::ensure_array($array);
|
||
|
array_unshift($array, $value);
|
||
|
return $value;
|
||
|
} else {
|
||
|
return null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* dans le tableau séquentiel $array, insérer $value à la position $index et
|
||
|
* décaler toutes les autres clés
|
||
|
*
|
||
|
* Retourner la valeur insérée
|
||
|
*/
|
||
|
static final function insert(&$array, $index, $value) {
|
||
|
self::ensure_array($array);
|
||
|
$count = count($array);
|
||
|
if ($count == 0 || $index >= $count) {
|
||
|
$array[] = $value;
|
||
|
} else {
|
||
|
while ($index < 0) $index += $count;
|
||
|
if ($index == 0) $prefix = [];
|
||
|
else $prefix = array_slice($array, 0, $index);
|
||
|
$suffix = array_slice($array, $index);
|
||
|
$array = array_merge($prefix, [$value], $suffix);
|
||
|
}
|
||
|
return $value;
|
||
|
}
|
||
|
|
||
|
/** Ajouter une valeur dans le tableau, pour utilisation avec pop() */
|
||
|
static final function push(&$array, $value): void {
|
||
|
self::ensure_array($array);
|
||
|
$array[] = $value;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* enlever la dernière valeur ajoutée dans le tableau avec push() et la
|
||
|
* retourner
|
||
|
*/
|
||
|
static final function pop(&$array, $default=null) {
|
||
|
self::ensure_array($array);
|
||
|
$count = count($array);
|
||
|
if ($count > 0) {
|
||
|
$value = array_pop($array);
|
||
|
} else {
|
||
|
$value = $default;
|
||
|
}
|
||
|
return $value;
|
||
|
}
|
||
|
|
||
|
#############################################################################
|
||
|
## del
|
||
|
|
||
|
static final function del_value(&$array, $value, int $max_count=1, bool $strict=false): int {
|
||
|
if ($array === null || $array === false) return 0;
|
||
|
self::ensure_array($array);
|
||
|
$count = 0;
|
||
|
$rekey = null;
|
||
|
while ($max_count <= 0 || $count < $max_count) {
|
||
|
$key = array_search($value, $array, $strict);
|
||
|
if ($key === false) break;
|
||
|
# s'il faut supprimer des clés, vérifier d'abord si c'est un tableau
|
||
|
# séquentiel, afin de refaire la numérotation le cas échéant
|
||
|
if ($rekey === null) $rekey = self::is_seq($array);
|
||
|
unset($array[$key]);
|
||
|
$count++;
|
||
|
}
|
||
|
if ($rekey) $array = array_values($array);
|
||
|
return $count;
|
||
|
}
|
||
|
|
||
|
static final function del_first_key(&$array, int $max_count=1): int {
|
||
|
if ($array === null || $array === false) return 0;
|
||
|
self::ensure_array($array);
|
||
|
$count = 0;
|
||
|
$rekey = null;
|
||
|
while ($max_count <= 0 || $count < $max_count) {
|
||
|
$key = array_key_first($array);
|
||
|
if ($key === null) break;
|
||
|
# s'il faut supprimer des clés, vérifier d'abord si c'est un tableau
|
||
|
# séquentiel, afin de refaire la numérotation le cas échéant
|
||
|
if ($rekey === null) $rekey = self::is_seq($array);
|
||
|
unset($array[$key]);
|
||
|
$count++;
|
||
|
}
|
||
|
if ($rekey) $array = array_values($array);
|
||
|
return $count;
|
||
|
}
|
||
|
|
||
|
static final function del_last_key(&$array, int $max_count=1): int {
|
||
|
if ($array === null || $array === false) return 0;
|
||
|
self::ensure_array($array);
|
||
|
$count = 0;
|
||
|
while ($max_count <= 0 || $count < $max_count) {
|
||
|
$key = array_key_last($array);
|
||
|
if ($key === null) break;
|
||
|
unset($array[$key]);
|
||
|
$count++;
|
||
|
}
|
||
|
return $count;
|
||
|
}
|
||
|
|
||
|
static final function del_keys(&$array, ...$keys): void {
|
||
|
if ($array === null || $array === false) return;
|
||
|
self::ensure_array($array);
|
||
|
foreach ($keys as $key) {
|
||
|
unset($array[$key]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#############################################################################
|
||
|
## getdel
|
||
|
|
||
|
/**
|
||
|
* obtenir la valeur correspondant à la clé $key, ou $default si elle n'est
|
||
|
* pas trouvée. puis supprimer la clé du tableau
|
||
|
*/
|
||
|
static final function getdel(&$array, $key, $default=null) {
|
||
|
self::ensure_array($array);
|
||
|
$value = self::get($array, $key, $default);
|
||
|
unset($array[$key]);
|
||
|
return $value;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* obtenir les valeurs correspondantes aux clés $keys sous forme de tableau
|
||
|
* séquentiel. supprimer les clés du tableau
|
||
|
*/
|
||
|
static final function getdels(&$array, ?array $keys): array {
|
||
|
self::ensure_array($array);
|
||
|
$values = [];
|
||
|
if ($keys !== null) {
|
||
|
foreach ($keys as $key) {
|
||
|
$values[] = self::get($array, $key);
|
||
|
unset($array[$key]);
|
||
|
}
|
||
|
}
|
||
|
return $values;
|
||
|
}
|
||
|
|
||
|
#############################################################################
|
||
|
## Chemins de clé
|
||
|
|
||
|
/**
|
||
|
* 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(?array $array, ?array $keys): bool {
|
||
|
$first = true;
|
||
|
foreach($keys 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 qui est de la forme key[.keys...] existe
|
||
|
* dans le tableau $array
|
||
|
*
|
||
|
* si $keys === null, retourner true
|
||
|
*/
|
||
|
static final function phas_s(?array $array, ?string $keys): bool {
|
||
|
if ($keys === null) return true;
|
||
|
$keys = explode(".", $keys);
|
||
|
return self::_phas($array, $keys);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Vérifier que le chemin $keys fourni sous forme de tableau existe dans le
|
||
|
* tableau $array
|
||
|
*
|
||
|
* si $keys est nul ou vide, retourner true
|
||
|
*/
|
||
|
static final function phas_a(?array $array, ?array $keys): bool {
|
||
|
if (!$keys) return true;
|
||
|
$keys = implode(".", $keys);
|
||
|
$keys = explode(".", $keys);
|
||
|
return self::_phas($array, $keys);
|
||
|
}
|
||
|
|
||
|
/** vérifier que le chemin $keys existe dans le tableau $array */
|
||
|
static final function phas($array, $keys): bool {
|
||
|
if ($keys === null) return true;
|
||
|
elseif (is_array($keys)) return self::phas_a($array, $keys);
|
||
|
else return self::phas_s($array, strval($keys));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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(?array $array, ?array $keys, $default=null) {
|
||
|
if (!$keys) return $default;
|
||
|
$value = $array;
|
||
|
$first = true;
|
||
|
foreach($keys 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;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Parcourir les enfants de $array avec le chemin $keys qui est de la forme
|
||
|
* key[.keys...] et retourner la valeur correspondante
|
||
|
*
|
||
|
* si $keys === null, retourner $default
|
||
|
*/
|
||
|
static final function pget_s(?array $array, ?string $keys, $default=null) {
|
||
|
if ($keys === null) return $default;
|
||
|
$keys = explode(".", $keys);
|
||
|
return self::_pget($array, $keys, $default);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Parcourir les enfants de $array avec le chemin $keys fourni sous forme de
|
||
|
* tableau et retourner la valeur correspondante
|
||
|
*
|
||
|
* si $keys est nul ou vide, retourner $default
|
||
|
*/
|
||
|
static final function pget_a(?array $array, ?array $keys, $default=null) {
|
||
|
if (!$keys) return $default;
|
||
|
$keys = implode(".", $keys);
|
||
|
$keys = explode(".", $keys);
|
||
|
return self::_pget($array, $keys, $default);
|
||
|
}
|
||
|
|
||
|
/** obtenir la valeur correspondant au chemin $keys dans $array */
|
||
|
static final function pget($array, $keys, $default=null) {
|
||
|
if ($keys === null) return $default;
|
||
|
elseif (is_array($keys)) return self::pget_a($array, $keys, $default);
|
||
|
else return self::pget_s($array, strval($keys), $default);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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(&$array, ?array $keys, $value): void {
|
||
|
if (!$keys) {
|
||
|
$array = $value;
|
||
|
return;
|
||
|
}
|
||
|
self::ensure_array($array);
|
||
|
$current =& $array;
|
||
|
$last = count($keys) - 1;
|
||
|
$i = 0;
|
||
|
foreach ($keys 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 $keys qui est de la forme key[.keys...]
|
||
|
*
|
||
|
* 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 null, $array est remplacé par $value
|
||
|
*/
|
||
|
static final function pset_s(&$array, ?string $keys, $value): void {
|
||
|
if ($keys === null) {
|
||
|
$array = $value;
|
||
|
} else {
|
||
|
$keys = explode(".", $keys);
|
||
|
self::_pset($array, $keys, $value);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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 null, $array est remplacé par $value
|
||
|
*/
|
||
|
static final function pset_a(&$array, ?array $keys, $value): void {
|
||
|
if (!$keys) {
|
||
|
$array = $value;
|
||
|
} else {
|
||
|
$keys = implode(".", $keys);
|
||
|
$keys = explode(".", $keys);
|
||
|
self::_pset($array, $keys, $value);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/** modifier la valeur au chemin de clé $keys dans le tableau $array */
|
||
|
static final function pset(&$array, $keys, $value): void {
|
||
|
if ($keys === null) $array = $value;
|
||
|
elseif (is_array($keys)) self::pset_a($array, $keys, $value);
|
||
|
else self::pset_s($array, strval($keys), $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(&$array, ?array $keys): void {
|
||
|
if ($array === false || $array === null) return;
|
||
|
if (!$keys) {
|
||
|
$array = null;
|
||
|
return;
|
||
|
}
|
||
|
self::ensure_array($array);
|
||
|
$current =& $array;
|
||
|
$last = count($keys) - 1;
|
||
|
$i = 0;
|
||
|
foreach ($keys as $key) {
|
||
|
if ($i == $last) break;
|
||
|
if ($current instanceof ArrayAccess) {
|
||
|
if (!$current->offsetExists($key)) break;
|
||
|
} elseif (is_array($current)) {
|
||
|
if (!self::has($current, $key)) 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 $keys qui est de la forme key[.keys...]
|
||
|
*
|
||
|
* si $array vaut null ou false, sa valeur est inchangée.
|
||
|
* si $keys est null, $array devient null
|
||
|
*/
|
||
|
static final function pdel_s(&$array, ?string $keys): void {
|
||
|
if ($array === false || $array === null) return;
|
||
|
if ($keys === null) {
|
||
|
$array = null;
|
||
|
} else {
|
||
|
$keys = explode(".", $keys);
|
||
|
self::_pdel($array, $keys);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* supprimer la valeur au chemin $keys fourni sous forme de tableau
|
||
|
*
|
||
|
* si $array vaut null ou false, sa valeur est inchangée.
|
||
|
* si $keys est vide ou null, $array devient null
|
||
|
*/
|
||
|
static final function pdel_a(&$array, ?array $keys): void {
|
||
|
if ($array === false || $array === null) return;
|
||
|
if (!$keys) {
|
||
|
$array = null;
|
||
|
} else {
|
||
|
$keys = implode(".", $keys);
|
||
|
$keys = explode(".", $keys);
|
||
|
self::_pdel($array, $keys);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/** supprimer la valeur au chemin de clé $keys dans $array */
|
||
|
static final function pdel(&$array, $keys): void {
|
||
|
if ($array === false || $array === null) return;
|
||
|
if ($keys === null) $array = null;
|
||
|
elseif (is_array($keys)) self::pdel_a($array, $keys);
|
||
|
else self::pdel_s($array, strval($keys));
|
||
|
}
|
||
|
|
||
|
#############################################################################
|
||
|
## map
|
||
|
|
||
|
static final function map(?array $array, callable $func): ?array {
|
||
|
if ($array === null) return null;
|
||
|
return array_map($func, $array);
|
||
|
}
|
||
|
|
||
|
#############################################################################
|
||
|
## filter
|
||
|
|
||
|
static final function filter_n(?array $array): ?array { return SL::filter_n($array); }
|
||
|
static final function filter_z(?array $array): ?array { return SL::filter_z($array); }
|
||
|
static final function filter_f(?array $array): ?array { return SL::filter_f($array); }
|
||
|
static final function filter_f2(?array $array): ?array { return SL::filter_pf($array); }
|
||
|
|
||
|
#############################################################################
|
||
|
## Tests sur les valeurs
|
||
|
|
||
|
static final function any_v(?array $array, $value, bool $strict=true): bool {
|
||
|
if ($strict) return SL::any_same($array, $value);
|
||
|
else return SL::any_equals($array, $value);
|
||
|
}
|
||
|
static final function all_v(?array $array, $value, bool $strict=true): bool {
|
||
|
if ($strict) return SL::all_same($array, $value);
|
||
|
else return SL::all_equals($array, $value);
|
||
|
}
|
||
|
static final function any_nv(?array $array, $value, bool $strict=true): bool {
|
||
|
if ($strict) return SL::any_not_same($array, $value);
|
||
|
else return SL::any_not_equals($array, $value);
|
||
|
}
|
||
|
static final function all_nv(?array $array, $value, bool $strict=true): bool {
|
||
|
if ($strict) return SL::all_not_same($array, $value);
|
||
|
else return SL::all_not_equals($array, $value);
|
||
|
}
|
||
|
static final function any_z(?array $array): bool { return SL::any_z($array); }
|
||
|
static final function all_z(?array $array): bool { return SL::all_z($array); }
|
||
|
static final function any_nz(?array $array): bool { return SL::any_nz($array); }
|
||
|
static final function all_nz(?array $array): bool { return SL::all_nz($array); }
|
||
|
static final function any_n(?array $array): bool { return SL::any_n($array); }
|
||
|
static final function all_n(?array $array): bool { return SL::all_n($array); }
|
||
|
static final function any_nn(?array $array): bool { return SL::any_nn($array); }
|
||
|
static final function all_nn(?array $array): bool { return SL::all_nn($array); }
|
||
|
static final function any_f(?array $array): bool { return SL::any_f($array); }
|
||
|
static final function all_f(?array $array): bool { return SL::all_f($array); }
|
||
|
static final function any_t(?array $array): bool { return SL::any_t($array); }
|
||
|
static final function all_t(?array $array): bool { return SL::all_t($array); }
|
||
|
static final function any_f2(?array $array): bool { return SL::any_pf($array); }
|
||
|
static final function all_f2(?array $array): bool { return SL::all_pf($array); }
|
||
|
static final function any_t2(?array $array): bool { return SL::any_pt($array); }
|
||
|
static final function all_t2(?array $array): bool { return SL::all_pt($array); }
|
||
|
|
||
|
#############################################################################
|
||
|
## Fonctions avancées
|
||
|
|
||
|
/** dans le tableau $array, "renommer" les clés selon le tableau $key_map */
|
||
|
static function map_keys(?array &$array, ?array $key_map): void {
|
||
|
if ($array === null || $key_map === null) return;
|
||
|
foreach ($key_map as $from => $to) {
|
||
|
if (array_key_exists($from, $array)) {
|
||
|
$array[$to] = $array[$from];
|
||
|
unset($array[$from]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static $flattener;
|
||
|
|
||
|
/**
|
||
|
* Applatir le tableau $array
|
||
|
*
|
||
|
* Pour chaque élément avec une clé séquentielle:
|
||
|
* - si c'est un tableau, l'applatir puis rajouter ses éléments tels quels au
|
||
|
* résultat
|
||
|
* - sinon ajouter l'élément tel quel
|
||
|
*
|
||
|
* Pour chaque élément avec une clé associative:
|
||
|
* - si la valeur n'existe pas déjà, elle est rajoutée telle quelle
|
||
|
* - si la valeur source est null ou false, la valeur destination n'est pas
|
||
|
* modifiée
|
||
|
* - sinon, les deux valeurs sont transformées en tableau le cas échéant.
|
||
|
* si $flattenValue == true, alors le tableau source est applati au préalable.
|
||
|
* puis cette nouvelle valeur est fusionnée avec array_merge() dans la valeur
|
||
|
* précédente.
|
||
|
*/
|
||
|
static final function flatten(?array &$array, bool $flattenValue=true): void {
|
||
|
if (self::$flattener === null) self::$flattener = new Flattener();
|
||
|
self::$flattener->flatten($array, $flattenValue);
|
||
|
}
|
||
|
|
||
|
/** retourner le tableau $array applati */
|
||
|
static final function flattened(?array $array, bool $flattenValue=true): array {
|
||
|
self::flatten($array, $flattenValue);
|
||
|
return $array;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Extraire d'un tableau les clés séquentielles
|
||
|
*
|
||
|
* Retourner $seq où $seq est un tableau avec uniquement les valeurs des clés
|
||
|
* séquentielles. S'il n'existe aucune clé séquentielle retourner $default.
|
||
|
*
|
||
|
* Par exemple: extract_seq(["a", "b" => "c"]) retourne ["a"]
|
||
|
*/
|
||
|
static final function extract_seq(?array $array, ?array $default=null): ?array {
|
||
|
$seq = null;
|
||
|
if ($array !== null) {
|
||
|
$index = 0;
|
||
|
foreach ($array as $key => $value) {
|
||
|
if ($key === $index) {
|
||
|
$seq[] = $value;
|
||
|
$index++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if ($seq === null) $seq = $default;
|
||
|
return $seq;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Extraire d'un tableau les clés associatives
|
||
|
*
|
||
|
* Retourner une liste $assoc où $assoc est un tableau avec uniquement les
|
||
|
* valeurs des clés associatives. S'il n'existe aucune clé associative,
|
||
|
* retourner $default.
|
||
|
*
|
||
|
* Par exemple: split_assoc(["a", "b" => "c"]) retourne ["b" => "c"]
|
||
|
*/
|
||
|
static final function extract_assoc(?array $array, ?array $default=null): ?array {
|
||
|
$assoc = null;
|
||
|
if ($array !== null) {
|
||
|
$index = 0;
|
||
|
foreach ($array as $key => $value) {
|
||
|
if ($key === $index) $index++;
|
||
|
else $assoc[$key] = $value;
|
||
|
}
|
||
|
}
|
||
|
if ($assoc === null) $assoc = $default;
|
||
|
return $assoc;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Extraire d'un tableau les clés séquentielles et les clés associatives
|
||
|
*
|
||
|
* Retourner une liste [$seq, $assoc] où $seq est un tableau avec uniquement
|
||
|
* les valeurs des clés séquentielles et $assoc est un tableau avec uniquement
|
||
|
* les valeurs des clés associatives. S'il n'existe aucune clé séquentielle
|
||
|
* (resp. aucune clé associative), $seq (resp. $assoc) vaut null.
|
||
|
*
|
||
|
* Par exemple: split_assoc(["a", "b" => "c"]) retourne [["a"], ["b" => "c"]]
|
||
|
*/
|
||
|
static final function split_assoc(?array $array): array {
|
||
|
$seq = null;
|
||
|
$assoc = null;
|
||
|
if ($array !== null) {
|
||
|
$i = 0;
|
||
|
foreach ($array as $key => $value) {
|
||
|
if ($key === $i) {
|
||
|
$seq[] = $value;
|
||
|
$i++;
|
||
|
} else {
|
||
|
$assoc[$key] = $value;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return [$seq, $assoc];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Joindre en un seul tableau un tableau avec des clés séquentielles et un
|
||
|
* tableau avec des clés associatives.
|
||
|
*
|
||
|
* Si $seq_first==true, les clés séquentielles arrivent d'abord, ensuite les
|
||
|
* clés associatives. Sinon, ce sont les clés associatives qui arrivent d'abord
|
||
|
*/
|
||
|
static final function merge_assoc(?array &$array, ?array $seq, ?array $assoc, bool $seq_first=false): void {
|
||
|
if ($seq === null && $assoc === null) $array = [];
|
||
|
elseif ($seq === null) $array = $assoc;
|
||
|
elseif ($assoc === null) $array = $seq;
|
||
|
elseif ($seq_first) $array = array_merge($seq, $assoc);
|
||
|
else $array = array_merge($assoc, $seq);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Construire un sous-ensemble du tableau $array en sélectionnant les clés
|
||
|
* mentionnées dans $keys
|
||
|
* .. si $keys === null, retourner $array
|
||
|
* .. sinon, $keys est un tableau avec des clés séquentielles ou associatives.
|
||
|
* chacune des clés séquentielles est prise telle quelle. les clés associatives
|
||
|
* permettent de renommer les clés
|
||
|
*
|
||
|
* soit $array = ["a" => 1, "b" => 2, "c" => 3]
|
||
|
* alors select($array, ["a", "b" => "x"])
|
||
|
* retourne ["a" => 1, "x" => 2]
|
||
|
*/
|
||
|
static final function select(?array $array, ?array $keys, $default=null): array {
|
||
|
if ($array === null) $array = [];
|
||
|
if ($keys === null) return $array;
|
||
|
|
||
|
$index = 0;
|
||
|
$result = [];
|
||
|
foreach ($keys as $key => $tkey) {
|
||
|
if ($key === $index) {
|
||
|
# clé séquentielle
|
||
|
$value = self::get($array, $tkey, $default);
|
||
|
$index++;
|
||
|
} else {
|
||
|
# clé associative
|
||
|
$value = self::get($array, $key, $default);
|
||
|
}
|
||
|
$result[$tkey] = $value;
|
||
|
}
|
||
|
return $result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* construire un sous-ensemble du tableau $array en sélectionnant les clés
|
||
|
* mentionnées dans $keys.
|
||
|
* .. si $keys === null, retourner $array
|
||
|
* .. sinon, $keys est un tableau avec des clés séquentielles ou associatives.
|
||
|
* pour chacune des clés séquentielles, la valeur est une clé pour récupérer
|
||
|
* la valeur dans $array
|
||
|
* pour chacune des clés associatives, la valeur est celle fournie
|
||
|
*/
|
||
|
static final function select_replace(?array $array, ?array $keys, $default=null): array {
|
||
|
if ($array === null) $array = [];
|
||
|
if ($keys === null) return $array;
|
||
|
|
||
|
$index = 0;
|
||
|
$result = [];
|
||
|
foreach ($keys as $key => $value) {
|
||
|
if ($key === $index) {
|
||
|
# clé séquentielle
|
||
|
$result[$value] = self::get($array, $value, $default);
|
||
|
$index++;
|
||
|
} else {
|
||
|
# clé associative
|
||
|
$result[$key] = $value;
|
||
|
}
|
||
|
}
|
||
|
return $result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* comme {@link select_replace()} mais $keys est applati d'abord
|
||
|
*
|
||
|
* par exemple:
|
||
|
* ~~~php
|
||
|
* $src = ["a" => 1, "b" => 2, "c" => 3];
|
||
|
* $dest = A::select($src, ["a", "x" => 9, ["z" => 8, "c"], "d"]);
|
||
|
* # $dest === ["a" => 1, "x" => 9, "z" => 8, "c" => 3, "d" => null]
|
||
|
* ~~~
|
||
|
*/
|
||
|
static final function select_replace2(?array $array, ?array $keys, $default=null): array {
|
||
|
if ($array === null) $array = [];
|
||
|
if ($keys === null) return $array;
|
||
|
self::flatten($keys);
|
||
|
return self::select_replace($array, $keys, $default);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* construire un sous-ensemble du tableau $array en sélectionnant les clés
|
||
|
* mentionnées dans $keys.
|
||
|
* .. si $keys === null, retourner $array
|
||
|
* .. sinon, $keys est un tableau avec des clés séquentielles ou associatives.
|
||
|
* pour chacune des clés séquentielles, la valeur est une clé pour récupérer
|
||
|
* la valeur dans $array
|
||
|
* pour chacune des clés associatives, la valeur fournie est prise par défaut
|
||
|
* si la valeur correspondante n'existe pas ou vaut false dans $array
|
||
|
*/
|
||
|
static final function select_default(?array $array, ?array $keys, $default=null): array {
|
||
|
if ($array === null) $array = [];
|
||
|
if ($keys === null) return $array;
|
||
|
|
||
|
$index = 0;
|
||
|
$result = [];
|
||
|
foreach ($keys as $key => $value) {
|
||
|
if ($key === $index) {
|
||
|
# clé séquentielle
|
||
|
$result[$value] = self::get($array, $value, $default);
|
||
|
$index++;
|
||
|
} else {
|
||
|
# clé associative
|
||
|
if (array_key_exists($key, $array)) {
|
||
|
$arrayValue = $array[$key];
|
||
|
if ($arrayValue !== false) $value = $arrayValue;
|
||
|
}
|
||
|
$result[$key] = $value;
|
||
|
}
|
||
|
}
|
||
|
return $result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* comme {@link select_default()} mais $keys est applati d'abord
|
||
|
*
|
||
|
* par exemple:
|
||
|
* ~~~php
|
||
|
* $src = ["a" => 1, "b" => 2, "c" => 3];
|
||
|
* $dest = A::select($src, ["a", "x" => 9, ["z" => 8, "c"], "d"]);
|
||
|
* # $dest === ["a" => 1, "x" => 9, "z" => 8, "c" => 3, "d" => null]
|
||
|
* ~~~
|
||
|
*/
|
||
|
static final function select_default2(?array $array, ?array $keys, $default=null): array {
|
||
|
if ($array === null) $array = [];
|
||
|
if ($keys === null) return $array;
|
||
|
self::flatten($keys);
|
||
|
return self::select_default($array, $keys, $default);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Construire un sous-ensemble du tableau $array en sélectionnant les clés
|
||
|
* mentionnées dans $includes et pas mentionnées dans $excludes
|
||
|
*
|
||
|
* soit $array = ["a" => 1, "b" => 2, "c" => 3, "d" => 4]
|
||
|
* alors xselect($array, ["a", "b" => "x"], ["d"])
|
||
|
* retourne ["a" => 1, "x" => 2]
|
||
|
*/
|
||
|
static final function xselect_keys(?array $array, ?array $includes, ?array $excludes, $default=null): array {
|
||
|
if ($array === null) $array = [];
|
||
|
if ($includes === null) {
|
||
|
if ($excludes === null) return $array;
|
||
|
else $includes = array_keys($array);
|
||
|
}
|
||
|
|
||
|
$index = 0;
|
||
|
$result = [];
|
||
|
foreach ($includes as $fromkey => $tokey) {
|
||
|
if ($fromkey === $index) {
|
||
|
# clé séquentielle
|
||
|
$index++;
|
||
|
$fromkey = $tokey;
|
||
|
}
|
||
|
if ($excludes !== null && in_array($fromkey, $excludes)) continue;
|
||
|
$value = self::get($array, $fromkey, $default);
|
||
|
$result[$tokey] = $value;
|
||
|
}
|
||
|
return $result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Construire un sous-ensemble du tableau $array en sélectionnant les valeurs
|
||
|
* mentionnées dans $includes et pas mentionnées dans $excludes
|
||
|
*
|
||
|
* soit $array = ["a" => 1, "b" => 2, "c" => 3, "d" => 4]
|
||
|
* alors xselect($array, ["a", "b" => "x"], ["d"])
|
||
|
* retourne ["a" => 1, "x" => 2]
|
||
|
*/
|
||
|
static final function xselect(?array $array, ?array $includes, ?array $excludes, $default=null): array {
|
||
|
if ($array === null) $array = [];
|
||
|
if ($includes === null && $excludes === null) return $array;
|
||
|
|
||
|
$result = [];
|
||
|
foreach ($array as $key => $value) {
|
||
|
if ($excludes !== null && in_array($value, $excludes)) continue;
|
||
|
if ($includes !== null && !in_array($value, $includes)) continue;
|
||
|
$result[$key] = $value;
|
||
|
}
|
||
|
return $result;
|
||
|
}
|
||
|
}
|