Pull to refresh

Делаем PHP строго типизированным

Reading time 2 min
Views 11K
Данный пост посвящается любителям typehint'ов и строгой типизации, которой у PHP нет по определению.


копаясь недавно в мануалах по PHP, набрел на раздел о typehint'инге, и совершенно случайно полез в комментарии, где и нашел великолепное (хотя и тяжелое) решение для PHP5, как сделать язык строго типизированным. Под катом решение.

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

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

    private function __constrct() {}

    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;
                        }
                    }
                }
                throw new Exception( $ErrMessage );
            }
        }
        return FALSE; 
    }
}
Typehint::initializeHandler();


И вот несколько тестов:
function teststring(string $string) { echo $string; }
function testinteger(integer $integer) { echo $integer; }
function testfloat(float $float) { echo $float; }

try {
    teststring( 'string2' );
    testinteger( 14 );
    testfloat( 14.0 );
} catch ( Exception $e ) {
    echo $e->getMessage();
}


оригинал
Tags:
Hubs:
+6
Comments 43
Comments Comments 43

Articles