On Fri, Aug 31, 2012 at 10:24 PM, Sherif Ramadan <[email protected]>wrote:
> >
> > That might actually be something I could use :) But the fun for me
> begins here:
> >
> > $numbers = array();
> > $numbers[-1] = 5;
> > $numbers[] = 6;
> >
> > What would have happened to the keys? Normally [] is equivalent to
> [count($numbers)].
> >
>
> This is incorrect, $numbers[] = 6; is not equivalent to
> $numbers[count($numbers)] = 6; at all, because PHP uses an internal
> value for this that is represented an unsigned long in the Hashtable
> ht struct.
>
> As it stands today, that code would result in the following:
>
> $numbers = array();
> $numbers[-1] = 5;
> $numbers[] = 6;
> var_dump($numbers);
> /*
> array(2) {
> [-1]=>
> int(5)
> [0]=>
> int(6)
> }
> */
>
> Which looks awkward, I know, but the reason is that the internal value
> that represents the next key to be used when no key is supplied during
> an array push is an unsigned figure while integer values in PHP are
> all signed. Since one's complement is used this means the unsigned
> value will always wrap-around causing -1 to take us back to zero (you
> can't overflow an unsigned long).
>
> Here's how we can see this quirk rearing it's ugly head:
>
> $numbers = array();
> $numbers[PHP_INT_MAX] = 'foo';
> $numbers[] = 'bar';
> var_dump($numbers);
> /*
> Warning: Cannot add element to the array as the next element is
> already occupied in ... on line 1
> array(1) {
> [9223372036854775807]=>
> string(3) "foo"
> }
> */
>
> As you can see PHP has a bit of a hickup here. The implementation is
> such that the index is always initialized to 0 by default and clamped
> by the API (so when a negative value is supplied we still start back
> at 0).
>
> Here's the actual implementation of array_psuh:
>
> for (i = 0; i < argc; i++) {
> new_var = *args[i];
> Z_ADDREF_P(new_var);
>
> if (zend_hash_next_index_insert(Z_ARRVAL_P(stack), &new_var,
> sizeof(zval *), NULL) == FAILURE) {
> Z_DELREF_P(new_var);
> php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot add
> element to the array as the next element is already occupied");
> efree(args);
> RETURN_FALSE;
> }
> }
>
>
>
> $array = array();
> $array[PHP_INT_MAX+1] = 'foo';
> $array[] = 'bar';
> var_dump($array);
> /*
> array(2) {
> [-9223372036854775808]=>
> string(3) "foo"
> [0]=>
> string(3) "bar"
> }
> */
>
> Another gotchya, of the API is that the representation of the key used
> in the array and the next available key can be somewhat two
> misleading.
>
> ---
>
> On a final note the confusion behind proposing the use of negative
> indexes for array lookup in PHP is that PHP doesn't really have an
> array. Something I believe has been discussed at length in the past.
> Which is why it makes sense to separate the "key" used in the array
> from the "offset" of the element in the ordered map.
>
> $array = array(-1 => "foo",0 => "bar",3 => "baz")
> array_slice($array, -1); // makes perfect sense to me that this would
> return "baz"
>
> $array = array(-1 => "foo",0 => "bar",3 => "baz")
> echo $array[-1]; // makes perfect sense to me that this would return "foo"
>
> --
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: http://www.php.net/unsub.php
>
>
This discussion kinda reminds me of some of the debates over AUTO_INCREMENT
behavior in the MySQL community. Specifically, they end up having to
tackle the same funcamental, conceptual dilemma: If I
assign/insert/whatever an arbitrary value to a container that can be
incremented, and then I direct said container to generate the next
increment, what value should that be? What's the most sensible (or perhaps
the least unsensible) way to determine that?
Of course, I don't really know what the answer is. From a strictly logical
standpoint (ignoring the fact that it just doesn't work this way in PHP),
my thinking would be that the count-based index approach makes the most
sense. I think many (if not most) PHP developers incorrectly assume this
to already be the case now.
What's my point? I'm not sure that I have one-- but if I did, the point
would be that any approach to handling this will likely be problematic in
some way or another. That said, I think we should find a way to support
negative indexes. There were times when being able to do that would have
been very convenient for me. =)
--Kris