Created
June 22, 2022 00:45
-
-
Save ghostwriter/50a2ee58efe7354a5591abad739ff772 to your computer and use it in GitHub Desktop.
collection wip
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| declare(strict_types=1); | |
| namespace Ghostwriter\Collection; | |
| use Closure; | |
| use Ghostwriter\Collection\Contract\CollectionInterface; | |
| use InvalidArgumentException; | |
| use Traversable; | |
| use const PHP_INT_MAX; | |
| use const true; | |
| /** | |
| * @template TValue | |
| * @implements CollectionInterface<TValue> | |
| */ | |
| abstract class AbstractCollection implements CollectionInterface | |
| { | |
| /** | |
| * @var Closure():iterable<TValue> | |
| */ | |
| private Closure $generator; | |
| /** | |
| * @param ?Closure():iterable<TValue> $generator | |
| */ | |
| final private function __construct(?Closure $generator = null) | |
| { | |
| $this->generator = $generator ?? static fn (): iterable => []; | |
| } | |
| public function append(iterable $iterable = []): self | |
| { | |
| return new static(function () use ($iterable): Traversable { | |
| yield from ($this->generator)(); | |
| yield from $iterable; | |
| }); | |
| } | |
| public function contains(mixed $item, ?Closure $function = null): bool | |
| { | |
| $function = $function ?? static fn (mixed $value): mixed => $value; | |
| foreach (($this->generator)() as $value) { | |
| if ($function($item) === $function($value)) { | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| public function count(): int | |
| { | |
| return iterator_count($this); | |
| } | |
| public function drop(int $length): self | |
| { | |
| return $this->slice($length); | |
| } | |
| public function filter(Closure $function): self | |
| { | |
| return new static(function () use ($function): Traversable { | |
| foreach (($this->generator)() as $value) { | |
| if ($function($value)) { | |
| yield $value; | |
| } | |
| } | |
| }); | |
| } | |
| public function first(Closure $function = null): mixed | |
| { | |
| $function = $function ?? static fn (mixed $_): bool => true; | |
| foreach (($this->generator)() as $value) { | |
| if ($function($value)) { | |
| return $value; | |
| } | |
| } | |
| return null; | |
| } | |
| public static function fromGenerator(Closure $generator): self | |
| { | |
| return new static($generator); | |
| } | |
| public static function fromIterable(iterable $values = []): self | |
| { | |
| return new static(static fn () => yield from $values); | |
| } | |
| public function getIterator(): iterable | |
| { | |
| return ($this->generator)(); | |
| } | |
| public function isEmpty(): bool | |
| { | |
| return 0 === $this->count(); | |
| } | |
| public function last(?Closure $function = null): mixed | |
| { | |
| $last = null; | |
| $function = $function ?? static fn (mixed $_): bool => true; | |
| foreach (($this->generator)() as $value) { | |
| if ($function($value)) { | |
| $last = $value; | |
| } | |
| } | |
| return $last; | |
| } | |
| public function map(Closure $function): self | |
| { | |
| return new static(function () use ($function) { | |
| foreach (($this->generator)() as $value) { | |
| yield $function($value); | |
| } | |
| }); | |
| } | |
| public function reduce(Closure $function, mixed $accumulator = null): mixed | |
| { | |
| foreach (($this->generator)() as $value) { | |
| $accumulator = $function($accumulator, $value); | |
| } | |
| return $accumulator; | |
| } | |
| public function slice(int $offset, int $length = PHP_INT_MAX): self | |
| { | |
| return new static(function () use ($offset, $length): Traversable { | |
| $count = 0; | |
| if ($offset < $count) { | |
| throw new InvalidArgumentException('$offset must be positive'); | |
| } | |
| if ($length < $count) { | |
| throw new InvalidArgumentException('$length must be positive'); | |
| } | |
| if ($length === $count) { | |
| return; | |
| } | |
| foreach (($this->generator)() as $value) { | |
| if ($count++ < $offset) { | |
| continue; | |
| } | |
| yield $value; | |
| if ($count >= ($offset + $length)) { | |
| break; | |
| } | |
| } | |
| }); | |
| } | |
| public function take(int $length): self | |
| { | |
| return $this->slice(0, $length); | |
| } | |
| public function toArray(): array | |
| { | |
| return iterator_to_array($this, false); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| declare(strict_types=1); | |
| namespace Ghostwriter\Collection\Contract; | |
| use Closure; | |
| use Countable; | |
| use IteratorAggregate; | |
| use Traversable; | |
| use const PHP_INT_MAX; | |
| /** | |
| * @template TValue | |
| * @template-implements IteratorAggregate<array-key,TValue> | |
| */ | |
| interface CollectionInterface extends Countable, IteratorAggregate | |
| { | |
| /** | |
| * @param iterable<TValue> $iterable | |
| */ | |
| public function append(iterable $iterable): self; | |
| /** | |
| * @param TValue $item | |
| * @param ?Closure(TValue):TValue $function | |
| */ | |
| public function contains(mixed $item, ?Closure $function = null): bool; | |
| /** | |
| * @return int<0, max> | |
| */ | |
| public function count(): int; | |
| /** | |
| * @param int<0, max> $length | |
| */ | |
| public function drop(int $length): self; | |
| /** | |
| * @param (Closure(TValue):bool) $function | |
| */ | |
| public function filter(Closure $function): self; | |
| /** | |
| * @param ?Closure(TValue):bool $function | |
| * | |
| * @return null|TValue | |
| */ | |
| public function first(?Closure $function = null): mixed; | |
| /** | |
| * @param Closure():Traversable $generator | |
| */ | |
| public static function fromGenerator(Closure $generator): self; | |
| /** | |
| * @template TIterableValue | |
| * | |
| * @param iterable<TIterableValue> $values | |
| */ | |
| public static function fromIterable(iterable $values = []): self; | |
| /** | |
| * @return iterable<TValue> | |
| */ | |
| public function getIterator(): iterable; | |
| public function isEmpty(): bool; | |
| /** | |
| * @param ?Closure(TValue):bool $function | |
| * | |
| * @return null|TValue | |
| */ | |
| public function last(?Closure $function = null): mixed; | |
| /** | |
| * @template TMapValue | |
| * | |
| * @param (Closure(TValue):TMapValue) $function | |
| */ | |
| public function map(Closure $function): self; | |
| /** | |
| * @template TReduceValue | |
| * | |
| * @param (Closure(TReduceValue|null,TValue):TReduceValue) $function | |
| * @param TReduceValue $accumulator | |
| * | |
| * @return null|TReduceValue | |
| */ | |
| public function reduce(Closure $function, mixed $accumulator = null): mixed; | |
| /** | |
| * @param int<0, max> $offset | |
| * @param int<0, max> $length | |
| */ | |
| public function slice(int $offset, int $length = PHP_INT_MAX): self; | |
| /** | |
| * @param int<0, max> $length | |
| */ | |
| public function take(int $length): self; | |
| /** | |
| * @return array<array-key,TValue> | |
| */ | |
| public function toArray(): array; | |
| } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
PHP Collection package - https://github.com/ghostwriter/collection