Firstly, let's create a standalone example that can be tested more easily:
class Example {
public $length, $height, $width, $weight;
public function __construct($length, $height, $width, $weight) {
$this->length = $length;
$this->height = $height;
$this->width = $width;
$this->weight = $weight;
}
public function get_price() {
return 1.23;
}
}
$sample_data = [
42 => ['quantity' => 2, 'data' => new Example(42, 42, 42, 42)],
69 => ['quantity' => 1, 'data' => new Example(69, 69, 69, 69)],
];
$i = 0;
$totalweight = 0;
$totalprice = 0;
foreach ( $sample_data as $item_id => $values ) {
$_product = $values['data'];
$q = 1;
while ( $values['quantity'] >= $q ) {
$products[ $i ]->length = $_product->length;
$products[ $i ]->height = $_product->height;
$products[ $i ]->width = $_product->width;
$products[ $i ]->weight = $_product->weight;
$totalweight += $_product->weight;
$totalprice += $_product->get_price();
$q++;
$i++;
}
}
var_dump($products);
Now we can see what this did on older versions of PHP, for instance using this handy tool which runs the same code on multiple versions.
The output in PHP 7.4 is this:
Warning: Creating default object from empty value in /in/1Imu2 on line 31
Warning: Creating default object from empty value in /in/1Imu2 on line 31
Warning: Creating default object from empty value in /in/1Imu2 on line 31
array(3) {
[0]=>
object(stdClass)#3 (4) {
["length"]=>
int(42)
["height"]=>
int(42)
["width"]=>
int(42)
["weight"]=>
int(42)
}
[1]=>
object(stdClass)#4 (4) {
["length"]=>
int(42)
["height"]=>
int(42)
["width"]=>
int(42)
["weight"]=>
int(42)
}
[2]=>
object(stdClass)#5 (4) {
["length"]=>
int(69)
["height"]=>
int(69)
["width"]=>
int(69)
["weight"]=>
int(69)
}
}
So we can see that what's happening is that for each item, the code is implicitly creating a stdClass
object, before assigning properties on it. The fix is therefore to make that creation explicit by writing $products[ $i ] = new stdClass;
just before $products[ $i ]->length = $_product->length;
While we're at it, we should also create $products
as an empty array with $products = [];
before the foreach
loop.
Running our modified code in the same tool we can see that it now gives the same result on every PHP version from PHP 5.4 up to and including 8.1, with no Warnings.