从另一个字符串中的一个字符串替换匹配

时间:2015-06-03 16:25:09

标签: php regex model-view-controller router

我正在为我的PHP MVC应用程序编写路由器,我目前需要找到一种方法来使用路由中的匹配作为控制器和操作的变量。

例如,如果我有以下路线:/users/qub1/home

我想使用与此类似的正则表达式:\/users\/(?!/).*\/(?!/).*

然后我想指定这样的动作:$2(在这个例子中,这将是家庭)

传递给动作的参数如下:$1(在示例中,这将是qub1)。

然后执行类似于此的代码:

$controller = new UsersController();
$controller->$2($1);

配置的路由存储如下:

public function setRoute($route, $regex = false, $controller = 'Index', $action = 'index', $parameters = array()) {
        if(!$regex) {
            $route = preg_quote($route, '/');
        }

        $this->routes[] = [
                'route' => $route,
                'controller' => $controller,
                'action' => $action,
                'parameters' => $parameters
        ];
    }

以上示例的存储方式如下:$router->setRoute('\/users\/(?!/).*\/(?!/).*', true, 'User', '$2', [$1]);

基本上,我想使用一个正则表达式中的匹配组作为变量来替换另一个正则表达式(如果有意义的话)。

我希望我已经足够准确地描述了我的问题。谢谢你的帮助。

编辑:

我目前用于解析路由的代码(它不起作用,但它应该说明我想要实现的目标):

public function executeRoute($route) {
        // Loop over available routes
        foreach($this->routes as $currentRoute) {
            // Check if the current route matches the provided route
            if(preg_match('/^' . $currentRoute['route'] . '$/', '/' . $route, $matches)) {
                // If it matches, perform the current route's action
                // Define names
                $controllerClass = preg_replace('\$.*\d', $matches[str_replace('$', '', '$1')], ucfirst($currentRoute['controller'] . 'Controller'));
                $actionMethod = preg_replace('\$.*\d', $matches[str_replace('$', '', '$1')], strtolower($currentRoute['action']) . 'Action');
                $parameters = preg_replace('\$.*\d', $matches[str_replace('$', '', '$1')], join(', ', $currentRoute['parameters']));

                // Create the controller
                $controller = new $controllerClass();
                $controller->$actionMethod($parameters);

                // Return
                return;
            }
        }
}

1 个答案:

答案 0 :(得分:0)

虽然我不确定这是一个设计得很好的方法,但它是可行的。这是在if

中替换您的代码
// you already specify the controller name, so no need for replacing
$controllerClass = ucfirst($currentRoute['controller'] . 'Controller');

// also here, no need to replace. You just need to get the right element from the array
$actionMethod = strtolower($matches[ltrim($currentRoute['action'], '$')] . 'Action';

// here I make the assumption that this parameter is an array. You might want to add a check here
$parameters = array();
foreach ($currentRoute['parameters'] as $parameter) {
    $parameters[] = $matches[ltrim($parameter, '$')];
}

// check before instantiating
if (!class_exists($controllerClass)) {
    die('invalid controller');
}
$controller = new $controllerClass();

// also check before invoking the method
if (!method_exists($controller, $actionMethod)) {
    die('invalid method');
}
// this PHP function allows to call the function with a variable number of parameters
call_user_func_array(array($controller, $actionMethod), $parameters);

你的方法不是很有利的一个原因是你做了很多假设:

  • 正则表达式需要拥有与其他参数一样多的组
  • 如果您对正则表达式不精确,可以调用代码中的任何方法

也许这对你的项目来说已经足够好了,但如果你想创造一些不用于教育目的的东西,你应该考虑使用一个完善的路由器。