отношение доступа к переменной объекта изменяет переменную - PullRequest
2 голосов
/ 26 сентября 2019

Я сравнивал объекты и столкнулся с неожиданным поведением.
Следующий код не такой, как я с ним столкнулся, а самый простой способ объяснить / воспроизвести поведение / ошибку:

$obj1 = MyModel::find($id);
$obj2 = MyModel::find($id);
dd($obj1 == $obj2);

конечно, вернет true .
Однако, если я использую один из объектов для получения коллекции связанных объектов (с просто hasMany в модели), объект кажется измененным.

$users = $obj1->users;
dd($obj1 == $obj2);

теперь возвращает false .

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

Ответы [ 4 ]

3 голосов
/ 26 сентября 2019

Использование $obj1->users загружает коллекцию users в массив Model relationships.Этого достаточно, чтобы при свободном сравнении было возвращено false Сравнить dd($obj1, $obj2)

MyModel {
  ...
  #attributes: array:2[...],
  #original: array:2[...],
  #relations: array:2[...],
  ...
}

MyModel {
  ...
  #attributes: array:2[...],
  #original: array:2[...],
  #relations: array:0[...],
  ...
}

Так выглядит ваш первый пример.Теперь, если вы используете $users = $model2->users, это выглядит так:

MyModel {
  ...
  #attributes: array:2[...],
  #original: array:2[...],
  #relations: array:0[...],
  ...
}

MyModel {
  ...
  #attributes: array:2[...],
  #original: array:2[...],
  #relations: array:1[
    "users" => Collection { ... }
  ],
  ...
}

Если вы хотите, чтобы они были одинаковыми, вам нужно будет загрузить отношения следующим образом:

$obj1 = MyModel::with(["users"])->find($id);
$obj2 = MyModel::with(["users"])->find($id);
$users = $obj2->users; // With or without this line, the comparison returns `true`
dd($obj1 == $obj2); // true

В этот момент оба атрибута $obj1 и *1017* имеют одинаковый атрибут relations: array:1[].

1 голос
/ 26 сентября 2019

Ваш вопрос больше относится к PHP, чем к Laravel.Если вы посмотрите документацию Сравнение объектов , вы увидите, что:

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

Итак ... В вашем случае вы загрузили $obj1 и $obj2

$obj1 = MyModel::find($id);
$obj2 = MyModel::find($id);

Если мы будем следовать рекомендациям, при запуске dd PHP будет искать:

1.Экземпляр того же класса

Это true => MyModel::class == MyModel::class

2.Атрибуты : Это также верно, поскольку один и тот же класс равен одинаковым атрибутам.

3.Значения

Вы искали одну и ту же базу данных id, поэтому Laravel отобразил результат запроса в двух разных экземплярах ... но извлек те же значения.


Теперь, когдавы выполняете ленивую загрузку , Laravel вставит в массив relations новое значение.Таким образом, сравнение будет выполнено успешно для точек 1 и 2, но не получится в точке 3, так как

dd($obj1->relations)

/* RESULT
 * [...]
 * #relations: array:1[
 *  "users" => Collection { ... }
 * ],
 */

dd($obj2->relations)

/* RESULT
 * [...]
 * #relations: array:0[],
 */

Значения в этих атрибутах различны, и сравнение не выполнено.

0 голосов
/ 26 сентября 2019

Отношения не наследуются, если вы их не называете.Таким образом, когда вы вызываете пользователей в $ obj1, данные для пользователей наследуются, что делает его не таким, как $ obj2.

Тем не менее, требуется больше разъяснений, чем сделать это

dump($obj1);
dump($obj2);
die();

и отметьте в $ obj1 вы найдете данные о пользователях или массиве пользователей, тогда как в $ obj2 вы не найдете ничего такого, поскольку они все еще должны вызываться в нем.

0 голосов
/ 26 сентября 2019

Объекты не совпадают, потому что когда вы запускаете запрос как $ obj1-> users;$ obj1 изменен. Если вы используете dd () $ obj1, вы увидите, что у объекта есть новый атрибут, в этом случае вызовите пользователей, представляющих собой набор пользователей.

Теперь, если вы попытаетесь сравнитьэти два объекта, вы получите false, потому что они имеют разные атрибуты.

Теперь, если вы вызовете $ obj2-> users и снова сравните $ obj1 == $ obj2, вы получите true.

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