【问题标题】:PHP : Remove object from arrayPHP:从数组中删除对象
【发布时间】:2011-04-04 03:38:24
【问题描述】:

在 PHP 中从对象数组中删除对象的优雅方法是什么?

只是为了清楚..

class Data{

  private $arrObservers;

  public add(Observer $o) {  
    array_push($this->arrObservers, $o);  
  }    
  public remove(Observer $o) {  
    // I NEED THIS CODE to remove $o from $this->arrObservers
  }  

}

【问题讨论】:

  • 我猜你的意思是array_push($this->arrObservers, $o)
  • 对于 Data::add(), $this->observers[] = $o,效率更高。

标签: php arrays object


【解决方案1】:

阅读 GoF 书籍的观察者模式部分?这是一个解决方案,无需进行昂贵的搜索来查找要删除的对象的索引。

public function addObserver(string $aspect, string $viewIndex, Observer $view)
{   
    $this->observers[$aspect][$viewIndex] = $view;
}

public function removeObserver(string $aspect, string $viewIndex)
{
    if (!isset($this->observers[$aspect])) {
        throw new OutOfBoundsException("No such aspect ({$aspect}) of this Model exists: " . __CLASS__);
    }
    
    if (!isset($this->observers[$aspect][$viewIndex])) {
        throw new OutOfBoundsException("No such View for ({$viewIndex}) was added to the aspect ({$aspect}) of this Model:" . __CLASS__);
    }

    unset($this->observers[$aspect][$viewIndex]);
}

如果您不使用跟踪由特定Models 更新的Views 的方式,您可以松开“方面”维度。

public function addObserver(string $viewIndex, Observer $view)
{   
    $this->observers[$viewIndex] = $view;
}

public function removeObserver(string $viewIndex)
{   
    if (!isset($this->observers[$viewIndex])) {
        throw new OutOfBoundsException("No such View for ({$viewIndex}) was added to this Model:" . __CLASS__);
    }

    unset($this->observers[$viewIndex]);
}

总结

在将对象分配给数组之前,以一种查找元素的方式构建。否则,您必须先发现对象元素的索引。

如果您有大量的对象元素(或者甚至更多),那么您可能需要先求助于查找对象的索引。 PHP 函数array_search() 是一种以值开头并获取索引/键作为回报的方法。

https://www.php.net/manual/en/function.array-search.php

请务必在调用函数时使用strict 参数。

如果第三个参数 strict 设置为 true 那么 array_search() 函数将在大海捞针中搜索相同的元素。这 意味着它还将执行严格的针类型比较 大海捞针,和对象必须是同一个实例

【讨论】:

    【解决方案2】:

    如果要从对象数组中删除一个或多个对象(使用 spl_object_hash 确定对象是否相同),可以使用此方法:

    $this->arrObservers = Arr::diffObjects($this->arrObservers, [$o]);
    

    来自this library

    【讨论】:

      【解决方案3】:

      要从multi dimensional array 中删除对象,您可以使用以下命令:

      $exampleArray= [
          [
            "myKey"=>"This is my key",
            "myValue"=>"10"
          ],
          [
            "myKey"=>"Oh!",
            "myValue"=>"11"
          ]
      ];
      

      使用array_column,您可以指定您的键列名称:

      if(($key = array_search("Oh!", array_column($exampleArray, 'myKey'))) !== false) {
          unset($exampleArray[$key]);
      }
      

      这将删除指示的对象。

      【讨论】:

        【解决方案4】:

        我相信这是最好的方法

        $index = array_search($o, $this->arrObservers, true);
        
        unset($this->arrObservers[$index]);
        

        【讨论】:

          【解决方案5】:
           function obj_array_clean ($array, $objId)
           {
              $new = array() ;
              foreach($array as $value)
              {
                  $new[$value->{$objId}] = $value;
              }
              $array = array_values($new);
              return $array;
           }
          
           $ext2 = obj_array_clean($ext, 'OnjId');
          
          • 它将从数组对象 $array 中删除重复的对象“OnjId”。

          【讨论】:

            【解决方案6】:

            试试这个,会解决你的问题。

            class Data{
              private $arrObservers;
            
              public add(Observer $o) {  
                array_push($this->arrObservers,$o);  
              }    
            
              public remove($Observer $o) {  
                unset($this->arrObservers[$o]);  
              }  
            }
            

            【讨论】:

            • array_push 将分配一个数字键,因此即使数组可以使用对象作为键,您也不会找到 $o 作为键
            【解决方案7】:

            将其用于您的内部对象存储:http://us2.php.net/manual/en/class.splobjectstorage.php

            【讨论】:

              【解决方案8】:

              你可以的

              function unsetValue(array $array, $value, $strict = TRUE)
              {
                  if(($key = array_search($value, $array, $strict)) !== FALSE) {
                      unset($array[$key]);
                  }
                  return $array;
              }
              

              您还可以使用spl_object_hash 为对象创建一个哈希并将其用作数组键。

              然而,PHP 也有一个用于对象集合的原生数据结构 SplObjectStorage

              $a = new StdClass; $a->id = 1;
              $b = new StdClass; $b->id = 2;
              $c = new StdClass; $c->id = 3;
              
              $storage = new SplObjectStorage;
              $storage->attach($a);
              $storage->attach($b);
              $storage->attach($c);
              echo $storage->count(); // 3
              
              // trying to attach same object again
              $storage->attach($c);
              echo $storage->count(); // still 3
              
              var_dump( $storage->contains($b) ); // TRUE
              $storage->detach($b);
              var_dump( $storage->contains($b) ); // FALSE
              

              SplObjectStorageTraversable,所以你也可以foreach 覆盖它。

              顺便说一句,PHP 还为SubjectObserver 提供了本机接口。

              【讨论】:

              • +1 这是最好的方法。更不用说从 PHP 5.3 开始,SplObjectStorage 实现了ArrayAccess
              • 我建议使用if(($key = array_search($value, $array, $strict)) !== false) cuz 0 == false
              • @Anpher 好电话。固定的。虽然我真的认为如果只有对象要处理,OP 应该使用 SplObjectStorage。
              • 赞成 SplObjectStorage 的参考 - 正是我需要的。
              • SplObjectStorage!这是最好的方法
              【解决方案9】:

              我同意上面的答案,但为了完整起见(您可能没有唯一的 ID 可用作键),我从数组中删除值的首选方法如下:

              /**
               * Remove each instance of a value within an array
               * @param array $array
               * @param mixed $value
               * @return array
               */
              function array_remove(&$array, $value)
              {
                  return array_filter($array, function($a) use($value) {
                      return $a !== $value;
                  });
              }
              
              /**
               * Remove each instance of an object within an array (matched on a given property, $prop)
               * @param array $array
               * @param mixed $value
               * @param string $prop
               * @return array
               */
              function array_remove_object(&$array, $value, $prop)
              {
                  return array_filter($array, function($a) use($value, $prop) {
                      return $a->$prop !== $value;
                  });
              }
              

              使用方式如下:

              $values = array(
                  1, 2, 5, 3, 5, 6, 7, 1, 2, 4, 5, 6, 6, 8, 8,
              );
              print_r(array_remove($values, 6));
              
              class Obj {
                  public $id;
                  public function __construct($id) {
                      $this->id = $id;
                  }
              }
              $objects = array(
                  new Obj(1), new Obj(2), new Obj(4), new Obj(3), new Obj(6), new Obj(4), new Obj(3), new Obj(1), new Obj(5),
              );
              print_r(array_remove_object($objects, 1, 'id'));
              

              希望对您有所帮助。

              【讨论】:

                【解决方案10】:

                我建议使用对象的 ID(如果你有 ID,那么任何对该对象唯一的东西都应该在合理范围内起作用)作为数组键。这样,您可以在数组中寻址对象,而无需运行循环或将 ID 存储在另一个位置。代码看起来像这样:

                $obj_array[$obj1->getId()] = $obj1;
                $obj_array[$obj2->getId()] = $obj2;
                $obj_array[$obj3->getId()] = $obj3;
                
                unset($obj_array[$object_id]);
                

                更新:

                class Data{
                
                  private $arrObservers;
                
                  public add(Observer $o) {  
                    $this->arrObservers[$o->getId()] = $o;  
                  }    
                  public remove(Observer $o) {  
                    unset($this->arrObservers[$o->getId()]);
                  }  
                
                }
                

                【讨论】:

                • 不过,您将需要 Observer 对象的 getId() 方法。
                【解决方案11】:
                $obj_array['obj1'] = $obj1;
                $obj_array['obj2'] = $obj2;
                $obj_array['obj3'] = $obj3;
                unset($obj_array['obj3']);
                

                【讨论】:

                • -1 因为 OP 将对象赋予函数,而不是键,因此这个例子是不完整的。
                【解决方案12】:

                unset($myArray[$index]); 其中$index 是您要删除的元素的索引。如果您不想要更具体的答案,请显示一些代码或描述您正在尝试做的事情。

                【讨论】:

                • 这没问题,但是如何找到对象的索引?按数组中的值搜索?
                • @daniphp 你可以用 === 比较对象。
                猜你喜欢
                • 1970-01-01
                • 2020-08-14
                • 2014-08-24
                • 1970-01-01
                • 2018-07-22
                • 2012-05-12
                • 2019-06-18
                • 2017-04-13
                • 2016-11-26
                相关资源
                最近更新 更多