Строгая типизация параметров передаваемых в функцию

Обсуждение документации. Переводы Cookbook и авторские рецепты.
Ответить
jarick
Сообщения: 1
Зарегистрирован: 2012.09.16, 22:25
Откуда: Калининград

Строгая типизация параметров передаваемых в функцию

Сообщение jarick »

Всем привет. Часто при тестировании работы функции, при вызове её передаються не тот тип параметров, который ожидался для неё. Классический пример null вместо string, из-за этого возникают в самых неожиданных местах непонятные ошибки. Понять суть ошибки в таком случае не всегда можно быстро( по крайне мере у меня так :roll: ). Вроде как Scalar type hints наконец-то включили в php 5.4 http://habrahabr.ru/post/136800/.

В yii очень круто написан функционал работы с веб сервисами. Тип данных для SOAP определяется из списка параметров к функции. За основу был взят данный код из веб сервисов, вот его реализация:

Код: Выделить всё

protected $mapDefaultType = array(
        'string','array','bool','float','double','int','integer','long'
    );

    public function __call($name,$parameters)
    {
        //защита от бесконечной рекурсии
        if($name !== 'behaviors')
        {
            $reflections = new SplObjectStorage();
            $reflections->attach(new ReflectionClass($this));
            $list = array_keys($this->behaviors());
            for($i = 0; $i < count($list); $i++)
            {
                $reflections->attach(new ReflectionClass($this->asa($list[$i])));
            }
            foreach($reflections as $reflection)
            {
                foreach($reflection->getMethods() as $method)
                {
                    if($method->isPublic() && ($method->getName() === $name))
                    {
                        $comment = $method->getDocComment();
                        if(strpos($comment,'@protected')!==false)
                        {
                            $comment=preg_replace('/^\s*\**(\s*?$|\s*)/m','',$comment);
                            $params=$method->getParameters();
                            $n=preg_match_all('/^@param\s+([\w\.]+(\[\s*\])?)\s*?.*$/im',$comment,$matches);
                            if($n>count($params))
                            {
                                $n=count($params);
                            }
                            for($i=0;$i<$n;++$i)
                            {
                                if(in_array($matches[1][$i], $this->mapDefaultType))
                                {
                                    if(!call_user_func_array('is_'.$matches[1][$i], array($parameters[$i])))
                                        throw new CException(Yii::t('jarick',"Параметр {$parameters[$i]} не являеться типом: {$matches[1][$i]}"));
                                }else
                                {
                                    if(!$parameters[$i] instanceof $matches[1][$i])
                                        throw new CException(Yii::t('jarick',"Параметр {$parameters[$i]} не являеться объектом класса: {$matches[1][$i]}"));
                                }
                            }
                        }
                    }
                }
            }
        }
        return parent::__call($name,$parameters);
    }
Пример использования:

Код: Выделить всё

/**
    *Добавление языка
    *@param string
    *@return bool
    *@protected
    **/
    public function addLang($lang)
Т.е. при вызове функции addLang(null) будет сгенерирована понятная ошибка о том что null не есть string.
Вероятно кто-то уже до меня реализововал нечто подобное, если кто поделиться ссылкой буду рад.
Ответить