src/Collection/Map.php
<?php
declare(strict_types=1);
namespace Tale\Collection;
use Tale\AbstractCollection;
use Tale\Collection;
use Tale\CollectionInterface;
class Map extends AbstractCollection implements MapInterface
{
/**
* @var array
*/
private $keys = [];
/**
* @var array
*/
private $values = [];
public function __construct(iterable $entries = [])
{
foreach ($entries as $entry) {
if (!\is_array($entry) || \count($entry) !== 2) {
throw new \InvalidArgumentException('Map entries need to be an array of [$key, $value]');
}
$this->offsetSet($entry[0], $entry[1]);
}
}
public function getKeys(): CollectionInterface
{
return new Collection($this->keys);
}
public function getValues(): CollectionInterface
{
return new Collection($this->values);
}
public function getEntries(): CollectionInterface
{
return new Collection($this->getIterable());
}
public function has($key)
{
return $this->offsetExists($key);
}
public function set($key, $value): void
{
$this->offsetSet($key, $value);
}
public function get($key)
{
return $this->offsetGet($key);
}
public function remove($key)
{
$this->offsetUnset($key);
}
public function offsetExists($offset): bool
{
return \in_array($offset, $this->keys, true);
}
public function offsetGet($offset)
{
$index = \array_search($offset, $this->keys, true);
if ($index === false) {
throw new \OutOfRangeException('The key doesn\'t exist in this map');
}
return $this->values[$index];
}
public function offsetSet($offset, $value): void
{
$index = \array_search($offset, $this->keys, true);
if ($index === false) {
$index = \count($this->keys);
$this->keys[$index] = $offset;
}
$this->values[$index] = $value;
}
public function offsetUnset($offset): void
{
$index = \array_search($offset, $this->keys, true);
if ($index === false) {
return;
}
array_splice($this->keys, $index, 1);
array_splice($this->values, $index, 1);
}
public function count(): int
{
return \count($this->keys);
}
public function sort(callable $comparator = null): void
{
$entries = $this->toArray();
usort($entries, $comparator ?? function (array $entryA, array $entryB) {
return $entryA[1] <=> $entryB[1];
});
$this->keys = [];
$this->values = [];
foreach ($entries as $entry) {
[$key, $value] = $entry;
$this->keys[] = $key;
$this->values[] = $value;
}
}
public function join(string $delimiter = ',', string $keyDelimiter = null): string
{
$entries = iterator_to_array($this->getIterator());
$values = [];
foreach ($entries as [$key, $value]) {
$values[] = $keyDelimiter !== null
? "{$key}{$keyDelimiter}{$value}"
: $value;
}
return implode($delimiter, $values);
}
public function serialize(): string
{
return serialize([$this->keys, $this->values]);
}
public function unserialize($serialized): void
{
[$this->keys, $this->values] = unserialize($serialized);
}
public function jsonSerialize()
{
return iterator_to_array($this->getEntries());
}
protected function getIterable(): iterable
{
foreach ($this->keys as $i => $key) {
yield [$key, $this->values[$i]];
}
}
}