Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:62620 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 5094 invoked from network); 1 Sep 2012 08:17:33 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 1 Sep 2012 08:17:33 -0000 Authentication-Results: pb1.pair.com smtp.mail=kris.craig@gmail.com; spf=pass; sender-id=pass Authentication-Results: pb1.pair.com header.from=kris.craig@gmail.com; sender-id=pass Received-SPF: pass (pb1.pair.com: domain gmail.com designates 209.85.215.42 as permitted sender) X-PHP-List-Original-Sender: kris.craig@gmail.com X-Host-Fingerprint: 209.85.215.42 mail-lpp01m010-f42.google.com Received: from [209.85.215.42] ([209.85.215.42:65340] helo=mail-lpp01m010-f42.google.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id 69/10-03671-C94C1405 for ; Sat, 01 Sep 2012 04:17:33 -0400 Received: by lahl5 with SMTP id l5so2768850lah.29 for ; Sat, 01 Sep 2012 01:17:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :cc:content-type; bh=2NhPybZJkFXQETXsGCf85893SAfiJoJ4Y8WfIliQnU8=; b=lhEGZkjDzCLI905YsnyPbeGTF9so3XnahqANJixtcX4X1RF1MPwqeBjomYDnYEedxd ohyX6UGL/GNJRiV0x+cvSA7vj5vYr7Xj96gCqTY6+7nN1OUMIA+0YsgyuJp+KlUxX09W hU3VecZgt52vBmdzVnapu3k5AAWvtngiSOQtBaCXRrZlYlUeVqr8d4+VTJTBj0oZjmxQ uQYAztP6vEn9b7/Pxb9eMfbJ/XR17QmyZC5pANsOB9iMa3x/nJZrzqILeTa3FP/PTujQ IxQ6I/KxwT/viGS3BanhMvJSsPOVp7hazd07ythGMA3/2cPOOcXXhqCbjof4/5S6KIr1 4rwQ== MIME-Version: 1.0 Received: by 10.112.38.228 with SMTP id j4mr1578315lbk.111.1346487449164; Sat, 01 Sep 2012 01:17:29 -0700 (PDT) Received: by 10.152.41.33 with HTTP; Sat, 1 Sep 2012 01:17:29 -0700 (PDT) In-Reply-To: References: Date: Sat, 1 Sep 2012 01:17:29 -0700 Message-ID: To: Sherif Ramadan Cc: Tjerk Meesters , Rasmus Schultz , Ferenc Kovacs , "internals@lists.php.net" Content-Type: multipart/alternative; boundary=e0cb4efe2f121a1c7904c89f8a3d Subject: Re: [PHP-DEV] Support negative indexes for arrays and strings From: kris.craig@gmail.com (Kris Craig) --e0cb4efe2f121a1c7904c89f8a3d Content-Type: text/plain; charset=ISO-8859-1 On Fri, Aug 31, 2012 at 10:24 PM, Sherif Ramadan 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 --e0cb4efe2f121a1c7904c89f8a3d--