Skip to content

Negative indices on empty array don't affect next chosen index #11154

Closed

Description

@ColinHDev

Description

I was browsing through php's source code to look at how arrays work and noticed the following:

This code:

<?php
$a = array();
$a[-5] = "-5";
$a[] = "after -5";

behaves differently than this code:

<?php
$b = array(
  -5 => "-5"
);
$b[] = "after -5";

Resulted in this output:

array(2) {
  [-5]=>
  string(2) "-5"
  [0]=>
  string(8) "after -5"
}
array(2) {
  [-5]=>
  string(2) "-5"
  [-4]=>
  string(8) "after -5"
}

But I expected this output instead:

array(2) {
  [-5]=>
  string(2) "-5"
  [-4]=>
  string(8) "after -5"
}
array(2) {
  [-5]=>
  string(2) "-5"
  [-4]=>
  string(8) "after -5"
}

https://3v4l.org/MjbOm

I am not sure, if this is a bug or intended, so I wanted to create an issue regarding that.

The PR #3772 changed that appending to arrays would also work if the previous element has a negative index without defaulting to 0 in that case.
It did so by setting the default value for nNextFreeElement from 0 to ZEND_LONG_MIN, while also adding the following "guard clause" to the _zend_hash_index_add_or_update_i( ) function, which makes sure that the chosen index defaults to 0 if it's still at ZEND_LONG_MIN and the element should be put at the next index. https://github.com/php/php-src/blob/master/Zend/zend_hash.c#L1027-L1029.
But it did not change that for the _zend_empty_array constant: https://github.com/php/php-src/blob/master/Zend/zend_hash.c#L258. Because of that, the following if statement is always false for empty arrays since (any_negative_key >= 0) == false: https://github.com/php/php-src/blob/master/Zend/zend_hash.c#L1110-L1112.

My question is, is this intended? Because it looks like a bug to me, especially since that "guard clause" would ensure that running $a[] = "" on an empty array, would still use index 0.
But I am not familiar with the PHP internals, so I might have completely missed something. So if there is a reason for this behaviour or why _zend_empty_array's nNextFreeElement can't start at ZEND_LONG_MIN, I would be happy to know why!

PHP Version

PHP 8.2.3

Operating System

No response

Activity

  1. iluuu1994 commented on Apr 28, 2023

    @iluuu1994
    Member

    Thank you for your analysis! This does indeed sound like a bug, as it doesn't behave as described in https://wiki.php.net/rfc/negative_array_index. Your suggestion to adjust .nNextFreeElement = ZEND_LONG_MIN of _zend_empty_array sounds correct.

    Unfortunately, this behavior is long-standing and I'm afraid of BC breaks for currently supported PHP versions. Targetting master with a note in UPGRADING should be ok.

  2. ColinHDev commented on Apr 28, 2023

    @ColinHDev
    ContributorAuthor

    Alright, thank you very much!
    I will look into submitting a PR when I'm home.

  3. added a commit that references this issue on Jul 19, 2024
    e2f477c
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions