HelloAnnyong•

This is amazing.

I think this might actually be the best one on this subreddit. All the others can be explained in some way by understanding the underlying mechanics of type coercion, etc., etc.

But this one is pure WTF.

25
OneWingedShark•

There's one other one that's completely inexplicable: the penultimate-item duplication bug. Consider:

// Columns, in one-based notation, to match w/ imported spreadsheet.
$columns = { 1, 3, 4, 5, 11 };

// Index Fix-up; as columens need to zero-based for PHP arrays.
foreach( $columns as $key => &$value )
    --$value;

// Columns now: { 0, 2, 3, 4, 10 };
    
// Actual processing.
foreach( $columns as $key => &$value )
{/* WHATEVER. */}

The second loop will repeat the second-to-last item twice, so if WHATEVER is Echo $value . "\n"; the output will be:
0
2
3
4
4

2
mahacctissoawsum•

I ran into this one before. Scratched my head for a long time before I figured out WTF was going on.

2
OneWingedShark•

Yep.
It's completely unintuitive, and certainly a bug, especially given the logical, linguistic, and intuitive meaning of "for each".

5
davvblack•

This is actually really easy to understand.

Think of foreach as doing &$key = key, &$value = value after each time in the first loop, at the very end, you have $value that is a by-reference to the last value you looked at, which is the last member of the loop.

Then, when you go over it again (The next loop I believe doesn't need to be &, it can just be foreach( $columns as $key => $value )), you are assigning this reference to each value in the loop, which is assigning the last member over and over again as well. As you look at the first item, you set the last item to match the first item, etc, until you get to the second to last, and last == second to last, then when you switch to the last one, that's what it's already set there.

2
OneWingedShark•

But it's wrong -- that's the point.

1
poizan42OP•

What is actually going on here ??!?!??!

http://codepad.org/FNeda0KY

20
jmcs•

What is actually going on here ??!?!??!

PHP

24
FishCustard•
array(1) {
  ["42"]=>
  string(3) "wat"
}

This should not exist. Look, it even says so in the documentation!

A key may be either an integer or a string. If a key is the standard representation of an integer, it will be interpreted as such (i.e. "8" will be interpreted as 8, while "08" will be interpreted as "08").

The string "42" should be cast to the integer 42 when the array is created. If you create an array the 'normal' way, that's exactly what happens.

For some insane reason casting a stdclass to an array allows numeric strings to get into the set of keys, thereby unleashing Zalgo, the Nezperdian Hivemind of Chaos via inconsistency.

When you do a lookup like $x["42"], PHP says 'ooh, that's a numeric string, I should cast it before doing the lookup', casts it and finds nothing. $keys[0] also contains "42" and the same PHP-logic is applied.

TL;DR

21
HelloAnnyong•

A key may be either an integer or a string. If a key is the standard representation of an integer, it will be interpreted as such (i.e. "8" will be interpreted as 8, while "08" will be interpreted as "08").

This is actually false! The documentation lies. Numeric keys that fit inside an integer (or is it float?) on the current architecture will be cast to integers. But longer strings will not, as I describe in a recent thread.

Not only that, but creating an array with integer literals behaves differently than creating one with string literals.

Take a look at this.

$number_key_array = array(
  12345 => "Foo",
  123451234512345 => "Bar",
  123451234512345123451234512345 => "Baz"
);
var_dump($number_key_array);

$string_key_array = array(
  "12345" => "Foo",
  "123451234512345" => "Bar",
  "123451234512345123451234512345" => "Baz"
);
var_dump($string_key_array);

Results in this output:

array(2) {
  [12345]=>
  string(3) "Foo"
  [-2147483648]=>
  string(3) "Baz"
}
array(3) {
  [12345]=>
  string(3) "Foo"
  ["123451234512345"]=>
  string(3) "Bar"
  ["123451234512345123451234512345"]=>
  string(3) "Baz"
}

Two big "what the fuck"s there:

First that using any large integer literal as a key casts the key to INT_MIN.

Second that explicitly specifying string keys casts only some of them to integers.

26
FishCustard•

What the actual fucking fuck.

All of these behaviours are questionable, but to have which one you'll get partially dependent on the system architecture is just plain moronic. Need I mention the fact that PHP seems to think that having integer keys overflow and thereby wrap around is absolutely fine and not worthy of a message saying "Hey, meatbag, this value is over INT_MAX!".

16
nahguri•

What? No bigint promotion? And no errors when this happens?

Just.. what.

3

Arrays can't have string representations of integers as keys and objects can't have integers as property names unless they are string representations.

5
shillbert•

Arrays can't have string representations of integers as keys

True, but they can have string representations of numbers that are too large to be ints on the current platform. So if you want string representations of integers as your array keys, just make sure to add a couple dozen zeros to the end.

2
HelloAnnyong•

Arrays can't have string representations of integers as keys

As I mentioned in a post above, that is only usually true. :)

2
poizan42OP•

It also breaks the other way when casting to object... http://codepad.org/qLk9bQqp

4
FishCustard•

Lots of things break when you're dealing with numeric object properties.

As this StackOverflow user commented, this is one of PHP's 'dark alleys'.

Personally I think this:

If a key is the standard representation of an integer, it will be interpreted as such

is TRWTF. Why the fuck would you do this?! You end up with the worst of the strict and loose typing worlds.

3
klti•

This behavior makes for really entertaining bugs when combined with array functions that reindex integer keys, but keep string keys.

3

It looks like when you cast the object to an array it just copies the public property names directly into an array, even though arrays can't have string representations of integers.

That becomes a problem because objects don't have integers as property names. Even if you set a property name to an integer, it'll end up being a string.

One can't have string representations of integers, one can't have integers unless they are string representations.

You can use get_object_vars instead of casting array to avoid this strange issue.

5
suspiciously_calm•

Now this is exactly the kind of assert I would put in a unit test for an array/map library.

17
OneWingedShark•

The thing I take away from this is: don't write your libraries in PHP!

3
TheGreatFohl•

Please tell me that this is a bug and not "intended by design"

7
steadweb•

"I have no idea what I'm doing."

Stupid inconsistency. http://codepad.org/phKfL4qj.

7