nicklasos
1/29/2014 - 10:28 AM

PHP Type hinting

PHP Type hinting

<?php

define('TYPEHINT_PCRE', '/^Argument (\d)+ passed to (?:(\w+)::)?(\w+)\(\) must be an instance of (\w+), (\w+) given/');

class TypeHintException extends Exception {}

class TypeHint
{

    private static $Typehints = array(
        'boolean'   => 'is_bool',
        'integer'   => 'is_int',
        'float'     => 'is_float',
        'string'    => 'is_string',
        'resrouce'  => 'is_resource'
    );

    private function __construct() {}

    public static function initializeHandler()
    {
        set_error_handler('Typehint::handleTypehint');
        return true;
    }

    private static function getTypehintedArgument($ThBackTrace, $ThFunction, $ThArgIndex, &$ThArgValue)
    {
        foreach ($ThBackTrace as $ThTrace) {
            // Match the function; Note we could do more defensive error checking.
            if (isset($ThTrace['function']) && $ThTrace['function'] == $ThFunction) {
                $ThArgValue = $ThTrace['args'][$ThArgIndex - 1];
                return true;
            }
        }

        return false;
    }

    public static function handleTypehint($ErrLevel, $ErrMessage)
    {
        if ($ErrLevel == E_RECOVERABLE_ERROR) {
            if (preg_match(TYPEHINT_PCRE, $ErrMessage, $ErrMatches)) {
                list($ErrMatch, $ThArgIndex, $ThClass, $ThFunction, $ThHint, $ThType) = $ErrMatches;

                if (isset(self::$Typehints[$ThHint])) {
                    $ThBacktrace = debug_backtrace();
                    $ThArgValue  = NULL;

                    if (self::getTypehintedArgument($ThBacktrace, $ThFunction, $ThArgIndex, $ThArgValue)) {
                        if (call_user_func(self::$Typehints[$ThHint], $ThArgValue)) {
                            return true;
                        } else {
                            throw new TypeHintException('Type check error!');
                        }
                    }
                }
            }
        }

        return false;
    }
}

TypeHint::initializeHandler();

function teststring(string $string)
{
    echo 'string';
    echo $string;
}

function testinteger(integer $integer)
{
    echo $integer;
}

function testfloat(float $float)
{
    echo $float;
}

try {
    testString('123');
} catch (Exception $e) {
    echo $e->getMessage();
}