Monday, 10 November 2014

Strictly Research

Fig 1. Strict Easter Egg
Recently this screen shot was posted on twitter, there was a thread on reddit, and there was much nattering.

While I value very highly the fact that PHP, at it's heart, is a dynamic language, why shouldn't we be able to use strict ?

If a programmer wants to use strict type hints, then it doesn't need to effect all those people not using strict type hints.

Strict parameter type hints in PHP7 ?

So, I decided to put some effort into writing an extension for PHP7 that will introduce the ability to perform strict type hinting without changing the engine.

The extension uses autoboxing and Zend magic to coerce hinted scalars to complex types, providing mechanics to cast back to scalar for Zend.

This means that the following code works exactly as you expect it too:
use strict\Integer;

function add(integer $one, integer $two) {
    return $one + $two;
}

var_dump(add(10, 20));

While this code:
use strict\Integer;

function add(integer $one, integer $two) {
    return $one + $two;
}

var_dump(add("10", "20"));

Will produce something like the following error:
Fatal error: Uncaught exception 'strict\TypeException' with 
   message 'illegal implicit cast to integer from string' in file:4
Stack trace:
#0 file(4): strict\Integer->__construct('10')
#1 file(8): add('10', '20')
#2 {main}
  thrown in file on line 4

Finally, the following code:
use strict\Integer;

function add(integer $one, integer $two) {
    return (double) $one + (double) $two;
}

var_dump(add(10, 20));

Will also fail, with something like the following error:
Fatal error: Uncaught exception 'strict\TypeException' with 
   message 'illegal cast to double from integer' in file:5
Stack trace:
#0 file(8): add(Object(strict\Integer), Object(strict\Integer))
#1 {main}
  thrown in file on line 5

We can see from the examples above that casting rules are strict in the true sense of the word, any cast to another type, implicit or explicit will fail.

Strict parameter type hinting in other languages allows you to document and write very precise and easy to understand API's.

We certainly shouldn't change the nature of PHP, but we should bring the benefits of strict types into PHP if we can, and it seems like we can.

Your very own boxes !

The extension comes with autoboxes for scalar types, however should the programmer want some particular functionality on the box, such as a fancy string API, the programmer can declare their own String class.

The following code demonstrates designing your own boxes:
use strict\Autobox;

class String extends Autobox {

    public function __construct($value) {
        $this->setValue(
            Autobox::string, $value);
    }
    
    public function reverse() {
        return new String(strrev($this->getValue()));
    }
}

function reverse(string $str) {
    return $str->reverse();
}

var_dump((string) reverse("7PHP"));

The output will be string(4) "PHP7"

API

The Autobox class has the following API:
class Autobox {
    final protected function setValue(integer $type, mixed $value);
    final public function getValue();
    final public function getType();
}

The method Autobox::setValue should only be called by constructors (although this rule is not enforced), and can only be called once.

Try it

It is time to be brave, and try it for yourself: http://github.com/krakjoe/strict

Disclaimer: I don't know if this research is going anywhere, was fun though :)