1

Can someone explain the output of this code?

Why is it "fb" instead of "100100"?

$items = array();
$items[] = "foo";
$items[] = "bar";

foreach($items as $item) {
    $item['points'] = 100;
}

foreach($items as $item) {
    echo $item['points']; //output: "fb"
}
3
  • Do you perhaps mean that the output is "foobar"? Commented Jul 23, 2015 at 2:15
  • @kittykittybangbang no, it is "fb"...weird, huh? Commented Jul 23, 2015 at 2:16
  • $item is a string,I just get Warning code.you can add print_r($items) follw the first foreach. Commented Jul 23, 2015 at 2:37

3 Answers 3

3

You loop though the $items array, which has two elements.

First: foo and second: bar. E.g.

Array (
  [0] => foo
  [1] => bar
)

Now you access them like this:

echo $item['points'];

PHP will convert points which is a string into an integer, as you can see from the manual warning:

Warning: [...] Non-integer types are converted to integer. [...]

Which in your case will be 0.

And so you access the two values (strings) as array:

string: f o o
index:  0 1 2  //$index["points"] -> $index[0]

string: b a r
index:  0 1 2  //$index["points"] -> $index[0]

So you print the first character of both strings (e.g. foo and bar), which are:

fb

EDIT:

Also worth to note here is, that PHP only silently converts it with PHP <5.4 from newer version you will get a warning, as from the manual:

As of PHP 5.4 string offsets have to either be integers or integer-like strings, otherwise a warning will be thrown. Previously an offset like "foo" was silently cast to 0.

Which in your case with PHP >=5.4 you would get:

Warning: Illegal string offset 'points' ...

Sign up to request clarification or add additional context in comments.

5 Comments

@Darren It's 04:27 AM in the morning, so I guess 1 typo is allowed :) (Thanks for the fix)
Haha I just had to ;-) 3 coffees in here !
It makes sense, I'm not sure why I didn't realise it. Foo and Bar are just string values, not arrays themselves, so trying to call $item['points'] wouldn't work. Odd why PHP would just convert points to an integer though, and not throw an exception.
@cid You're welcome. It can be really confusing if you don't know that you can access a string as an 0-based index array in PHP.
@cid updated my answer. It's also worth to note, that it only converts it silently with PHP < 5.4, in newer version you will get a warning.
1

I found this question intriguing.

I had my own walk-through and here is the result.

$items is defined as follows.

$items = [
  0 => "foo",
  1 => "bar"
];

Then, goes into the foreach loop.

foreach($items as $item) {
    $item['points'] = 100;
}

At the beginning, $item contains a string "foo". The [] syntax is dominantly used for associative arrays, so it tricks us that $item might be an array, which is not the case. A less well-known usage of the [] is to get/set a single character in a string via [int] or {int} expression, as @Rizier123 has noted in his answer. For example, a "string"[0] gives "s". So, the following code

$item['points'] = 100;

is virtually similar to

"foo"['points'] = 100;

Now, a non-integer value given as a character position of a string, raises a PHP warning, and the position (here 'points') will be force-converted to an integer.

// Converting a string to integer:
echo intval('points'); // gives 0

As a result, the "foo"['points']" statement becomes "foo"[0], so

"foo"[0] = 100;

Now, the assignment part. The [] syntax operates on a single character. The numeric 100 is first converted to a string "100" and then only the first character is taken out for the assignment operation(=). The expression is now similar to

"foo"[0] = "1"; // result: "1oo"

To make things a bit twisted, the modified value of $item( which is "1oo") is not preserved. It's because the $item is not a reference. See https://stackoverflow.com/a/9920684/760211 for more information.

So, all the previous operations are negligible in terms of the end result. The $items are intact in the original state.

Now, in the last loop, we can see that the $item['point'] statement tries to read a character out of a string, in an erroneous way.

foreach($items as $item) {
    echo $item['points']; //output: "fb"
}

echo "foo"[0]; // "f"
echo "boo"[0]; // "b"

Comments

0

You're not actually modifying the array by doing $items as $item. $item is its own variable, so it would make sense that you get the correct output when printing within that loop.

1 Comment

Sorry, I edited my comment. It will print out "11" as the output. Also, do you mean that $item is a temporary variable accessible only within the loop? Then why can I do this with a while loop?

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.