7

I'm trying to insert into an array at a certain point:

$hi = "test";
$var2 = "next";
$arr = array(&$hi);
$arr[] = &$var2; // this works
array_splice($arr, 1, 0, &$var2); // this doesn't

Why does trying to insert it into the array with splice fail and using the first method doesn't?

4 Answers 4

8

The quick-and-dirty answer, but please be aware that calling this function with a reference is deprecated and may (depending on your php configuration) generate a warning:

array_splice($arr, 1, 0, array(&$var2));

The hows-and-whys answer: What's happening is pretty subtle. When you do the splice, because you have inserted a reference into that position, $var2 is actually being reassigned. You can verify it with the following code:

<?php
  $hi = "test";
  $var2 = "next";
  $arr = array(&$hi);
  $arr[] = &$var2; // this works
  printf("=== var2 before splice:\n%s\n", var_export($var2, TRUE));
  array_splice($arr, 1, 0, &$var2); // this doesn't
  printf("=== var2 after splice:\n%s\n", var_export($var2, TRUE));
?>

You will get the following result:

=== var2 before splice:
'next'
=== var2 after splice:
array (
  0 => 'next',
)

Notice that before the splice, $var2 was a string, just as you expected it to be ('next'). After the splice, though, $var2 has been replaced with an array containing one element, the string 'next'.

I think what's causing it is what the documentation says: "If replacement is not an array, it will be typecast to one (i.e. (array) $parameter)." So what is happening is this:

  • You're passing &$var2 into array as replacement.
  • Internally, php is converting &$var2 into array(&$var2). It might actually be doing something that's equivalent to $param = array($param), which means that &$var2 would be set to array(&$var2), and since it's a reference and not a copy of $var2 like it normally would be, this is affecting the variable that would normally be out of scope of the call.
  • Now it moves this new value of $var2 to the end position and inserts a copy of $var2 in the second position.

I'm not sure exactly all of the wizardry of what's happening internally, but $var is definitely being reassigned during the splice. Notice that if you use a third variable, since it's not assigning something to something that already exists as a reference, it works as expected:

<?php
  $hi = "test";
  $var2 = "next";
  $var3 = "last";
  $arr = array(&$hi);
  $arr[] = &$var2; // this works
  array_splice($arr, 1, 0, &$var3);
  printf("=== arr is now\n%s\n", var_export($arr, TRUE));
?>

Generates the result:

=== arr is now
array (
  0 => 'test',
  1 => 'last',
  2 => 'next',
)
Sign up to request clarification or add additional context in comments.

10 Comments

P.S. I think that the reason that calling it with array(&$var2) works is because internally, splice isn't having to convert &$var2 to array(&$var2) likely through self-assignment, thus changing $var2 in the process. You're explicitly creating a new symbol array(&$var2) that is physically separate in memory with no self-assignment required.
P.P.S. This kind of unintended side effect is precisely why call-time pass-by-reference has been deprecated. ;)
@AndyLobel you should change the accepted answer to this one.
@Hamish this answer does explain the problem, but I dont think he actually mentions how to solve it lol (correct me if i'm wrong)
You didn't ask how to solve it, you asked, "Why does trying to insert it into the array with splice fail and using the first method doesn't?" The "rightest" answer is that you really shouldn't be doing this to start with; as mentioned elsewhere, call-time pass-by-reference has been deprecated. The way you phrased your question ("Why?" instead of "How do I?"), I assumed that you wanted to know what mechanism was causing the result you were seeing, which was the basis of my answer.
|
2

You might need to make the last argument an array, otherwise according to the manual you'll get typecasted to one.

array_splice( $arr, 1, 0, array( &$var2 ) ); 

2 Comments

Solution is correct, but for @Travesty3's reason. Typecasting isn't a problem - it's the call time pass by reference that fails.
from the manual: If replacement is just one element it is not necessary to put array() around it, unless the element is an array itself, an object or NULL.
2

When I try an example like yours, I get a warning that says "Call-time pass-by-reference has been deprecated." According to this answer:

You can set allow_call_time_pass_reference to true in your php.ini file. But it's a hack.

Comments

0

Here I am iterating an array($values_arr) and storing the references of each variable in another array ($params). You can alter the usage it as per your requirements.

$params = array();
$values_arr = array('a', 'b', 123);
foreach ($values_arr as $key=>&$val) {
    $params[$key] = &$val;
}

Result

array (size=3)
  0 => &string 'a' (length=1)
  1 => &string 'b' (length=1)
  2 => &int 123

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.