Using data structures for types

Data types should be very specific. Anyone using a variable should know exactly what type it is, how it looks like (if it’s a structure). While for some languages it’s common sense and really enforced, others will let you mess with a variable’s type, no matter it’s a primitive, an object, an array.

I’m going to talk about data coming from JSON, databases or other sources, which can be represented into data structures.

In a language like Go, you map data into well defined structures.

package main

import (
    "encoding/json"
    "fmt"
)

type Person struct {
    ID int
    Age int
    Name string
}

func main() {
    string := `{
        "id":453,
        "age":26,
        "name":"John Doe"
    }`

    input := []byte(string)

    person := Person{}
    err := json.Unmarshal(input, &person)
    if err != nil {
        panic(err)
    }

    fmt.Println(person) // Person struct
    fmt.Println(person.ID) // integer
    fmt.Println(person.Age) // integer
    fmt.Println(person.Name) // string
}

You know exactly that you have an object of type Person, with integer ID, integer Age, and string Name. No need to check anything anywhere. If you mess up, you’ll know at compile time.

A dynamic typed language like PHP has a different approach.

$string = '{  
	"id":453,
	"age":26,
	"name":"John Doe"
}';
	
$person = json_decode($string);

print_r($person); echo "\n";
echo $person->id . "\n";
echo $person->age . "\n";
echo $person->name . "\n";

You’ll get a generic object, with some properties not defined anywhere, you just assume you have them. A developer using your API won’t know what the object his working with looks like. It’s just an obscure object.

But you can handle this even in PHP, and you really should. You should avoid as much as possible using generic objects, and arrays for variables that represent an entity, a structure. You can do this by having a type (a data structure class).

<?php

class Person 
{
   /**
    * @var int
    */
    private $id;

    /**
     * @var int
     */
    private $age;

    /**
     * @var string
     */
    private $name;
    
    /**
     * @return int
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * @param int $id
     */
    public function setId($id)
    {
        $this->id = $id;
    }

    /**
     * @return int
     */
    public function getAge()
    {
        return $this->age;
    }

    /**
     * @param int $age
     */
    public function setAge($age)
    {
        $this->age = $age;
    }

    /**
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * @param string $name
     */
    public function setName($name)
    {
        $this->name = $name;
    }
}

$string = '{"id":453, "age":26, "name":"John Doe"}';
$response = json_decode($string);
$person = new Person();
$person->setId($response->id);
$person->setName($response->name);
echo $person->getId(). "\n";

// You can also declare the argument type in a function, so you know exactly what type you're working with
function display(Person $person) {
    print_r($person->getName());
}
display($person);

Wait… I still used the generic object and just passed its assumed values into another object. Indeed, it’s out of scope how you get the data into the object.

The purpose of this type short presentation is to encourage you to return well defined objects from your functions, and use well defined types for functions arguments, so that anyone who interacts with your API knows what they’re dealing with.

The “overhead” is worth every extra bit used, things are transparent, type hinting saves a lot of validation, developers will be happy to know exactly the type they’re using.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.