1

I have an array, I need to copy the first item in the array and alter it.

This is what i'm doing:

echo $QuantityDiscounts[0]['price'] . '<br>';
echo $QuantityDiscounts[0]['from_quantity'] . '<br>';

$firstItem                  = $QuantityDiscounts[0];
$firstItem['from_quantity'] = 999;
$firstItem['price']         = 999;

echo $QuantityDiscounts[0]['price'] . '<br>';
echo $QuantityDiscounts[0]['from_quantity'] . '<br>';

This is the output this gives me:

4.870000
10
4.870000
999

When I change the value of the copied array it's changing the original array. What makes this even stranger is that it only happens for the 'from_quantity' item. As you can see the 'price' element remains unaltered.

I can't figure out why this is happening, as you can see i'm not using references. Is there an explanation for this behaviour that i'm missing?

Some more info:

If I first copy the 'from_quantity' in the original array so that it uses a different key this behaviour goes away.

$QuantityDiscounts[0]['test'] = $QuantityDiscounts[0]['from_quantity'];

echo $QuantityDiscounts[0]['price'] . '<br>';
echo $QuantityDiscounts[0]['from_quantity'] . '<br>';
echo $QuantityDiscounts[0]['test'] . '<br>';

$firstItem = $QuantityDiscounts[0];
$firstItem['from_quantity'] = 999;
$firstItem['test']          = 999;
$firstItem['price']         = 999;

echo $QuantityDiscounts[0]['price'] . '<br>';
echo $QuantityDiscounts[0]['from_quantity'] . '<br>';
echo $QuantityDiscounts[0]['test'] . '<br>';

Outputs:

4.870000
10
10
4.870000
999
10

** UPDATE ** - Thanks for your help so far

Here is the function that generates the array. I can see that a reference is being used there which must be causing the problems. Does this mean I can't copy and modify the 'from_quantity' without changing the original?

protected function formatQuantityDiscounts($specific_prices, $price, $tax_rate, $ecotax_amount)
{
    foreach ($specific_prices as $key => &$row)
    {
        $row['quantity'] = &$row['from_quantity'];
        if ($row['price'] >= 0) // The price may be directly set
        {
            $cur_price = (Product::$_taxCalculationMethod == PS_TAX_EXC ? $row['price'] : $row['price'] * (1 + $tax_rate / 100)) + (float)$ecotax_amount;
            if ($row['reduction_type'] == 'amount')
                $cur_price -= (Product::$_taxCalculationMethod == PS_TAX_INC ? $row['reduction'] : $row['reduction'] / (1 + $tax_rate / 100));
            else
                $cur_price *= 1 - $row['reduction'];
            $row['real_value'] = $price - $cur_price;
        }
        else
        {
            if ($row['reduction_type'] == 'amount')
                $row['real_value'] = Product::$_taxCalculationMethod == PS_TAX_INC ? $row['reduction'] : $row['reduction'] / (1 + $tax_rate / 100);
            else
                $row['real_value'] = $row['reduction'] * 100;
        }
        $row['nextQuantity'] = (isset($specific_prices[$key + 1]) ? (int)$specific_prices[$key + 1]['from_quantity'] : -1);
    }
    return $specific_prices;
}
jd182
  • 3,180
  • 6
  • 21
  • 30
  • 2
    I just made a phpfiddle and tried it and it's not referencing for me - http://phpfiddle.org/main/code/b8g-03e You must be doing something else. – Dan Goodspeed Nov 22 '13 at 11:54
  • 1
    which version of php ? please provide a full code we can copy/paste to test – Asenar Nov 22 '13 at 11:57
  • Possibly the OP is doing something like this: http://phpfiddle.org/main/code/naj-0gu – Kaii Nov 22 '13 at 12:00
  • OP is leaving out important details. The edit provided nothing substantial. –  Nov 22 '13 at 12:00
  • @remyabel what extra detail would you like? I haven't left anything out except the creation of the $QuantityDiscounts array. Is that relevant? – jd182 Nov 22 '13 at 12:02
  • @jd182 Yes, provide it. We can't reproduce your results. – user4035 Nov 22 '13 at 12:03
  • @Kaii Look at what OP say: "as you can see i'm not using references." Most probably it's a lie, and he is using a reference, causing this behaviour. – user4035 Nov 22 '13 at 12:05
  • 1
    @user4035 she definitely is, but doesn't know. the OP probably has the assumption that references must be explicit (i.e. `$firstItem =& $QuantityDiscounts[0];`), but this is not correct when copying arrays that already contain references. – Kaii Nov 22 '13 at 12:09
  • user4035 why would I come on here and lie? @Kaii *he, yes you're right. I've posted the code that creates the array and a reference is being used in there that I wasn't aware of – jd182 Nov 22 '13 at 12:14
  • is that code from some CMS? (it looks like prestashop ) – Asenar Nov 22 '13 at 12:18
  • @Asenar - yes that method is from PrestaShop. ProductController::formatQuantityDiscounts() – jd182 Nov 22 '13 at 12:22

2 Answers2

1

If $QuantityDiscounts[0]['from_quantity'] already IS a reference, you don't need to reference it again - it will stay a reference and the reference will be copied on assignment, instead of the actual value.

This code demonstrates what i mean:

$foo = 10;

$QuantityDiscounts[0]['price'] = 4.870000;
$QuantityDiscounts[0]['from_quantity'] =& $foo;
$firstItem                  = $QuantityDiscounts[0];
$firstItem['from_quantity'] = 999;
$firstItem['price']         = 999;

echo $QuantityDiscounts[0]['price'] . '<br>';
echo $QuantityDiscounts[0]['from_quantity'] . '<br>';

Outputs:

4.87
999    (instead of the initial value 10 !)

To get a real COPY of your array (and all its elements) you need to manually dereference the child elements. Unfortunately, PHP has no built-in method for that, yet.

See this QA on StackOverflow on how to dereference array elements while copying.

Community
  • 1
  • 1
Kaii
  • 20,122
  • 3
  • 38
  • 60
  • This is probably not related, but I recall having to use `AddRange` in C# because copying a list would have the original be modified. Perhaps there is a similar function in PHP. –  Nov 22 '13 at 12:15
  • Thank you, this is exactly my problem. I didn't realise the array already contained a reference and that the reference would remain even after copying the array. – jd182 Nov 22 '13 at 12:19
0

The most plausible cause of your problem is that your variable points to a object, and not to an array. Acessing objects as arrays is very simple through the ArrayAccess interface, and because it points to a object (and objects are always passed as references), the value changes. Clone the variable before making any changes.

The other probably reason is that you are explicit using references. In this case, you have to find where the problem lies and fix it by yourself, as we don't have access to your application.

Denis Lins
  • 816
  • 7
  • 22