php – Type Hinting 類型提示

雖然歸類 PHP 為弱型別,不過在做 class 或 function 參數傳遞的時候還是可以做類型提示的約束喔!其實從 php 5.1 就已經可以有這種功能了,只是普遍都不流行使用,畢竟弱型別只要有一套判別技巧,是非常快速開發的,懂得運用的話並不會造成太大的困擾。因為可以更專注在應用層面。

本身已經有型別約束的功能了,參考官網介紹 http://php.net/manual/en/language.oop5.typehinting.php

但是我們最常遇到的 int 與 string 是沒辦法去做判別提示的。畢竟很多時間,我們是不太需要知道數字 1 是否等於文字 1,真的有須要去做判別,可以配合 === 使用。當然如果希望能明確識別 1 與 “1”,官網下面的網友已經貢獻出程式碼了,我這裡稍微做了修改美化

class Typehint
{
    private static $TYPEHINT_PCRE = "/^Argument (\d)+ passed to (?:(\w+)::)?(\w+)\(\) must be an instance of (\w+), (\w+) given/";
    
    private static $Typehints = array(
        'bool'       => 'is_bool',
        'int'       => '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) return FALSE;

        if (!preg_match(self::$TYPEHINT_PCRE, $ErrMessage, $ErrMatches)) return FALSE;

        list($ErrMatch, $ThArgIndex, $ThClass, $ThFunction, $ThHint, $ThType) = $ErrMatches;

        if (!isset(self::$Typehints[$ThHint])) return FALSE;

        $ThBacktrace = debug_backtrace();

        $ThArgValue  = NULL;

        if (!self::getTypehintedArgument($ThBacktrace, $ThFunction, $ThArgIndex, $ThArgValue)) return FALSE;
        

        if (!call_user_func(self::$Typehints[$ThHint], $ThArgValue)) return FALSE;

        return TRUE;
    }
}

在全域的地方添加

Typehint::initializeHandler();

接著可以測試一下囉

function testbool(bool $string) { echo $string; }
function teststring(string $string) { echo $string; }
function testinteger(int $integer) { echo $integer; }
function testfloat(float $float) { echo $float; }
function testarray(array $ary) { echo "TRUE"; }
function testobject(stdClass $ary) { echo "TRUE"; }

//使用布林
testbool(true);

//使用字串
teststring("123"); //出現警告 must be an instance of string, integer given

//使用物件
$param = array();
testobject($param); //出現警告  must be an instance of stdClass, array given

 

 

 

發表迴響