Почему PHP strlen() возвращает отрицательную длину?

strlen($str) возвращает отрицательные значения для "огромной строки", которая создается с помощью str_repeat:

<?php

error_reporting(E_STRICT|E_ALL);
echo phpversion(); // 5.3.26
echo PHP_INT_MAX; // 9223372036854775807
ini_set('memory_limit', '-1');
ini_set('max_execution_time', 0);

$gb = 1024 * 1024 * 1024;
$str = str_repeat('a', 2 * $gb);
echo strlen($str); // gives int(-2147483648)
echo $str[0]; // Notice: Uninitialized string offset: 0

$str2 = str_repeat('a', 4 * $gb);
echo strlen($str2); // gives int(0)

$str3 = str_repeat('a', 123 + 4 * $gb);
echo strlen($str3); // gives int(123)

$str4 = str_repeat('a', 6 * $gb); // starts to wrap again...
echo strlen($str4); // gives int(-2147483648)
echo $str4[0]; // Notice: Uninitialized string offset: 0

$str5 = str_repeat('a', 123 + 8 * $gb);
echo strlen($str5); // gives int(123)

?>

Определено ли это поведение?

Или это ошибка PHP?

Ответ 1

string может достигать 2 ГБ.

Похоже, что это на самом деле (2GB - 1). Это отлично работает на моем поле x64:

$str = str_repeat('a', 2 * 1024 * 1024 * 1024 -1);
echo $str[0];

... пока это прерывается:

$str = str_repeat('a', 2 * 1024 * 1024 * 1024);
echo $str[0];

То, что вы делаете, просто undefined, и руководство должно быть исправлено. Я бы тоже ожидал предупреждения.

Интересно, что это приводит к фатальной ошибке:

$str = str_repeat('a', 2 * 1024 * 1024 * 1024 -2); // 2GB - 2 bytes
$str .= 'b'; // ok
$str .= 'c'; // PHP Fatal error:  String size overflow


Update:

В отчете сообщается об ошибке. Документация на php.net исправлена ​​и теперь пишет "максимум 2147483647 байт".

Ответ 2

Я предполагаю, что вы просто переполняете int своей большой строкой. Из руководства:

Размер целого числа зависит от платформы, хотя максимальное значение около двух миллиардов - это обычное значение (это 32 бита). PHP не поддерживает целые числа без знака. Integer размер может быть определен с использованием константы PHP_INT_SIZE и максимального значения с использованием константы PHP_INT_MAX с PHP 4.4.0 и PHP 5.0.5.

Итак, это должно быть ОК, если ваш размер строки может поместиться в int.