3

我正在用 PHP 组合一个路由器,它匹配一个模式,比如“users/:id”,到一个路由,比如“users/123”,返回类似于“id”=> 123 的东西。这就是我到目前为止所拥有的.

function match_path($path, $pattern){
if ($path == $pattern){
  return true;
}
// check for :replacements
if (strpos($pattern, ":")!== false) {
  // split path & pattern into fragments
  $split_path =  explode('/',$path);
  $split_pattern = explode('/', $pattern);
  // check that they are the same length
  if (count($split_path) !== count($split_pattern)){
    return false;
  }
  // iterate over pattern
  foreach ($split_pattern as $index => $fragment) {
    // if fragment is wild
    if (strpos($fragment, ":") == 0){
      $params[substr($fragment, 1)] = $split_path[$index];
    // if fragment doesn't match
    } elseif ($fragment !== $split_path[$index]) {
      return false;
    }
    // continue if pattern matches
  }
  // returns hash of extracted parameters
  return $params;
}
return false;

}

我确信必须有一种方法可以用正则表达式干净地做到这一点。

更好的是,很可能有一个 PHP 函数可以做到这一点。

4

2 回答 2

1

使用这样的东西怎么样?

/**
 * Compares a url to a pattern, and populates any embedded variables
 * Returns false if the pattern does not match
 * Returns an array containing the placeholder values if the pattern matches
 * If the pattern matches but does not contain placeholders, returns an empty array
 */
function checkUrlAgainstPattern($url, $pattern) {
    // parse $pattern into a regex, and build a list of variable names
    $vars = array();
    $regex = preg_replace_callback(
        '#/:([a-z]+)(?=/|$)#',
        function($x) use (&$vars) {
            $vars[] = $x[1];
            return '/([^/]+)';
        },
        $pattern
    );

    // check $url against the regex, and populate variables if it matches
    $vals = array();
    if (preg_match("#^{$regex}$#", $url, $x)) {
        foreach ($vars as $id => $var) {
            $vals[$var] = $x[$id + 1];
        }
        return $vals;
    } else {
        return false;
    }
}

这用于preg_replace_callback()将模式转换为正则表达式并捕获占位符列表,然后preg_match()根据生成的正则表达式评估 url 并提取占位符值。

一些使用示例:

checkUrlAgainstPattern('/users/123', '/users/:id');
// returns array('id' => '123')

checkUrlAgainstPattern('/users/123/123', '/users/:id');
// returns false

checkUrlAgainstPattern('/users/123/details', '/users/:id/:page');
// returns array('id' => '123', 'page' => 'details')
于 2013-06-28T19:24:39.790 回答
1

Rails 上的 PHP,嗯?;-)

关于 的行为的重要说明strpos您应该使用严格 ===的运算符进行检查,因为它可能返回 false(来源: http: //php.net/manual/en/function.strpos.php )。经过粗略的阅读/测试,这就是我认为脚本有问题的全部......

<?php
// routes-test.php

echo "should be [ id => 123 ]:\n";
var_dump( match_path( 'user/123', 'user/:id' ) );

function match_path($path, $pattern) { ... }
?>

// cmd line
$ php routes-test.php # your implementation
should be [ id => 123 ]:
array(2) {
  ["ser"]=>
  string(4) "user"
  ["id"]=>
  string(3) "123"
}
$ php routes-test.php # using ===
should be [ id => 123 ]:
array(1) {
  ["id"]=>
  string(3) "123"
}

您应该采用 YAGNI 方法来使用正则表达式。如果您要做的只是匹配类似的东西/^:\w+$/,那么您可以更快地完成它,并且与 strpos 和朋友的行数相当。

于 2013-06-28T19:21:59.903 回答