【问题标题】:PHP Routing: Giving predefined routes higher priorityPHP 路由:赋予预定义路由更高的优先级
【发布时间】:2020-04-09 22:18:31
【问题描述】:

我正在创建一个 PHP 应用程序,它使路由 URL 变得更加容易。

    // Define the routes
    $routes = [
        '/programs',
        '/programs/{}',
        '/programs/{}/members',
        '/programs/{}/{}',
        '/programs/{}/{}/members'
    ];

    // Example URL
    $url = '/programs/test/members';

    /*
     * Split the URL at /
     * Remove the first and last value from the returned array
    */
    $parts = array_values( array_filter( preg_split( "/\//", $url ) ) );

    // Loop over the defined routes
    foreach($routes as $route){
        // Split the route into parts, like we do with the url
        $route_parts = array_values( array_filter( preg_split( "/\//", $route ) ) );

        /*
         * If the route parts is more than the parts of the url
         * then continue to the next value in the routes array
         */
        if( sizeof( $route_parts ) != sizeof( $parts ) ) continue;

        // Loop over the route parts
        for( $i=0; $i<sizeof( $route_parts ); $i++ ) {
            /*
             * Compare the route part to the url part and see if they match
             * or if the route part is {}
             */
            if ( $route_parts[ $i ] != '{}' && $route_parts[ $i ] != $parts[ $i ] ) continue;
        }

        // Echo the route if it passes all the above checks
        echo 'got through: '. $route . '<br />';
    }

一般来说,这是有效的。但是,正如预期的那样,当代码尝试获取指定 url 的路由时,它会有点扭曲。它同时返回

/programs/{}/members

/programs/{}/{}

路由 - 因为它们都匹配 URL。

我正在寻找有关如何放入一些代码的指示,以便系统知道 /programs/{}/members 是预定义路由,并且应该比 /programs/{}/{} 路由具有更高的优先级 -因为代码应该只返回一个路由。

谢谢。

【问题讨论】:

  • 在您的$routes 表中,您将/programs/{}/members 列在/programs/{}/{} 之前,因为它具有更高的优先级,因此第一个匹配的路由是“赢家”。或者是匹配所需通配符最少的匹配项(即{})。
  • @Booboo 是的,我有代码可以找到通配符最少的那个,但我认为它的效率有点低,因为它是一个单独的 for 循环,在一个单独的数组上使用这个函数的结果。我想第一个解决方案可以工作,但如果是用户设置它,它可能很容易被破坏。不过感谢您的建议 - 非常感谢。
  • 你也可以总是取最长的字符串:)

标签: php regex url routing


【解决方案1】:

在@Booboo 和@freeek 的帮助下,我想出了以下答案:

    // Define the routes
    $routes = [
        '/programs',
        '/programs/{}',
        '/programs/{}/{}',
    ];

    // Example URL
    $url = '/programs/some_program/some_course';

    /*
     * Split the URL at /
     * Remove the first and last value from the returned array
    */
    $parts = array_values( array_filter( preg_split( "/\//", $url ) ) );


    // Define valid routes array
    $valid_routes = $routes;

    // Loop over the defined routes
    foreach($routes as $route){
        // Split the route into parts, like we do with the url
        $route_parts = array_values( array_filter( preg_split( "/\//", $route ) ) );

        /*
         * If the route parts is more than the parts of the url
         * then continue to the next value in the routes array
         */
        if( sizeof( $route_parts ) != sizeof( $parts ) ){
            // Remove the route from the valid routes array
            $valid_routes = array_values( array_diff( $valid_routes, [$route] ) );
        }

        // Loop over the route parts
        for( $i=0; $i<sizeof( $route_parts ); $i++ ) {
            /*
             * Compare the route part to the url part and see if they match
             * or if the route part is {}
             */
            if ( $i >= sizeof( $parts ) || ( $route_parts[ $i ] != '{}' & $route_parts[ $i ] != $parts[ $i ] ) ){
                // Remove the route from the valid routes array
                $valid_routes = array_values( array_diff( $valid_routes, [$route] ) );
            }
        }
    }

    // Find the route with the least occurrence of the {} characters
    $route = $this->leastOccurrence( $valid_routes, '{}' );

    if( $route != null ){
        // Route found, output the route
        echo 'Found route: ' . $route;
    } else {
        // No route found, 404
        echo '404, not found';
    } 

    function leastOccurrence( $array, $characters ){
        if( sizeof( $array ) < 1 ) return null;
        $least = $array[0];
        foreach( $array as $item ){
            if( substr_count( $item, $characters ) < substr_count( $least, $characters ) ) $least = $item;
        }
        return $least;
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-03-16
    • 2013-11-02
    • 1970-01-01
    • 2020-09-13
    • 1970-01-01
    • 1970-01-01
    • 2016-08-04
    相关资源
    最近更新 更多