push($source, $pkeys); } protected $stack = []; function stackDepth(): int { return count($this->stack); } function &root(): array { return $this->stack; } function push(&$source, $pkeys=null): self { if ($source === null) $source = []; if (is_array($source)) $root =& $source; elseif ($source instanceof IArray) $root =& $source->array(); else throw ValueException::unexpected_type(["array", IArray::class], $source); if ($pkeys === "" || $pkeys === null) $pkeys = []; if (is_string($pkeys)) $pkeys = explode(".", $pkeys); if (!is_array($pkeys)) throw ValueException::unexpected_type(["array", "string"], $pkeys); $data =& $root; foreach ($pkeys as $pkey) { if (!is_array($data)) $data = [$data]; elseif (!array_key_exists($pkey, $data)) $data[$pkey] = null; $data =& $data[$pkey]; } $key = A::last($pkeys); $md = $this->md(); if ($md !== null) $md->ensureSchema($data, $key); array_unshift($this->stack, null); $this->stack[0] =& $data; return $this; } function &pop(): array { $data =& $this->stack[0]; array_shift($this->stack); return $data; } function &peek(int $index=1): array { $count = count($this->stack); if ($count > 0) { while ($index < 0) $index += $count; } return $this->stack[$index]; } function __toString(): string { return var_export($this->stack, true); } function &array(): ?array { return $this->stack[0]; } function keys(): array { $keys = []; foreach ($this->stack as $data) { $dataKeys = array_fill_keys(array_keys($data), true); A::merge2($keys, $dataKeys); } return array_keys($keys); } function count(): int { return count($this->keys()); } function _has($key): bool { foreach ($this->stack as $data) { if (array_key_exists($key, $data)) return true; } return false; } function &_get($key, $default=null) { foreach ($this->stack as $data) { if (array_key_exists($key, $data)) return $data[$key]; } return $default; } function _set($key, $value) { if ($key === null) $this->stack[0][] = $value; else $this->stack[0][$key] = $value; return $this; } function _del($key) { unset($this->stack[0][$key]); return $this; } /** * retourner le gestionnaire de schéma. le mieux dans les classes dérivées est * d'utiliser le trait {@link TArrayMd} qui maintient un cache partagé entre * toutes les instances de la classe. */ protected function md(): ?Metadata { $schema = static::SCHEMA; if ($schema === null) return null; else return new Metadata($schema); } # Rajouter ceci dans les classes dérivées: #use TArrayMd, TAutoconstsStatic; // ou TArrayMdDynamic, TAutoconstsDynamic #const _AUTOGEN_CONSTS = ["" => [self::class, "_AUTOGEN_CONSTS"]]; ##--autogen-dynamic-- }