我们知道,php的复合类型只有array与object,面对一些多维数组的运算时,难免有些吃力,下面我们来封装一个php集合类。

<?php

/**
 * Interface Arrayable
 */
interface Arrayable
{
    public function toArray(): array;
}

/**
 * Interface Jsonable
 */
interface Jsonable
{
    public function toJson(int $options = 0): string;
}

/**
 * Interface JsonSerializable
 */
interface JsonSerializable
{
    public function jsonSerialize(): array;
}

/**
 * Class Collect
 * @package app\helpers\Support
 */
class Collect implements Arrayable, Jsonable, JsonSerializable
{
    protected $items = [];

    /**
     * Collect constructor.
     * @param array $items
     */
    public function __construct($items = [])
    {
        $this->items = $this->getArrayAbleItems($items);
    }

    /**
     * @param $items
     * @return array|mixed
     */
    private function getArrayAbleItems($items)
    {
        if (is_array($items)) {
            return $items;
        } elseif ($items instanceof self) {
            return $items->all();
        } elseif ($items instanceof Arrayable) {
            return $items->toArray();
        } elseif ($items instanceof Jsonable) {
            return json_decode($items->toJson(), true);
        } elseif ($items instanceof JsonSerializable) {
            return $items->jsonSerialize();
        }

        return (array)$items;
    }

    /**
     * @param callable|null $callback
     * @return $this
     */
    public function filter(callable $callback = null): self
    {
        if ($callback) {
            $return = [];

            foreach ($this->items as $key => $value) {

                //获取到满足条件的回调则加入$return中
                if ($callback($value, $key)) {
                    $return[$key] = $value;
                }
            }

            return new static($return);
        }

        return new static(array_filter($this->items));
    }

    /**
     * 返回满足条件的数据
     * @param $key
     * @param $value
     * @param bool $strict
     * @return $this
     */
    public function where($key, $value, $strict = true): self
    {
        return $this->filter(function ($item) use ($key, $value, $strict) {
            return $strict ? $item == $value : $item === $value;
        });
    }

    /**
     * @param $key
     * @param array $value
     * @return $this
     */
    public function whereIn($key, array $value = []): self
    {
        return $this->filter(function ($item) use ($key, $value) {
            return in_array($item, $value);
        });
    }

    /**
     * @return array
     */
    public function all(): array
    {
        return $this->items;
    }

    /**
     * @return array
     */
    public function toArray(): array
    {
        return array_map(function ($value) {
            return $value instanceof Arrayable ? $value->toArray() : $value;
        }, $this->items);
    }

    /**
     * @param int $options
     * @return string
     */
    public function toJson(int $options = 0): string
    {
        return json_encode($this->jsonSerialize(), $options);
    }

    /**
     * @return array
     */
    public function jsonSerialize(): array
    {
        return array_map(function ($value) {
            if ($value instanceof JsonSerializable) {
                return $value->jsonSerialize();
            } elseif ($value instanceof Jsonable) {
                return json_decode($value->toJson(), true);
            } elseif ($value instanceof Arrayable) {
                return $value->toArray();
            } else {
                return $value;
            }
        }, $this->items);
    }
}

function collect($items = [])
{
    return new Collect($items);
}

var_dump(collect([111, 222, 333, 444, 555])->filter(function ($item) {
    return $item > 200 ? $item : null;
}));

var_dump(collect([111, 222, 333, 444, 555])->where(0, 111)->all());

var_dump(collect([111, 222, 333, 444, 555])->whereIn(0, [111, 222, 333])->all());

//大概原理就是这样,模拟了集合操作中的filter与whereIn操作,当然这个还有一些不完善的地方,主要是学习构造集合操作的思路.