These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * slince routing library |
||
4 | * @author Tao <[email protected]> |
||
5 | */ |
||
6 | namespace Slince\Routing; |
||
7 | |||
8 | use Psr\Http\Message\ServerRequestInterface; |
||
9 | use Slince\Routing\Exception\RouteNotFoundException; |
||
10 | use Slince\Routing\Exception\MethodNotAllowedException; |
||
11 | |||
12 | class Matcher |
||
13 | { |
||
14 | /** |
||
15 | * Routes collection |
||
16 | * @var RouteCollection |
||
17 | */ |
||
18 | protected $routes; |
||
19 | |||
20 | public function __construct(RouteCollection $routes) |
||
21 | { |
||
22 | $this->routes = $routes; |
||
23 | } |
||
24 | |||
25 | /** |
||
26 | * Find the route that match the given path from the routes |
||
27 | * @param string $path |
||
28 | * @return Route |
||
29 | */ |
||
30 | public function match($path) |
||
31 | { |
||
32 | $path = '/' . ltrim($path, '/'); |
||
33 | return $this->doMatch($path); |
||
34 | } |
||
35 | |||
36 | /** |
||
37 | * Find the route that match given request |
||
38 | * @param ServerRequestInterface $request |
||
39 | * @return Route |
||
40 | */ |
||
41 | public function matchRequest(ServerRequestInterface $request) |
||
42 | { |
||
43 | return $this->doMatch($request); |
||
44 | } |
||
45 | |||
46 | /** |
||
47 | * Do match |
||
48 | * @param string|ServerRequestInterface $pathOrRequest |
||
49 | * @return Route |
||
50 | */ |
||
51 | protected function doMatch($pathOrRequest) |
||
52 | { |
||
53 | $route = $pathOrRequest instanceof ServerRequestInterface |
||
54 | ? $this->findRouteFromRequest($pathOrRequest) |
||
55 | : $this->findRoute($pathOrRequest); |
||
56 | $computedParameters = $this->computeRouteParameters($route); |
||
57 | $route->setComputedParameters($computedParameters); |
||
58 | return $route; |
||
59 | } |
||
60 | |||
61 | /** |
||
62 | * @param ServerRequestInterface $request |
||
63 | * @throws MethodNotAllowedException |
||
64 | * @throws RouteNotFoundException |
||
65 | * @return Route |
||
66 | */ |
||
67 | protected function findRouteFromRequest(ServerRequestInterface $request) |
||
68 | { |
||
69 | $requiredMethods = []; |
||
70 | foreach ($this->routes as $route) { |
||
71 | if (static::matchSchema($route, $request) |
||
72 | && static::matchHost($route, $request) |
||
73 | && static::matchPath($request->getUri()->getPath(), $route) |
||
74 | ) { |
||
75 | if (static::matchMethod($route, $request)) { |
||
76 | return $route; |
||
77 | } else { |
||
78 | $requiredMethods = array_merge($requiredMethods, $route->getMethods()); |
||
79 | } |
||
80 | } |
||
81 | } |
||
82 | if (!empty($requiredMethods)) { |
||
83 | throw new MethodNotAllowedException($requiredMethods); |
||
84 | } |
||
85 | throw new RouteNotFoundException(); |
||
86 | } |
||
87 | |||
88 | /** |
||
89 | * @param string $path |
||
90 | * @throws RouteNotFoundException |
||
91 | * @return Route |
||
92 | */ |
||
93 | protected function findRoute($path) |
||
94 | { |
||
95 | foreach ($this->routes as $route) { |
||
96 | if (static::matchPath($path, $route)) { |
||
97 | return $route; |
||
98 | } |
||
99 | } |
||
100 | throw new RouteNotFoundException(); |
||
101 | } |
||
102 | |||
103 | /** |
||
104 | * Checks whether the route matches the current request host |
||
105 | * @param Route $route |
||
106 | * @param ServerRequestInterface $request |
||
107 | * @return boolean |
||
108 | */ |
||
109 | protected static function matchHost(Route $route, $request) |
||
110 | { |
||
111 | if (empty($route->getHost())) { |
||
112 | return true; |
||
113 | } |
||
114 | if (preg_match($route->compile()->getHostRegex(), $request->getUri()->getHost(), $matches)) { |
||
115 | $routeParameters = array_filter($matches, function($value, $key){ |
||
116 | return !is_int($key) && $value; |
||
117 | }, ARRAY_FILTER_USE_BOTH); |
||
118 | $route->setParameter('_hostMatches', $routeParameters); |
||
119 | return true; |
||
120 | } |
||
121 | return false; |
||
122 | } |
||
123 | |||
124 | /** |
||
125 | * Checks whether the route matches the current request method |
||
126 | * @param Route $route |
||
127 | * @param ServerRequestInterface $request |
||
128 | * @return boolean |
||
129 | */ |
||
130 | protected static function matchMethod(Route $route, $request) |
||
131 | { |
||
132 | if (!$route->getMethods()) { |
||
133 | return true; |
||
134 | } |
||
135 | return in_array(strtoupper($request->getMethod()), $route->getMethods()); |
||
136 | } |
||
137 | |||
138 | /** |
||
139 | * Checks whether the route matches the scheme |
||
140 | * @param Route $route |
||
141 | * @param ServerRequestInterface $request |
||
142 | * @return boolean |
||
143 | */ |
||
144 | protected static function matchSchema(Route $route, $request) |
||
145 | { |
||
146 | if (!$route->getSchemes()) { |
||
147 | return true; |
||
148 | } |
||
149 | return in_array($request->getUri()->getScheme(), $route->getSchemes()); |
||
150 | } |
||
151 | |||
152 | /** |
||
153 | * Checks whether the route matches the given path |
||
154 | * @param string $path |
||
155 | * @param Route $route |
||
156 | * @return boolean |
||
157 | */ |
||
158 | protected static function matchPath($path, Route $route) |
||
159 | { |
||
160 | if (preg_match($route->compile()->getPathRegex(), rawurldecode($path), $matches)) { |
||
161 | $routeParameters = array_filter($matches, function($value, $key){ |
||
162 | return !is_int($key) && $value; |
||
163 | }, ARRAY_FILTER_USE_BOTH); |
||
164 | $route->setParameter('_pathMatches', $routeParameters); |
||
165 | return true; |
||
166 | } |
||
167 | return false; |
||
168 | } |
||
169 | |||
170 | /** |
||
171 | * 处理路由参数 |
||
172 | * @param Route $route |
||
173 | * @return array |
||
174 | */ |
||
175 | protected static function computeRouteParameters(Route $route) |
||
176 | { |
||
177 | return array_replace($route->getDefaults(), |
||
178 | $route->getParameter('_hostMatches') ?: [], |
||
179 | $route->getParameter('_pathMatches', []) ?: [] |
||
0 ignored issues
–
show
|
|||
180 | ); |
||
181 | } |
||
182 | } |
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.
In this case you can add the
@ignore
PhpDoc annotation to the duplicate definition and it will be ignored.