Re: Support negative indexes for arrays and strings

From: Date: Sat, 01 Sep 2012 08:17:29 +0000
Subject: Re: Support negative indexes for arrays and strings
References: 1 2 3 4 5  Groups: php.internals 
Request: Send a blank email to internals+get-62620@lists.php.net to get a copy of this message
On Fri, Aug 31, 2012 at 10:24 PM, Sherif Ramadan <theanomaly.is@gmail.com>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

« previous php.internals (#62620) next »