代码之家  ›  专栏  ›  技术社区  ›  Sylwester

是否可以在PHP中生成唯一的值?

php
  •  3
  • Sylwester  · 技术社区  · 6 年前

    我正在创建一个数组类,希望一个值能够由高阶函数返回。其思想是,它是一个实例常量或方法返回的值,这样我可以跳过 map .

    在其他语言中,生成数组或某个复合值,例如 ['skip'] 将使其指针相等,这样我就可以使用指针相等的运算符,它将不等于具有完全相同内容的其他数组,但我的问题是 ['skip'] === ['skip'] 是真的,所以即使 === 两个值相同。

    下面是一个使用我的代码的示例,其中我与以前跳过的代码具有相同的值:

    namespace Test;
    use Common\Domain\Collection;
    
    $arr = new Collection();
    $arr[] = 1;
    $arr[] = 2;
    $arr[] = 3;
    $arr[] = 4;
    echo count($arr); // prints 4
    $arr2 = $arr->map(function ($v) { 
        return $v % 2 == 0 ? Collection::SKIP : ["skip"]; 
    });
    echo count($arr2); // prints 0, but should be 2
    

    有没有办法获得一个独特的价值或以某种方式解决这个问题? 这是实现的代码 Collection :

    namespace Common\Domain;;
    
    class Collection implements \Iterator, \Countable, \ArrayAccess
    {
        const SKIP = ["skip"];
        private $arr = [];
    
        public function map(callable $fn, bool $keepKeys = false) :Collection
        {
            $arr = new static();
            $nOrder = 0;
            foreach($this->arr as $key => $value) {
                $result = call_user_func($fn, $value, $key, $nOrder, $this);
                if($result !== self::SKIP) {
                    if($keepKeys) {
                        $arr[$key] = $result;
                    } else {
                        $arr[] = $result;
                    }
                }
            }
            return $arr;
        }
    
        // implementation of interfaces \Iterator, \Countable, \ArrayAccess
    
        public function current()
        {
            return current($this->arr);
        }
    
        public function next()
        {
            next($this->arr);
        }
    
        public function key()
        {
            return key($this->arr);
        }
    
        public function valid()
        {
            return isset($this->arr[$this->key()]);
        }
    
        public function rewind()
        {
            reset($this->arr);
        }
    
        public function count()
        {
            return count($this->arr);
        }
    
        public function offsetExists($offset)
        {
            return array_key_exists($offset, $this->arr);
        }
    
        public function offsetGet($offset)
        {
            return $this->arr[$offset];
        }
    
        public function offsetSet($offset, $value)
        {
            $this->arr[$offset] = $value;
        }
    
        public function offsetUnset($offset)
        {
            unset($this->arr[$offset]);
        }
    
    }
    
    2 回复  |  直到 6 年前
        1
  •  1
  •   OddBrew    6 年前

    我猜您正在寻找Java类型枚举,PHP中不存在枚举。我对您的问题的最佳猜测是使用一个对象而不是常量,您可以静态地实例化它以方便使用。然后,在map函数的循环中,使用 instanceof 不是基本的相等运算符,而是针对您定义的类。

    所以,这里:

    class UniqueValue
    {
        public static function get()
        {
            return new self();
        }
    }
    

    然后:

    $arr2 = $arr->map(function ($v) { 
        return $v % 2 == 0 ? UniqueValue::get() : ["skip"]; 
    });
    

    在你的收藏中:

    public function map(callable $fn, bool $keepKeys = false) :Collection
        {
            $arr = new static();
            $nOrder = 0;
            foreach($this->arr as $key => $value) {
                $result = call_user_func($fn, $value, $key, $nOrder, $this);
                if($result ! instanceof UniqueValue) {
                    if($keepKeys) {
                        $arr[$key] = $result;
                    } else {
                        $arr[] = $result;
                    }
                }
            }
            return $arr;
        }
    

    这是我能想到的最快的方法。如果数组包含来自“外部”的数据,我认为它不可能以任何方式与来自您自己代码的类检查相匹配。

        2
  •  0
  •   Eriks Klotins    6 年前

    我将通过实现另一种方法来解决这个问题。方法 delete 将在集合上映射函数,并移除函数返回false的任何元素。

    例如

    class Collection
    {
    // ...
        public function delete($func)
        {
            $result = new static();
            foreach($this->arr as $item)
            {
                if($func($item) !== false) $result[] = $item;
            }
        }
    }
    
    // example
    
    $arr = new Collection();
    $arr[] = 1;
    $arr[] = 2;
    $arr[] = 3;
    $arr[] = 4;
    echo count($arr); // prints 4
    $arr2 = $arr->delete(function ($v) { 
      return $v % 2 ? true : false;
    });
    var_dump($arr2); // prints [2, 4]