Strong typing in PHP (“wrapping”): To implement or not to implement?

by Michał Giergielewicz on 13th September 2012

Post image for Strong typing in PHP (“wrapping”): To implement or not to implement?

PHP is a language of weak typing, which means that the type of variables can be changing during runtime. Since the version 5.0, PHP has enabled the, so called, type hinting. Type hinting means method parameters marking to demand a certain type of data. This allows, to some extent, for data type control. Unfortunately, it works only for objects and arrays, so the possibility to determine either the integer or the string doesn’t exist. There are ways to avoid the problem of weak typing, and one of them is wrapping.

Wrapping is literally a process of “wrapping” data into some class hiding access to it behind the class’ interface. Now, because the access is limited to the interface we can implement a multitude of restrictions and validations gaining a decent level of strong typing. An example is a wrapper for array type, although you can easily use type hinting for the arrays, using this wrapper gives you an additional bonus of unifying the interface for the methods operating on arrays.

A simple example: 

<?php
class ArrayObject
{
    private $array = array();

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

    public function getArray()
    {
        return $this->array;
    }

    public function push($value)
    {
        array_push($this->array, $value);
    }

    public function merge(ArrayObject $array)
    {
        return new ArrayObject(array_merge($this->array, $array->getArray()));
    }
    
    public function count()
    {
        return count($this->array);
    }
}
?>

The example above defines ArrayObject class. The constructor receives one parameter that is assigned to the object’s property, ergo to the variable we are wrapping. Thanks to the wrapper for an array type we can use type hinting in the constructor’s parameter. From now on, all the operations are conducted with the help of the interface, which in this case consists of only 4 methods.

  • getArray()needed when there’s a requirement for extracting variable from the wrapper’s object, use it for instance in such PHP functions, as array_push or array_merge.
  • push($value) method adding next record to the array.
    merge(ArrayObject $array) receives an object ArrayObject as a parameter enabling type control. In this situation there is no
  • possibility of transferring variable of a different type to the method.
  • count() returns array’s length.

In case of the example presented, merge returns a new object of ArrayObject type, instead of assigning the result to the property. It’s not a must-do, but comes more from the willingness to increase control over the object and its state. Additionally, it’s a first step to introduce a new improvement – immutable type objects. 

These objects don’t allow for a change in property after it’s been initialized. The class here still allows for modification for the push is not yet properly secured.

public function __construct(array $array = array(), $immutable = false)
{
    $this->array = $array;
    $this->immutable = (bool)$immutable;
}
	
public function push($value)
{
    if ($this->immutable === true)
    {
        throw Exception("This object is immutable");
    }
    array_push($this->array, $value);
}

After making such adjustment, once initializing the object by setting the second parameter to true it becomes immutable. Of course, one can also change the implementation of push method, so that an object’s copy is created, and once the record is added, it’s returned as a result of a function. No need to throw an exception here!

However, what’s most convincing is that an object, in contrary to array() type, can be passed by reference. This lowers memory usage and enables an easier way to implement methods. Since an ArrayObject type object can be passed in method’s parameter via reference, the change of such object inside the method will also be visible beyond the method’s scope.

$array = new ArrayObject($nativePHPArray);
$array->count(); // 4
$this->AddSomeRowsIntoArray($array); //method adds two records
$array->count(); // 6

After completing this operation $array variable will have a changed value, thanks to the object being passed via reference.

Using wrappers for the array type of variables seems obvious – as soon as we implement a full PHP functions’ scope operating on arrays, not only will we gain the same functionality but also profit out of strong typing, references or any other functionalities we’ll decide to implement.

In case of strings or integers we may face a bit more problems, since not all functionalities can be implemented in the wrapping class.

<?
$i = 5;
$i++

$i = new IntegerObject(5);
$i++; // the operation will fail
?>

Other constructions, although possible from the implementation point of view, will be unusable or will decrease code clarity (if you happen to like mind puzzles, I strongly recommend writing a for loop using wrapper type integer).

Adding wrappers will always mean some costs. Some wrappers, like the one above of the ArrayObject type are relatively „cheap”. Nonetheless, the IntegerObject type may turn out to be too expensive.

I shall leave you with the question: To implement or not to implement? How about sharing your experience? Will you decide on implementing?