PHP Reflection Features

    Everything written does not pretend to be ideologically true, is not a working example of a controller, and is not recommended for mindless copying 1 to 1.

    I looked at the idea of ​​writing the necessary parameters passed to the URL directly in the function arguments in Symfony2. PHPdoc comments were used there to identify routes.

    For example, we want to see our controller like this:
    class Controller {
        /**
         * Тестовое действие
         * @a /^[0-9]+$/i
         * @b /^[0-9a-z]+$/i
         */
        function testAction ( $a, $b = 'something' ) {
            echo 'a: '.$a.', b: '.$b;
        }
    }
    



    If, despite the warnings, you want to use the 1-in-1 example, be aware:
    - The Reflection API is slow to use
    - Impossibility to obfuscate
    - The architecture is not obvious and ideological
    - There may be difficulties with team support / development or by third-party developers.


    So, the task: if the variable "a" is not passed, or the "extra" variables are passed, an error is generated, if the variable "b" is not specified, the default value is substituted. Both variables are checked against regular expressions prescribed in PHPDoc.

    As a result, the verification function turned out as follows:
    function CheckURLValid ( $class, $method, $values_arr = array() ) {
        $class  = new ReflectionClass( $class );
        $method = $class->getMethod( $method );
        $param  = $method->getParameters();
        $doc    = $method->getDocComment();
        //Разбираем PHPdoc
        preg_match_all( '/@([a-z0-9_-]+)([^\n]+)/is', $doc, $arr );
        $reg_arr = array_combine($arr[1], $arr[2]);
        //Проходим по аргументам функции
        $params_arr = array();
        foreach ( $param as $p ) {
            $key        = $p->getName();
            $value      = isset ( $values_arr[$key] ) ? $values_arr[$key] : false;
            $regular    = isset ( $reg_arr[$key] ) ? trim($reg_arr[$key]) : false;
            $default    = $p->isDefaultValueAvailable() ? $p->getDefaultValue() : NULL;
            //Если есть регулярка - проверяем
            if ( isset ( $values_arr[$key] ) ) {
                if ( $regular && !preg_match( $regular, $values_arr[$key] ) )
                    throw new Exception( 'Параметр "'.$key.'" указан неверно!' );
            //Если параметр обязательный и он не указан
            } elseif ( !$p->isOptional() )
                throw new Exception( 'Указаны не все обязательные параметры!' );
            //Добавляем значение в общий массив
            $params_arr[$key] = $value ? $value : $default;
        }
        //Проверяем наличие лишних параметров
        if ( count(array_diff_key( $values_arr, $params_arr )) )
            throw new Exception ( 'Указаны лишние параметры!' );
        return $params_arr;
    }
    


    Usage example:
    try {
        $arr = CheckURLValid( 'Controller', 'testAction', $_GET );
        call_user_func_array( array('Controller', 'testAction'), $arr );
    } catch ( Exception $e ) {
        echo $e->getMessage();
    }
    

    You can drive various variations of the type:
    /test.php
    /test.php?a=abc
    /test.php?a=12
    /test.php?a=12&b=another
    /test.php?a=12&c=13

    You can pick up one file .

    Also popular now: