可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I am creating my own MVC framework in php as a means to learn more advanced programming. I've got the framework up and running however I have an issue regarding the current routing method. I want the framework to support a backend cms to compliment the front end website. The issue is that my routing structure works like so - mywebsite.com/controller/method/id
The routing engine sorts the information into an array like this
segments 0 => controller, 1 => method, 2 => id
Right now if I visit mywebsite.com/projects it takes me to what I have set up as an admin page. Not only do I want this to be accessible only from mywebsite.com/admin/projects, I want the mywebsite.com/projects to take me to frontend.
So if I want to visit mywebsite.com/projects
I'd like it to render the "front" controller, pushing "projects" into the method. If I visit mywebsite.com/admin/projects
I'd like it to load the projects controller.
Here's the current routing class in whole as follows.
<?php
class Request {
//url domain.com/controller/method/other
//holds url segments 0 => controller, 1 => method, 2 => other, etc
public $segments;
function __construct() {
$this->parse_globals();
}
function parse_globals(){
//$uri = preg_replace("|/(.*)|", "\\1", str_replace("\\", "/", $_SERVER['REQUEST_URI']));
$uri = (empty($_GET['rt'])) ? '' : $_GET['rt'];
$this->segments = array_filter(explode('/', $uri));
if (in_array("admin", $this->segments)) {
array_shift($this->segments);
}
print_r($this->segments);
//remove index php
if( reset($this->segments) == 'index.php') {
array_shift ($this->segments);
}
}
function controller(){
return $this->segment(0);
}
function method(){
return $this->segment(1);
}
function param( $str ){
return isset($_REQUEST[$str]) ? $_REQUEST[$str] : false;
}
function segment( $no ){
return isset($this->segments[$no]) ? $this->segments[$no] : false;
}
}
回答1:
Instead of simply using explode()
to separate the segments of URL, you could use a set of regular expression pattern.
For example, this following patter would try to match at firsts action
, and, if action
exists them check if there is controller
set before it:
'/(:?(:?\/(?P<controller>[^\/\.,;?\n]+))?\/(?P<action>[^\/\.,;?\n]+))?/'
Most of PHP frameworks use different ways to generate such patterns, with simplified notations. This way you can set which parts for each pattern are mandatory and which optional. And it is also possible to provide fallback values for the optional parts.
That said ...
Before starting to make something so complicated as cms with framework, you might invest some additional time in researching OOP. I would recommend to at least watch lectures from Miško Hevery and Robert C. Martin. Just because you think, that you know how to write a class, does not mean, that you understands object oriented programming.
Update
I have listed few materials in this answer. You might find them useful,
Additionally here are two more lectures, that were not in answer above:
- Clean Code I: Arguments
- Clean Code III: Functions
回答2:
My understanding is that there's three routing cases:
The basic one:
/<controller>/<action>/<parameters>
A special one for the admin panel (where "admin" would be a kind of separate module):
/<module>/<controller>/<action>/<parameters>
And finally a special case for "/projects" which maps to "/front/projects".
In that case, you need to make your routing class more flexible so that it can handle any kind of routing scheme. In a framework like Kohana, this would be done with rules such as:
Route::set('adminModule', 'admin/projects')
->defaults(array(
'controller' => 'projects',
'action' => 'admin',
));
Route::set('projectPage', 'projects')
->defaults(array(
'controller' => 'front',
'action' => 'projects',
));
Route::set('default', '(<controller>(/<id>(/<action>)))')
->defaults(array(
'controller' => 'index',
'action' => 'index',
));
Obviously this is just an example but you get the idea. Basically, you want to provide some sensible default routing (eg. controller/action/id) but you also need to allow users to configure other routes.
回答3:
I am currently developing a php router which is targeted at extreme high performance. you probably might want to take a look.
https://github.com/c9s/Pux
We also provide a pattern compiler that is doing the same thing as yours. but you can write a simpler path instead of complex patterns.
e.g., you may write something like this:
/product/:id/:name [ id => '\d+', name => '\w+' ]
FYI:
Pux is 48.5x faster than symfony router in static route dispatching, 31x faster in regular expression dispatching. (with pux extension installed)
Pux tries not to consume computation time to build all routes dynamically (like Symfony/Routing). Instead, Pux compiles your routes to plain PHP array for caching, the compiled routes can be loaded from cache very fast.
With Pux PHP Extension support, you may load and dispatch the routes 1.5~2x faster than pure PHP Pux.