Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:62618 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 95167 invoked from network); 1 Sep 2012 05:24:15 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 1 Sep 2012 05:24:15 -0000 Authentication-Results: pb1.pair.com header.from=theanomaly.is@gmail.com; sender-id=pass Authentication-Results: pb1.pair.com smtp.mail=theanomaly.is@gmail.com; spf=pass; 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: theanomaly.is@gmail.com X-Host-Fingerprint: 209.85.215.42 mail-lpp01m010-f42.google.com Received: from [209.85.215.42] ([209.85.215.42:47937] helo=mail-lpp01m010-f42.google.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id 4B/51-12451-EFB91405 for ; Sat, 01 Sep 2012 01:24:15 -0400 Received: by lahl5 with SMTP id l5so2728321lah.29 for ; Fri, 31 Aug 2012 22:24:11 -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=tPST39/mobcduMfbwcFFw3kPbjoojRdRS0FCiIUcqP8=; b=QbXV6o2oQjt+fZwQ1WPtkA3bipbCMAw1cw5Xhu2QSdSgjgg+N0rJY6rWqTwGL1ZFHX 7j8gNxNfbOWvoyVbuy2NCFEqPcsy8Vt5TIO/x9G2+ssGcsNPAXUbjZhX6R+K7bp2fJfQ uVJix+R0W9vN6FQZAijEUtQYiV6A1/3Xgc5/Qp3cyT4SqNlf4q2BGwDaVMmqwcmkgAkC rGlLpcqf0/PFMzcOQ4PN7mH17vJ+POivgu1tTydmzpb1lSnUFQmgfiAlJOEckr3EVnAO B4vNaPKuLQ+gjYLxCONPE/10LatuMBIQSapQQBan8vjl+3TLsT3C2yhxG5n6FJ3q1HkL Zz4Q== MIME-Version: 1.0 Received: by 10.112.88.2 with SMTP id bc2mr1495188lbb.61.1346477050938; Fri, 31 Aug 2012 22:24:10 -0700 (PDT) Received: by 10.112.8.7 with HTTP; Fri, 31 Aug 2012 22:24:10 -0700 (PDT) In-Reply-To: References: Date: Sat, 1 Sep 2012 01:24:10 -0400 Message-ID: To: Tjerk Meesters Cc: Rasmus Schultz , Ferenc Kovacs , "internals@lists.php.net" Content-Type: text/plain; charset=ISO-8859-1 Subject: Re: [PHP-DEV] Support negative indexes for arrays and strings From: theanomaly.is@gmail.com (Sherif Ramadan) > > 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"