PHP 7.4 Типизированное свойство с поплавками/двойниками

Заранее извиняюсь, если это ламерский вопрос, это мой первый. Я создаю небольшой фреймворк для университетского проекта и хотел как можно больше применять типы. Приятно видеть, что теперь в PHP 7.4 есть строгие типы для свойств,

Но это не применяется должным образом даже при объявлении strict_types.

Кроме того, я знаю, что люди говорят, что в PHP нет разницы между значениями типа double и float, но с типизированными свойствами PHP не распознает тип данных типа double.

См. простой тест кода ниже:

class FloatTest
{
    private float $float;

    private int $int;

    function __construct()
    {

    }

    public function setFloat(float $float):void
    {
        $this->float = $float;
    }

    public function getFloat()
    {
        return $this->float;
    }

    public function setInt(int $int):void
    {
        $this->int = $int;
    }

    public function getInt():int
    {
        return $this->int;
    }
}


$ft = new FloatTest();

$ft->setFloat(8);//No error is thrown, converts to float but no decimals
$ft->getFloat();// Returns number 8 as float, but there is no enforcing of decimal point?
var_dump(is_float(8));//returns false

//Argument 1 passed to FloatTest::setInt() must be of the type int, float given
$ft->setInt(8.2);//Works as expected, great!


class DoubleTest
{

    private double $double;

    function __construct()
    {
        # code...
    }

    public function setDouble(double $double):void
    {
        $this->double = $double;
    }

    public function getDouble():double
    {
        return $this->double;
    }
}

$dt = new DoubleTest();

//Argument 1 passed to DoubleTest::setDouble() must be an instance of double, int given:
$dt->setDouble(8);
$double = $dt->getDouble();
var_dump(is_double(8)); returns false

Основываясь на этом очень простом тесте, у меня есть несколько моментов, которые я нахожу странными:

  1. Почему PHP правильно применяет тип int, а не тип float? Почему, когда я проверяю с помощью is_float(), он возвращает false, но функция принимает целое число?

  2. Почему целочисленный тип идеально соблюдается, а не плавающий?

  3. Несмотря на то, что PHP имеет допустимый тип данных double, почему он предполагает, что double является экземпляром? double определенно является примитивным типом данных в PHP, так как функция is_double() работает отлично, см. исключение выше.

  4. В принципе, что было бы лучшим и самым чистым решением для обеспечения десятичных чисел в PHP?


person ptmp_727    schedule 11.08.2020    source источник


Ответы (1)


Почему PHP правильно применяет тип int, а не тип float? Почему, когда я проверяю с помощью is_float(), он возвращает false, но функция принимает целое число?

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

Почему целочисленный тип идеально соблюдается, а не плавающий?

Объявление типа PHP поставляется с режимом coercive в качестве режима по умолчанию, поэтому можно изменить объявленный тип, и ошибка TypeError не будет выдана только в том случае, если PHP может преобразовать значения неправильного типа в ожидаемые.

В вашем случае вы передаете 8(integer) методу, который ожидает число с плавающей запятой, это совершенно нормально, и PHP не будет жаловаться на это, потому что принуждение 8 к числу с плавающей запятой ничего не изменит/ничего не потеряет.

Что тогда делает strict_types ?

Это изменит поведение PHP с принудительного на строгое. Это означает, что PHP не будет терпеть, когда задействованная операция может привести к потере данных.

Если взять ваш пример, когда мы установим declare(strict_types=1), следующая строка будет проблемой

$ft->setInt(8.2);//Works as expected, great!

Поскольку мы пытаемся передать число float параметру int, что означает потерю данных (8.2 становится 8), PHP выдаст исключение.

Неустранимая ошибка: Uncaught TypeError: Аргумент 1, переданный FloatTest::setInt(), должен иметь тип int, заданное число с плавающей запятой


Несмотря на то, что PHP имеет допустимый тип данных double, почему он предполагает, что double является экземпляром? double определенно является примитивным типом данных в PHP, так как функция is_double() работает отлично.

PHP не имеет типа данных double, а is_double — это просто псевдоним is_float().

В принципе, что было бы лучшим и самым чистым решением для обеспечения десятичных чисел в PHP?

То, что вы сделали, это лучшая и самая чистая работа :)

person Rain    schedule 11.08.2020
comment
Спасибо, это все прояснило, я думал, что может быть вариант использования, когда мы хотим применить десятичную дробь, но, конечно, теперь имеет смысл 8 равно 8,00000, спасибо - person ptmp_727; 12.08.2020