Почему я получаю другое отрицательное значение из массива, чем я установил?

У меня есть массив тестов для функции:

        $testArray = array(
(object)array(
"value"     => 12345678901,
"expected"  => "123456789012"),
(object)array(
"value"     => "1234567890",
"expected"  => false
),
(object)array(
"value"     => (int)12345678901,
"expected"  => "123456789012"),
(object)array(
"value"     => 1234567890,
"expected"  => false
),
(object)array(
"value"     => "12345678901",

"expected"  => "123456789012"),
(object)array(
"value"     => "123456789012",
"expected"  => "123456789012"),
(object)array(
"value"     => "123456789013",
"expected"  => false
),
(object)array(
"value"     => "1234567890128",
"expected"  => "1234567890128"),
(object)array(
"value"     => "1234567890127",
"expected"  => false
),
(object)array(
"value"     => array(),
"expected"  => false
),
(object)array(
"value"     => (object)array(),
"expected"  => false
),
(object)array(
"value"     => array("1234567890127"),
"expected"  => false
),
(object)array(
"value"     => (object)array("1234567890127"),
"expected"  => false
)
);

Я запускаю массив через цикл foreach, чтобы увидеть, какие из них работают для проверки функции, и большинство из них работают. Третий должен вернуть 123456789012, но вместо этого он возвращает «-539222987», когда я получу значение. Почему это происходит, когда все остальное работает нормально?

Вот цикл foreach. Функция validUPC просто смотрит на upc и проверяет, является ли она действительной.

        foreach($testArray as $key => $test) { // Test each value
$result = App::make("Product")->validUPC($test->value);
var_dump($result);
echo "Result from array member $key was: $result\n";
if($result !== $test->expected) { // Check against expected value
echo "Test FAILED\n";
$success = false; // Returns false if any of them failed
}
else {
echo "Test passed\n";
}
}

Функция validUPC начинается так:

public function validUPC($upc = "non") {
try {
// If there is no upc specified, get the product upc
if($upc == "non") {
$upc = $this->upc;
}
// No arrays allowed
if(is_array($upc)) {
return false;
}
// Make it a string
$upc = (string)$upc;
var_dump($upc);

Который возвращает что-то вроде этого:

Product.php:99:float 12345678901
Product.php:101:string '12345678901' (length=11)
CatalogTest.php:70:string '123456789012' (length=12)
Result from array member 0 was: 123456789012 Test passed
Product.php:99:string '1234567890' (length=10)
Product.php:101:string '1234567890' (length=10)
CatalogTest.php:70:boolean false
Result from array member 1 was: Test passed
Product.php:99:int -539222987
Product.php:101:string '-539222987' (length=10)
CatalogTest.php:70:boolean false
Result from array member 2 was: Test FAILED

0

Решение

Не видя код в деталях, я буду размышлять.

На 32-битной платформе наибольшее представимое целое число равно 231-1 или 2147483647. Представленное вами целое число — 123456789012 — больше этого значения. Когда вы даете целое число больше максимального, PHP, как и другие языки, переполняет число значением, которое оно может представлять. В твоем случае это -539222987.

Я бы рекомендовал проверить, что ваш код не пытается работать с целыми числами больше PHP_INT_MAX на вашей платформе.


Ответ на комментарии: PHP конвертирует целые числа, большие, чем те, которые представлены доступными битами, в двойные. Но если вы тогда бросили тот удваиваясь до int, вы вводите то, что выглядит как обход. В 64-битной системе, например:

$a = pow(2, 65); // 65 === (PHP_INT_SIZE * 8) + 1
var_dump($a);
$b = (int)$a;
var_dump($b);
$c = $b - 100;
var_dump($c);

Математически мы ожидаем $ c === 36893488147419103132. Это не так. Выход:

float(3.6893488147419E+19)
int(0)
int(-100)

Плавающая точка — это приблизительно точное значение: мы поменяли точность в младших битах для возможности продолжать работать со значением как числом. Но затем, когда мы заставляем PHP рассматривать его как целое число, он сдается и усекает его до 0 — но поведение не определено, поэтому не полагайтесь на то, что оно всегда точно 0: весь ад вырвался на месте.

Хуже того, здесь нет ни предупреждения, ни уведомления. Так как же защитить свой код от этого сценария? Я призываю использовать strict_types, Когда вы ожидаете работать именно с intопределите свои функции, чтобы взять их. Если вы затем вычислите значение, которое превышает или понижает, вы получите число с плавающей запятой, которое перейдет в ваш строго int метод, который затем будут уведомить вас.

если ты необходимость работать с большими целыми числами, для этого есть библиотеки.

3

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector