ooptypesfloating-pointdoublephp-7.4

PHP 7.4 Typed property with floats / doubles


I apologise in advance if this is a lame question, Its my first. I am building a small framework for a university project and I wanted to enforce types as much as possible, Great to see now that PHP 7.4 has strict types for properties,

But it is not being properly enforced even with declare strict_types.

Also on a side note, I know people say in PHP there is no difference between doubles and floats, but with typed properties, PHP does not recognise double as a data type.

See the simple code test below:

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

Based on this very simple test I have a few points which I find strange:

  1. Why is PHP correctly enforcing the int type but not the float type? Why is it that when I check with is_float() it returns false but the function accepts an integer?

  2. Why is the integer type perfectly enforced but not the float?

  3. Even though PHP has a valid double data type, why does it assume double is an instance? double is definitely a primitive data type within PHP, as the is_double() function works perfectly, See exception thrown above.

  4. Basically what would be the best, cleanest work around to enforcing decimal numbers in PHP?


Solution

  • Why is PHP correctly enforcing the int type but not the float type? Why is it that when I check with is_float() it returns false but the function accepts an integer?

    Because float range can contain integers without losing any data. In other words, float is like a superset of integers, so you can't say I only want floats i don't want integers even in strongly typed languages and even if your code is in strict_types mode.

    Why is the integer type perfectly enforced but not the float?

    PHP type declaration comes with coercive mode as default mode, so it's possible to change the declared type and no TypeError will be thrown only if it's possible for PHP to coerce values of the wrong type into the expected ones.

    In your case you are passing 8(integer) to a method that expects a float, this is totally fine and PHP will not complain about it because coercing 8 to a float will not change anything/lose anything.

    So what does strict_types do then ?

    It will change the behavior of PHP from coercive to strict. That means PHP will not be tolerant when an involved operation could lead to data loss.

    By taking your example when we set declare(strict_types=1) the following line will be a problem

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

    Because we are trying to pass a float number to an int parameter which means a data loss (8.2 becomes 8 ) PHP will throw an exception

    Fatal error: Uncaught TypeError: Argument 1 passed to FloatTest::setInt() must be of the type int, float given


    Even though PHP has a valid double data type, why does it assume double is an instance? double is definitely a primitive data type within PHP, as the is_double() function works perfectly

    PHP has no double data type and is_double is just an alias of is_float()

    Basically what would be the best, cleanest work around to enforcing decimal numbers in PHP?

    What you did is the best and cleanest work :)