将请求解析为控制器/函数/参数的最佳方式

Best way to parse request into Controller / Function / Parameters

我开始试验我自己的 MVC。

我的目标只是实现控制器模型和视图并将它们关联起来,但不幸的是,它朝着(小)框架方向发展。

我在根文件夹中有一个基础 index.php 负责路由。 (确定应创建哪个控制器,将在新创建的控制器实例上调用哪个函数等)

我正在直接从 url 解析控制器、函数和变量(就像 codeigniter 所做的那样) 例如:http://baseurl/index.php{router} /User{controller}/get{function to be called}/1{variable-0}/desc{variable-1} 而不是使用获取识别它们的方法(如 ?c=mainController&f=function_to_be_called)。

我的问题是(根据我正在做的事情),是否有另一种(更好的方法)来达到相同的结果?

编辑:
示例请求:http://localhost:8080/ut/User/getUser/1

输出:array(3) { ["controller"]=> string(4) "User" ["function"]=> string(7) "getUser" ["variables"] => array(1) { [2]=> string(1) "1" } }

感谢您的关注。

<?php

namespace System;

class UrlParser
{
public static function parseRequest(string $url):?array
{
    //default destination if nothing matches
    $destination = '404';//self::$routes['index'];

    //the order: controller to be loaded, function to be called and parameters etc...
    $hierarchical_call = array();
    //remove www : [I know its not generic]
    //TODO: check base url if it contains www, don't remove www
    $url = str_replace('www', '', $url);
    // check for a trailer slash, if not add it
    $url = substr($url, strlen($url) - 1, 1) === '/' ? $url : $url . '/';

    // split url into base url and rest
    $url_parts = explode(baseurl, $url);
    //url has more content
    if (count($url_parts) > 1) {
        $rest_url = $url_parts[1];

        /*add leading slash for regex, it is easier to get the string between two slashed insteadof [A-Z]*/
        $rest_url = substr($rest_url, 0, 1) === '/' ? $rest_url : '/' . $rest_url;

        /*
         * use regex to get the first part which is between / and /
         * if it is index.php than check if url parts has any other request
         */
        $pattern = '/[a-zA-Z0-9_\.]+/';
        preg_match_all($pattern, $rest_url, $request_parts, PREG_SET_ORDER);
        /*
         * PREG_PATTERN_ORDER
         * Orders results so that $matches[0] is an array of full pattern matches,
         * $matches[1] is an array of strings matched by the first parenthesized subpattern, and so on.
         */
        for ($i = 0; $i < count($request_parts); $i += 1) {
            //the requested file is determined add the remaining parts to it
            if (strlen($request_parts[$i][0]) > 0 && $request_parts[$i][0] !== 'index.php') {
                $hierarchical_call[] = $request_parts[$i][0];
            }
        }
    }
    return $hierarchical_call;
  }
}

Php 具有内置函数 - parse_url.

$url = 'http://localhost:8080/ut/User/getUser/1';
$parsed = parse_url($url); 
var_dump($parsed);



array(4) { 
   ["scheme"]=> string(4) "http" 
   ["host"]=> string(9) "localhost"
   ["port"]=> int(8080)
   ["path"]=> string(18) "/ut/User/getUser/1"
}

之后explode路径:

$route = explode("/", $parsed['path']);
var_dump($route);



array(5) {
    [0]=> string(0) "" 
    [1]=> string(2) "ut"
    [2]=> string(4) "User"
    [3]=> string(7) "getUser"
    [4]=> string(1) "1"
}

首先,你不需要解析完整的URL,因为你可以检索用户的调用
$_SERVER['REQUEST_URI'] ... 但我想这不是那么优雅。

至于拆分该 URI 路径,您实际上应该使用正则表达式。在您的具体示例中,正则表达式为:
'#^/ut/(?P<controller>[\w]+)/(?P<method>[\w]+)/(?P<id>[\d]+)$#i'

实时样本:here

您可以阅读更多关于如何制作路由代码的内容here, but unless you are doing this as learning experience, you probably should instead use an existing library, like FastRoute or the Symfony's standalone router