1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Created by rozbo at 2017/3/19 下午5:30 |
4
|
|
|
*/ |
5
|
|
|
|
6
|
|
|
namespace puck; |
7
|
|
|
|
8
|
|
|
class Route { |
9
|
|
|
private $request; |
10
|
|
|
|
11
|
|
|
public function __construct(Request $request) { |
12
|
|
|
$this->request = $request; |
13
|
|
|
$this->errorCallback=function (){ |
14
|
|
|
die("404"); |
|
|
|
|
15
|
|
|
}; |
16
|
|
|
} |
17
|
|
|
|
18
|
|
|
public static $halts = false; |
19
|
|
|
private $routes = array(); |
20
|
|
|
private $regexRoutes = []; |
21
|
|
|
public static $methods = array(); |
22
|
|
|
public static $callbacks = array(); |
23
|
|
|
private $patterns = array( |
24
|
|
|
':any' => '[^/]+', |
25
|
|
|
':num' => '[0-9]+', |
26
|
|
|
':all' => '.*' |
27
|
|
|
); |
28
|
|
|
public $errorCallback; |
29
|
|
|
|
30
|
|
|
/** |
31
|
|
|
* Defines a route w/ callback and method |
32
|
|
|
*/ |
33
|
|
|
public function __call($method, $params) { |
34
|
|
|
$this->addRoute($method, $params[0], $params[1]); |
35
|
|
|
} |
36
|
|
|
|
37
|
|
|
/** |
38
|
|
|
* 添加一个路由 |
39
|
|
|
* @param string $method |
40
|
|
|
* @param string $uri |
41
|
|
|
* @param mixed $callBack |
42
|
|
|
*/ |
43
|
|
|
public function addRoute($method, $uri, $callBack) { |
44
|
|
|
$method = strtoupper($method); |
45
|
|
|
//预定义正则路由 |
46
|
|
|
if (strpos($uri, ':') !== false) { |
47
|
|
|
$searches = array_keys($this->patterns); |
48
|
|
|
$replaces = array_values($this->patterns); |
49
|
|
|
$uri = str_replace($searches, $replaces, $uri); |
50
|
|
|
$this->regexRoutes[] = [ |
51
|
|
|
'method' => $method, |
52
|
|
|
'regex' => '#^' . $uri . '$#', |
53
|
|
|
'callback' => $callBack |
54
|
|
|
]; |
55
|
|
|
} //自定义正则路由 |
56
|
|
|
elseif ($uri[0] == '#' |
57
|
|
|
|| (strlen($uri) > 2 && tools\Str::endsWith($uri, '/') && tools\Str::startsWith($uri, '/')) |
58
|
|
|
) { |
59
|
|
|
$this->regexRoutes[] = [ |
60
|
|
|
'method' => $method, |
61
|
|
|
'regex' => $uri, |
62
|
|
|
'callback' => $callBack |
63
|
|
|
]; |
64
|
|
|
} //直接定义的路由 |
65
|
|
|
else { |
66
|
|
|
$this->routes[$method . $uri] = [ |
67
|
|
|
'method' => $method, |
68
|
|
|
'uri' => $uri, |
69
|
|
|
'callback' => $callBack |
70
|
|
|
]; |
71
|
|
|
} |
72
|
|
|
} |
73
|
|
|
|
74
|
|
|
/** |
75
|
|
|
* Defines callback if route is not found |
76
|
|
|
*/ |
77
|
|
|
public function error($callback) { |
78
|
|
|
$this->errorCallback = $callback; |
79
|
|
|
} |
80
|
|
|
|
81
|
|
|
public static function haltOnMatch($flag = true) { |
82
|
|
|
self::$halts = $flag; |
83
|
|
|
} |
84
|
|
|
|
85
|
|
|
|
86
|
|
|
private function foundRoute($route, $param = []) { |
87
|
|
|
try { |
88
|
|
|
if ($route['callback'] instanceof \Closure) { |
89
|
|
|
app()->invokeFunction($route['callback'],$param); |
90
|
|
|
} else { |
91
|
|
|
// Grab all parts based on a / separator |
92
|
|
|
$parts = explode('/', $route['callback']); |
93
|
|
|
// Collect the last index of the array |
94
|
|
|
$last = end($parts); |
95
|
|
|
// Grab the controller name and method call |
96
|
|
|
$segments = explode('@', $last); |
97
|
|
|
app()->invokeMethod($segments, $param); |
98
|
|
|
} |
99
|
|
|
} catch (\ReflectionException $e) { |
100
|
|
|
return false; |
101
|
|
|
} |
102
|
|
|
catch (\InvalidArgumentException $e) { |
103
|
|
|
return false; |
104
|
|
|
} |
105
|
|
|
return true; |
106
|
|
|
} |
107
|
|
|
|
108
|
|
|
public function foundRegexRoute($current) { |
109
|
|
|
foreach ($this->regexRoutes as $regexRoute) { |
110
|
|
|
if (preg_match($regexRoute['regex'], $current['uri'], $matched)) { |
111
|
|
|
if ($regexRoute['method'] == $current['method'] |
112
|
|
|
|| $regexRoute['method'] == 'ANY' |
113
|
|
|
) { |
114
|
|
|
//将第一个成员,即是全部字符串剔除 |
115
|
|
|
array_shift($matched); |
116
|
|
|
return $this->foundRoute($regexRoute, $matched); |
117
|
|
|
} |
118
|
|
|
} |
119
|
|
|
} |
120
|
|
|
return false; |
121
|
|
|
} |
122
|
|
|
|
123
|
|
|
/** |
124
|
|
|
* Runs the callback for the given request |
125
|
|
|
*/ |
126
|
|
|
public function dispatch() { |
127
|
|
|
|
128
|
|
|
$current['uri'] = $this->request->path(); |
|
|
|
|
129
|
|
|
$current['method'] = $this->request->method(); |
130
|
|
|
# 第一种情况,直接命中 |
131
|
|
|
if (isset($this->routes[$current['method'] . $current['uri']])) { |
132
|
|
|
$this->foundRoute($this->routes[$current['method'] . $current['uri']]); |
133
|
|
|
} # 第二种情况,any命中 |
134
|
|
|
else if (isset($this->routes['ANY' . $current['uri']])) { |
135
|
|
|
$this->foundRoute($this->routes['ANY' . $current['method']]); |
136
|
|
|
} # 第三种情况,正则命中 |
137
|
|
|
else { |
138
|
|
|
if ($this->foundRegexRoute($current)) { |
|
|
|
|
139
|
|
|
|
140
|
|
|
} else { |
141
|
|
|
$route['callback'] = $this->errorCallback; |
|
|
|
|
142
|
|
|
$this->foundRoute($route); |
143
|
|
|
} |
144
|
|
|
} |
145
|
|
|
} |
146
|
|
|
} |
An exit expression should only be used in rare cases. For example, if you write a short command line script.
In most cases however, using an
exit
expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.