Как заставить по-разному индексированные массивы PHP указывать на одни и те же объекты - PullRequest
0 голосов
/ 04 января 2011

Внутри класса у меня есть три массива (в качестве переменных экземпляра), которые все должны указывать на одни и те же объекты. Первый - это численно проиндексированный массив, который я получаю от какой-то внешней функции. Второй массив должен индексировать те же объекты по их имени. Третий по другому свойству. Это для быстрого доступа через эти свойства. Итак, суть в том, что не имеет значения, какой массив я использую для доступа к объекту и его изменения.

Но этого не может быть. Я знаю о ссылках на PHP. Я знаю о ссылках на Java. Я знаю о указателях Си, но не могу этого сделать - куда бы я ни пытался поместить амперсанд (= &).

class xxx {

  private $objs;
  private $objsByName;

  public function __construct() {

    $this->objs = getObjs();
    $this->objsByName = array();
    foreach($this->objs as $obj) {
      $this->objsByName[$obj->getName()] = $obj;
    }
  }

}

Здесь нет места, где бы я не пытался заменить = на = &

Я что-то упустил?

Ответы [ 5 ]

0 голосов
/ 04 января 2011

В PHP5 вы можете добавить & к переменной as, чтобы цикл foreach не клонировал объект:

foreach($this->objs as &$obj) {
   $this->objsByName[$obj->getName()] = &$obj;
}

Ссылка: http://php.net/manual/en/control-structures.foreach.php

p / sЯ не уверен, нужен ли & внутри тела foreach или нет, но просто добавьте его, чтобы быть безопасным.Или вы можете попробовать удалить его, чтобы узнать, нужно оно или нет.

0 голосов
/ 04 января 2011

PHP всегда использует функции копирования при записи, есть вероятность, что ваши объекты будут одинаковыми до тех пор, пока один из них не будет изменен.

Чтобы избежать ошибок, вы должны сказать, что один из ваших массивов содержит данные, а остальные - просто индексы.

Используйте индекс, чтобы найти идентификатор, и используйте массив данных, индексированный по идентификатору, для чтения и изменения данных.

0 голосов
/ 04 января 2011

В PHP объекты всегда передаются по ссылке ( вы не можете скопировать объект, если не используете clone ключевое слово ).Этот код иллюстрирует это:

<?php

class AnObject{
    private $name;
    public $count=0;

    public function __construct($name){
        $this->name = $name;
    }

    public function getName(){
        return $this->name;
    }
}

function getObjs(){
    return array(
        new AnObject('One'),
        new AnObject('Two'),
        new AnObject('Three'),
    );
}


class xxx {

  private $objs;
  private $objsByName;

  public function __construct() {

    $this->objs = getObjs();
    $this->objsByName = array();
    foreach($this->objs as $obj) {
      $this->objsByName[$obj->getName()] = $obj;
    }
  }

  public function alterAnObjectByName($name){
      $this->objsByName[$name]->count++;
  }

}

$x = new xxx;
var_dump($x);
$x->alterAnObjectByName('Two');
var_dump($x);

Возможно, проблема в другом месте.

0 голосов
/ 04 января 2011

Отметьте эту часть в руководстве по php: http://php.net/manual/en/control-structures.foreach.php

Если на массив не есть ссылки, foreach работает с копией указанного массива, а не с самим массивом.У foreach есть некоторые побочные эффекты на указатель массива.Не полагайтесь на указатель массива во время или после foreach, не сбрасывая его.

Таким образом, ваш $ obj является копией.

Я не проверял код Хуссейна,но это выглядит как хороший вариант:)

0 голосов
/ 04 января 2011

Замените ваш цикл foreach на этот.

for($i = 0 , $n = count($this->objs); $i < $n ; $i ++){

$this->objsByName[$this->objs[$i]->getName()] = &$this->objs[$i];

}

Это решит вашу проблему:)

Спасибо!

Хуссейн.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...