>
> 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

Reply via email to