Negative String Offsets

Individual characters of a string can be accessed using the [] operator in combination with an integer offset that is zero-based:

$string = 'abcdef';

var_dump($string[0]);

Executing the code shown above will print the output shown below:

string(1) "a"

Prior to PHP 7.1, some string handling functions such as substr() supported negative string offsets and lengths while others such as strpos() did not. In an effort to improve the overall consistency of the language, PHP 7.1 expands the support of negative string offsets. Negative string offsets are counted from the right and -1, for instance, references the last character of a string (first character from the right).

On the syntax level, support for negative string offsets was added to the [] operator that allows access to the individual characters of a string. Here are some examples that show this:

$string = 'abcdef';

var_dump($string[-1]);

Executing the code shown above will print the output shown below:

string(1) "f"

In addition to read access to individual characters of a string, negative string offsets can also be used for manipulating strings on the character level:

$string = 'abcdef';

$string[-3] = '.';

var_dump($string);

The code shown above overwrites the third character from the right. Executing the example will print the following output:

string(6) "abc.ef"

String offsets can also be used with the isset() function to determine whether a string has a character at a specified position:

$string = 'abcdef';

var_dump(isset($string[-4]));

The code shown above checks whether the string has a character at the fourth position from the right. Executing the example will print the following output:

bool(true)

Furthermore, support for negative string offsets was added to the following functions:

strpos(), stripos(), substr_count(), grapheme_strpos(), grapheme_stripos(), grapheme_extract(), iconv_strpos(), file_get_contents(), mb_strimwidth(), mb_ereg_search_setpos(), mb_strpos(), and mb_stripos().

This expanded support of negative string offsets brings with it a backwards compatibility break. Prior to PHP 7.1, a negative string offset raised a warning and the offset was interpreted as zero. Now these negative string offsets are valid and interpreted accordingly.

If you have existing code that uses string offsets and if those string offsets can be negative then your code will behave differently in PHP 7.1 and later.

$string = 'abcdef';
$offset = -1;

var_dump($string[$offset]);

Executing the code shown above with PHP 5.6 or PHP 7.0 will generate the following output:

Notice: Uninitialized string offset: -1 in ...
string(0) ""

As we have seen earlier, executing the same code with PHP 7.1 will print string(1) "f".

You need to add a safeguard such as the one shown below to make existing code like this behave the same with PHP 7.1:

$string = 'abcdef';
$offset = -1;

if ((int) $offset < 0) {
    $offset = 0;
}

var_dump($string[$offset]);