Linesofcode
Linesofcode

Reputation: 5903

Laravel original variable affects temporary variable

I'm trying to keep the original data in a temporary variable called $copyItems, but whenever I change the value of the original variable $items it also changes in the copied variable.

Take the following example:

$items = \App\Models\Customers::with('Account')->get();
$copyItems = $items; // Should hold all the original $items values no matter the changes

// Prints "Stackoverflow"
echo $copyItems[0]->Account->name;

$items[0]->Account->name = 'John';

// Prints "John" and should print "Stackoverflow"
echo $copyItems[0]->Account->name;

How d'hell is this happening? I'm not using variable references &$items why is my temporary variable being changed?

With the clone $items approach the result is the same.

Upvotes: 1

Views: 948

Answers (3)

Sandro Vardiashvili
Sandro Vardiashvili

Reputation: 187

You could use Laravel Collections for $copyItems.

$copyItems = collect($items);

Upvotes: 0

lagbox
lagbox

Reputation: 50511

You are not copying an object when you assign it to another variable. $copyItems and $items are pointing to the same exact object.

Cloning won't help here, as clone will copy the Collection instance. Both of these collections would have items that actually point to the same exact objects, because clone is not cloning every object inside the collection, it is only cloning the Collection object itself.

Basically the variable isn't holding the object, it contains an identifier. This is why you hear/see people say that objects are always passed by reference, which is good enough for understanding but not completely true. The PHP manual goes into a little bit of an explanation about this.

"As of PHP 5, an object variable doesn't contain the object itself as value anymore. It only contains an object identifier which allows object accessors to find the actual object. When an object is sent by argument, returned or assigned to another variable, the different variables are not aliases: they hold a copy of the identifier, which points to the same object."

PHP.net Manual - OOP - Objects and References

Upvotes: 2

Justin Zhao
Justin Zhao

Reputation: 11

No, it should print stackoverflow. If you look at it from another perspective.

$items = \App\Models\Customers::with('Account')->get();
$copyItems = $items;

The above means:

$items = \App\Models\Customers::with('Account')->get();
$copyItems = \App\Models\Customers::with('Account')->get();

Then it runs:

echo $copyItems[0]->Account->name;

So it prints out stackoverflow. Then it runs:

$items[0]->Account->name = 'John';

The above command basically means:

$copyItems[0]->Account->name = 'John';

Which is why your next command outputs John:

echo $copyItems[0]->Account->name;

Upvotes: 0

Related Questions