PHP Type Hinting

PHP Type Hinting

PHP type hinting is something I’m a huge fan of and think everyone should use. It removes a lot of the guess work from your PHP; you know that your method will only accept certain types. Being able to know this in advance will help reduce unexpected errors.

PHP’s Basic Types

Scalar Types

A scalar type holds a single value.

  • bool
  • int
  • float
  • string

Compound Types

A compound type may contain multiple values. Below are the compound types that PHP supports.

  • array
  • callable
  • class/interface name

Example of Scalar/Compound Types

Below is an example of type hinting your methods; I’ve added comments to help explain.


<?php
class Book {
    public function read(int $numberOfPages)
    {
        // You don't want someone passing 'dog' as a parameter
        // 'You're going to read dog pages' doesn't make sense.
        echo "You're going to read " . $numberOfPages . " pages";
    }

    public function flipPages(array $pages)
    {
        // When you know you're getting an array, it helps!
        foreach($pages as $page)
        {
            echo $page;
        }
    }
}

Type hinting keeps you from having to use functions like is_int to ensure your method is receiving the correct type.

PHP Object Oriented Types

When you’re learning to write object oriented PHP, it can be a bit difficult to grasp the concept and understand the benefits. I encourage you to write/use classes whenever you can, instead of using procedural code. If you keep practicing, you’ll get better, and eventually become a more efficient developer. Below is an example of using a concrete class as a type hint.

Type Hint with Concrete Class


<?php
interface GymEquipment {
    public function get();
}

class Weight implements GymEquipment {
    protected $lbs;

    public function __construct(int $lbs)
    {
        $this->lbs = $lbs;
    }

    public function get()
    {
        echo "I'm getting " . $this->lbs . "lbs of weights";
    }
}

class RowingMachine implements GymEquipment {
    protected $difficulty;

    public function __construct(string $difficulty)
    {
        $this->difficulty = $difficulty;
    }

    public function get()
    {
        echo "I'm going to row so " . $this->difficulty;
    }
}

class Exercise {
    public function lift(Weight $weight)
    {
        $weight->get();
    }

    public function row(RowingMachine $rowingMachine)
    {
        $rowingMachine->get();
    }
}

$exercise = new Exercise;

$weight = new Weight(45);
$exercise->lift($weight); // OUTPUT: I'm getting 45lbs of weights

$rowingMachine = new RowingMachine('hard');
$exercise->row($rowingMachine); // OUTPUT: I'm going to row so hard

Our Weight class expects an integer since lbs is a standard measurement. The RowingMachine class expects a string since I have no idea what kind of settings one may have.

The Exercise class has two methods, lift() and row(). Unless you’re really strong, I don’t think you want to lift the rowing machine, so lift() only accepts the type Weight. If lift() accepted the interface GymEquipment then it could accept a RowingMachine as an argument. The row() method of the Exercise class only accepts a type of RowingMachine.

Type Hint with Interface

Let’s see how we would type hint using an interface. We will need to refactor our code a little bit, and it will usually benefit us by doing this.


<?php
interface GymEquipment {
    public function start();
    public function stop();
}

class Weight implements GymEquipment {
    protected $weight;
    public function __construct(int $weight)
    {
        $this->weight = $weight;
    }
    public function start()
    {
        echo "I'm getting " . $this->weight . "lbs of weights";
    }
    public function stop()
    {
        echo "I'm done lifting weights.";
    }
}

class RowingMachine implements GymEquipment {
    protected $difficulty;
    public function __construct(string $difficulty)
    {
        $this->difficulty = $difficulty;
    }
    public function start()
    {
        echo "I'm going to row so " . $this->difficulty;
    }
    public function stop()
    {
        echo "I'm done rowing.";
    }
}

class Exercise {
    public function begin(GymEquipment $gymEquipment)
    {
        $gymEquipment->start();
    }
    public function end(GymEquipment $gymEquipment)
    {
        $gymEquipment->stop();
    }
}

$exercise = new Exercise;

$weight = new Weight(45);
$exercise->begin($weight); // OUTPUT: I'm getting 45lbs of weights
$exercise->end($weight); // OUTPUT: I'm done lifting weights.

$rowingMachine = new RowingMachine('hard');
$exercise->begin($rowingMachine); // OUTPUT: I'm going to row so hard
$exercise->end($rowingMachine); // OUTPUT: I'm done rowing.

By using an interface as a type hint, we can pass multiple concrete classes as a parameter, as long as the class implements the interface. By doing this, you aren’t restricting yourself.

Conclusion

If you would like to practice object-oriented PHP on your own, try writing the Exercise example that also accepts a name. Then, when it echo’s out the action, have it include a name from the Exercise construct. If you want to write something else, then do that, do what interests you. Put your code on GitHub and email it to me; also email me if you have any questions.