Skip to content

Refactor: namespace everything #13

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 23 additions & 65 deletions src/IterableObject.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@

namespace BenTools\IterableFunctions;

use Closure;
use EmptyIterator;
use InvalidArgumentException;
use IteratorAggregate;
use Traversable;

/**
* @internal
*/
final class IterableObject implements IteratorAggregate
{
/**
Expand All @@ -18,93 +19,50 @@ final class IterableObject implements IteratorAggregate
/**
* @var callable
*/
private $filter;
private $filterFn;

/**
* @var callable
*/
private $map;
private $mapFn;

/**
* IterableObject constructor.
* @param iterable|array|Traversable $iterable
* @param callable|null $filter
* @param callable|null $map
* @throws InvalidArgumentException
*/
public function __construct($iterable, $filter = null, $map = null)
public function __construct(?iterable $iterable = null, ?callable $filter = null, ?callable $map = null)
{
if (null === $iterable) {
$iterable = new EmptyIterator();
}
if (!is_iterable($iterable)) {
throw new InvalidArgumentException(
sprintf('Expected array or Traversable, got %s', is_object($iterable) ? get_class($iterable) : gettype($iterable))
);
}

// Cannot rely on callable type-hint on PHP 5.3
if (null !== $filter && !is_callable($filter) && !$filter instanceof Closure) {
throw new InvalidArgumentException(
sprintf('Expected callable, got %s', is_object($filter) ? get_class($filter) : gettype($filter))
);
}

if (null !== $map && !is_callable($map) && !$map instanceof Closure) {
throw new InvalidArgumentException(
sprintf('Expected callable, got %s', is_object($map) ? get_class($map) : gettype($map))
);
}

$this->iterable = $iterable;
$this->filter = $filter;
$this->map = $map;
$this->iterable = $iterable ?? new EmptyIterator();
$this->filterFn = $filter;
$this->mapFn = $map;
}

/**
* @param callable $filter
* @return self
*/
public function filter($filter)
public function filter(callable $filter): self
{
return new self($this->iterable, $filter, $this->map);
return new self($this->iterable, $filter, $this->mapFn);
}

/**
* @param callable $map
* @return self
*/
public function map($map)
public function map(callable $map): self
{
return new self($this->iterable, $this->filter, $map);
return new self($this->iterable, $this->filterFn, $map);
}

/**
* @inheritdoc
*/
public function getIterator()
public function getIterator(): Traversable
{
$iterable = $this->iterable;
if (null !== $this->filter) {
$iterable = iterable_filter($iterable, $this->filter);
if (null !== $this->filterFn) {
$iterable = iterable_filter($iterable, $this->filterFn);
}
if (null !== $this->map) {
$iterable = iterable_map($iterable, $this->map);
if (null !== $this->mapFn) {
$iterable = iterable_map($iterable, $this->mapFn);
}
return iterable_to_traversable($iterable);
}

/**
* @return array
*/
public function asArray()
public function asArray(): array
{
$iterable = $this->iterable;
if (null !== $this->filter) {
$iterable = iterable_filter($iterable, $this->filter);
if (null !== $this->filterFn) {
$iterable = iterable_filter($iterable, $this->filterFn);
}
if (null !== $this->map) {
$iterable = iterable_map($iterable, $this->map);
if (null !== $this->mapFn) {
$iterable = iterable_map($iterable, $this->mapFn);
}
return iterable_to_array($iterable);
}
Expand Down
232 changes: 83 additions & 149 deletions src/iterable-functions.php
Original file line number Diff line number Diff line change
@@ -1,174 +1,108 @@
<?php

use BenTools\IterableFunctions\IterableObject;

if (!function_exists('iterable_map')) {

/**
* Maps a callable to an iterable.
*
* @param iterable|array|\Traversable $iterable
* @param callable $map
* @return array|ArrayIterator
* @throws InvalidArgumentException
*/
function iterable_map($iterable, $map)
{
if (!is_iterable($iterable)) {
throw new \InvalidArgumentException(
sprintf('Expected array or Traversable, got %s', is_object($iterable) ? get_class($iterable) : gettype($iterable))
);
}

// Cannot rely on callable type-hint on PHP 5.3
if (null !== $map && !is_callable($map) && !$map instanceof Closure) {
throw new InvalidArgumentException(
sprintf('Expected callable, got %s', is_object($map) ? get_class($map) : gettype($map))
);
}

if ($iterable instanceof Traversable) {
return new ArrayIterator(array_map($map, iterator_to_array($iterable)));
}

return array_map($map, $iterable);
namespace BenTools\IterableFunctions;


use ArrayIterator;
use CallbackFilterIterator;
use IteratorIterator;
use Traversable;

/**
* Maps a callable to an iterable.
*
* @param array|Traversable $iterable
* @return array|ArrayIterator
*/
function iterable_map(iterable $iterable, callable $map): iterable
{
if ($iterable instanceof Traversable) {
return new ArrayIterator(array_map($map, iterator_to_array($iterable)));
}

return array_map($map, $iterable);
}


if (!function_exists('is_iterable')) {

/**
* Check wether or not a variable is iterable (i.e array or \Traversable)
*
* @param mixed $iterable
* @return bool
*/
function is_iterable($iterable)
{
return is_array($iterable) || $iterable instanceof \Traversable;
/**
* Copy the iterable into an array. If the iterable is already an array, return it.
*
* @param array|Traversable $iterable
* @param bool $use_keys [optional] Whether to use the iterator element keys as index.
* @return array
*/
function iterable_to_array(iterable $iterable, bool $use_keys = true): array
{
if ($iterable instanceof Traversable) {
return iterator_to_array($iterable, $use_keys);
}

return $use_keys ? $iterable : array_values($iterable);
}

if (!function_exists('iterable_to_array')) {

/**
* Copy the iterable into an array. If the iterable is already an array, return it.
*
* @param iterable|array|\Traversable $iterable
* @param bool $use_keys [optional] Whether to use the iterator element keys as index.
* @return array
*/
function iterable_to_array($iterable, $use_keys = true)
{
return is_array($iterable) ? ($use_keys ? $iterable : array_values($iterable)) : iterator_to_array($iterable, $use_keys);
/**
* If the iterable is not intance of Traversable, it is an array => convert it to an ArrayIterator.
*
* @param array|Traversable $iterable
*/
function iterable_to_traversable(iterable $iterable): Traversable
{
if ($iterable instanceof Traversable) {
return $iterable;
}

return new ArrayIterator($iterable);
}

if (!function_exists('iterable_to_traversable')) {

/**
* If the iterable is not intance of \Traversable, it is an array => convert it to an ArrayIterator.
*
* @param iterable|array|\Traversable $iterable
* @return \Traversable
*/
function iterable_to_traversable($iterable)
{
if ($iterable instanceof Traversable) {
return $iterable;
} elseif (is_array($iterable)) {
return new ArrayIterator($iterable);
} else {
throw new \InvalidArgumentException(
sprintf(
'Expected array or \\Traversable, got %s',
is_object($iterable) ? get_class($iterable) : gettype($iterable)
)
);
}

/**
* Filters an iterable.
*
* @param array|Traversable $iterable
* @return array|CallbackFilterIterator
*/
function iterable_filter(iterable $iterable, ?callable $filter = null)
{
if (null === $filter) {
$filter = static function ($value) {
return (bool) $value;
};
}
}

if (!function_exists('iterable_filter')) {

/**
* Filters an iterable.
*
* @param iterable|array|\Traversable $iterable
* @param callable $filter
* @return array|CallbackFilterIterator
* @throws InvalidArgumentException
*/
function iterable_filter($iterable, $filter = null)
{
if (!is_iterable($iterable)) {
throw new \InvalidArgumentException(
sprintf('Expected array or Traversable, got %s', is_object($iterable) ? get_class($iterable) : gettype($iterable))
);
}

// Cannot rely on callable type-hint on PHP 5.3
if (null !== $filter && !is_callable($filter) && !$filter instanceof Closure) {
throw new InvalidArgumentException(
sprintf('Expected callable, got %s', is_object($filter) ? get_class($filter) : gettype($filter))
);
}

if (null === $filter) {
$filter = function ($value) {
return (bool) $value;
};
}

if ($iterable instanceof Traversable) {
if (!class_exists('CallbackFilterIterator')) {
throw new \RuntimeException('Class CallbackFilterIterator not found. Try using a polyfill, like symfony/polyfill-php54');
}
return new CallbackFilterIterator(new IteratorIterator($iterable), $filter);
}

return array_filter($iterable, $filter);
if ($iterable instanceof Traversable) {
return new CallbackFilterIterator(new IteratorIterator($iterable), $filter);
}

return array_filter($iterable, $filter);
}

if (!function_exists('iterable_reduce')) {
/**
* Reduces an iterable.
*
* @param iterable<mixed> $iterable
* @param callable(mixed, mixed) $reduce
* @return mixed
*
* @psalm-template TValue
* @psalm-template TResult
*
* @psalm-param iterable<TValue> $iterable
* @psalm-param callable(TResult|null, TValue) $reduce
* @psalm-param TResult|null $initial
*
* @psalm-return TResult|null
*/
function iterable_reduce($iterable, $reduce, $initial = null)
{
foreach ($iterable as $item) {
$initial = $reduce($initial, $item);
}

return $initial;
}
}

/**
* @param iterable|array|\Traversable $iterable
* @param callable|null $filter
* @param callable|null $map
* @return Traversable|IterableObject
* @throws InvalidArgumentException
* Reduces an iterable.
*
* @param iterable<mixed> $iterable
* @param callable(mixed, mixed) $reduce
* @return mixed
*
* @psalm-template TValue
* @psalm-template TResult
*
* @psalm-param iterable<TValue> $iterable
* @psalm-param callable(TResult|null, TValue) $reduce
* @psalm-param TResult|null $initial
*
* @psalm-return TResult|null
*/
function iterable($iterable, $filter = null, $map = null)
function iterable_reduce(iterable $iterable, callable $reduce, $initial = null)
{
foreach ($iterable as $item) {
$initial = $reduce($initial, $item);
}

return $initial;
}

function iterable(iterable $iterable, ?callable $filter = null, ?callable $map = null): IterableObject
{
return new IterableObject($iterable, $filter, $map);
}
Loading