所有从事 PHP 工作的人都知道 ThinkPHP 是一个免费开源的轻量级 PHP 框架。虽然它很轻量,但是它的功能却非常强大。
这也是我接触的第一个框架。 TP框架中默认的URL模式是PathInfo模式。这种模式非常强大。每次访问一个网站,肯定都会有一长串的参数,但太长了,不友好。访问MVC模式构建的网站,必须有三个参数,分别是module、controller、action、M、C、A,这些参数需要用“&”分隔。如果参数很多的话就特别不友好。然而PathInfo模式的功能就是为了缩短和简化这个长长的列表,让这个路径显示起来更加友好。
传统的访问路径是这样的:
http://www.webguidecorpuschristi.com/index.php?m=module&c=controller&a=action&var1=vaule1&var2=vaule2.....
而 ThinkPHP 在默认 URL 模式下可以实现这样的路径:
http://www.webguidecorpuschristi.com/index.php?module/controller/action/var1/vaule1/var2/value2.....
两者对比,很容易得出结论:PathInfo模式下的访问路径显示更加友好!
不过,这篇文章我想讲的是如何构建这样一个友好的访问路径。
我的目标路径是这样的(当然TP也可以轻松做到):
http://www.webguidecorpuschristi.com/module/controller/action/var1/vaule1/var2/value2.....
以上三个路径代表的意思是一样的,即都是访问同一个站点,参数相同
因为最近打算模仿写一个小框架来加强和巩固自己的基础知识。它是用MVC模式构建的,所以与模型、控制器、行为等接触较少。之前一直在使用ThinkPHP,感觉ThinkPHP中URL中的默认模式PATHINFO非常强大。所以我决定创建这样一个函数并在我自己的小框架的 URL 上使用它。一直想研究一下ThinkPHP的原代码,但是由于时间不够,一直没有实现。我计划在这个寒假期间研究一下这个框架的原始代码,这是我大学生涯的最后一个寒假。
---- 想要学习,就必须坚定、坚持。如果不坚定,就会有毅力。不坚定就会有退路。。
鼓励大家,坚持就是成功!好吧,让我们回到正题。我创建的PATHINFO在功能上与ThinkPHP一致。至于底层原理和效率问题,和TP中的PATHINFO是否一样还不清楚。毕竟我还没学过TP。这里原代码是按照我自己的想法写的。
1。 Apache 的重写模块。
使用apache的重写模块,该站点的所有访问路径只能从单个index.php条目输入。 (由于Apache重写规则也是个硬骨头,所以这里就不赘述了,我会另外写一篇文章来总结当时的重写规则,和大家互相学习。作者博客:http:// www.webguidecorpuschristi.com/phpstudy2015-6/)
2。正则表达式
正则表达式和PHP中的preg_match()函数的基础知识。这个函数是制作这个功能的关键,所以需要仔细理解。
3。类文件的自动加载和路径问题
在MVC模式中,最基本需要处理的参数是M、C、A这三个参数,这三个参数的思想贯穿了整个模式代码。
这里我们需要处理的是URL,即我们只需要确定通过路径的模块、控制器、动作来访问哪个类、哪个控制器、行为即可。这些类的对象的生成以及行为方法的调用都是自动的,我们不需要编写额外的代码来一一处理。
因此,如何准确地加载类文件和调用方法是非常关键的一步。 PHP有一个内置函数,当新Object创建时会自动触发,这就是__autoload()。它扩展了函数 spl_autoload_register() 来注册自动加载函数。
关于路径问题,由于需要实现自动化,即自动加载class文件等,所以需要一个相对健壮的加载路径代码,使其更加可移植。例如,它可以在Windows和Linux系统下顺利工作,因此需要在PHP中使用一个魔术常量__DIR__来编写路径代码。
Linux虚拟机,PHP5.3.6,域名www.webguidecorpuschristi.com
1。创建相应的文件夹。虽然这个例子很简单,但是我们不能含糊其辞,养成良好的习惯,争取早日成为高手,哈哈
这个文件夹可以根据个人想法创建。如果是用在框架上,这一步就非常重要了。具体请参考各框架的文件目录结构。我的文件目录如下:
我刚刚开始构建它。该目录非常简单,还不够完善。毕竟我还是个新手。各位大师,请不要批评我。如果可以的话,请给我一些建议。
这里我主要展示一下我的文件夹,方便后面的理解和分析。这个函数的重点是Url.class.php文件。
2。启用apache的重写模块
在对应的配置文件中打开即可,这里就不解释了。
然后在根目录下创建.htaccess文件,这里主要放置重写规则,如下图:
简单分析:
1。 RewriteEngine on 打开重写
2。 RewriteRule重写规则,表示非以上后缀的路径都适合
3。 RewriteCond判断是否为文件
这里的作用是让www.webguidecorpuschristi.com的所有路径只能通过index.php路径访问,这是一个单一的入口。
3。主码
Url.class.php
我把这个文件放到/Framework/Core文件夹下
";";
print_r($urls);
echo "
代码功能分析:
上面的Url.class.php类文件代码大致可以分为两部分。在第75行可以分为上半部和下半部,也就是getRoute方法所在的地方。
上半部分是方法addRoute,用于添加路径正则表达式,并存储在类属性$routes中。
下半部分是方法getRoute,用于匹配和处理访问路径。传入要访问的路径,然后与$routes中的正则表达式进行匹配。成功后,将进行进一步处理,并返回处理结果。
对于上面的Url.class.php类文件,我们可以在根目录下创建一个test.php测试文件或者直接在index.php文件上进行测试(方便快捷),帮助我们进一步理解其原理和该类文件的功能。功能。 (这里我不会创建测试文件,而是直接在index.php文件上测试)
测试 1:
index.php代码如下
在Url.class.php的addRoute方法中添加一个输出进行观察,如下图:
首先访问:http://www.webguidecorpuschristi.com/
结果:
总结:
1。显然,输出类属性$routes存储的是正则表达式。
2。在私有方法_ParseRoute中,调用_normalize()方法来处理$key。该方法是过滤掉$key中除a-zA-Z0-9以外的符号。
3。正则表达式中,[P<'.$key.'>]用于preg_match匹配,后面会解释。
4。在switch中,正则表达式被匹配并选择。可以自己定义,也可以自己写。例如:
int 代表 self::REGEX_INT,即正则表达式 =》([0-9]+?)
Alpha 代表 self::REGEX_ALPHA,即正则表达式 =》([a-zA-Z_-]+?)
Alphanum 代表自身::REGEX_ALPHANUMBERIC=》([0-9a-zA-Z_-]+?)
(正则表达式)表示使用自己写的表达式=》例如:(www[0-9]+?)
因此,添加正则路由addRoute的参数形式:[/int:module/alpha:controller/alphanum:action/(www[0-9]+?):id]任意组合(数量不限),冒号 以下参数与 preg_match 一起使用,稍后解释。
5。 $regex.=self::ANY;这里的作用是匹配URL路径的其他参数,即 http://www.webguidecorpuschristi.com/module/controller/action/var1/values1 ,action后面的var1、values1等参数。
测试完成后,将Url.class.php类文件恢复到原来的状态!
测试2:
index.php代码修改如下:
";";
echo "index.php 第一个输出
";
print_r($url);
echo "
";";死;
echo "index.php getRoute 输出结果第五次输出
";
print_r($urls);
echo "
在Url.class.php的getRoute方法中添加以下输出:
第二个输出用于查看使用多个正则表达式时$routes的值,如下图:
第三个输出,如下图
第四个输出,如下图
第三个和第四个输出用于查看和理解preg_match()函数
开始访问:http://www.webguidecorpuschristi.com/m/c/a/var/value
结果与总结:
1。输出
这里需要你了解和体验$_SERVER
2。输出2
有多条路径时,都会保存在$routes中
3。输出三、四
这里我们需要重点关注preg_matches()函数。
注:
使用 PCRE 函数时,模式需要用分隔符括起来。分隔符可以是任何非字母数字、非反斜杠或非空白字符。如果分隔符在模式中频繁出现,更好的选择是使用其他分隔符来提高可读性。
由此我们可以知道$routes中的值@的含义,它是分隔符,但是我们经常使用/。
preg_matches()的第一个参数是正则表达式。这里我们把它放在 $routes 中。
preg_matches()的第二个参数是需要匹配的数据。这里我们放入传入的URL(这里的URL就是输出一的值)。
preg_matches()的第二个参数是一个不必要的参数。如果填写该参数,则所有成功匹配的值都会放入该数组中。
preg_matches() 在 PHP5.2.2 中有一个新的小语法,小语法在这里至关重要。
如果使用这个小语法(?P 特别注意: 匹配foreach时,如果$routes包含多个正则表达式,则会按照顺序一一匹配URL。如果全部匹配成功,则后面的值会覆盖前面的值。 4。输出五
这里是getRoute()方法处理URL时返回的结果。 测试完成后,需要将Url.class.php文件恢复到原来的状态 至此,整个Url.class.php类文件已经解释和分析完毕,接下来就是接入MVC了。 下面简单介绍一下自动加载类文件、生成对象、调用方法。 可以查看上面的文件目录来了解下面的各个文件。 index.php文件 /Framework/Core/Core.php /框架/函数/AutoLoad.function.php /Framework/Core/Autoload.class.php 模块中还有两个控制器文件 TestController.class.php 在首页 TestController.class.php 开始访问: 1、http://www.webguidecorpuschristi.com/Home/Test/action/var1/vaule1/var2/value2 结果是:
2、http://www.webguidecorpuschristi.com/Admin/Test/action/var1/vaule1/var2/value2 结果是:
完成了,我厌倦了每个字的编码。这里的URL路径不处理大小写,因此模块、控制器和操作都是区分大小写的。 多思考,多思考,多编码,争取早日成为大师! 下次打算改成存储方式,将addRoute的常规路径存储在文件中的$routes中,然后在使用getRoute时取出来。然后使用apache的ab进行压力测试。 (以上是我自己的一些看法,如有不足或错误还请指出) 作者:那叶随风 声明:本博文为原创,仅代表本人在一段时间内工作和学习中总结的观点或结论。转载时,请在文章页面明显位置提供原文链接。
$router->addRoute("/alpha:module/alpha:controller/[0-9]+?:a1a");
$router->addRoute("/alpha:module/alpha:controller/alpha:action");
$router->addRoute("/alpha:module/alpha:controller/alpha:action/(www[0-9]+?):id");
$url=$_SERVER['REQUEST_URI'];
$urls=$router->getRoute($url);
$_GET['urls']=$urls;
$m=$urls['模块'];
$c=$urls['控制器'];
$a=$urls['action'];
如果($m&&$c)
{
$autoload=new 自动加载($m,$c);
$autoload->PutFile();
}
$object=new $c;
$object->$a();
?>
# 加载PHP自动加载函数文件
include_once(__DIR__."/../Function/AutoLoad.function.php");
?>
spl_autoload_register('CoreFunction');
函数 CoreFunction($classname)
{
$file=__DIR__."/../Core/".$classname.".class.php";
if(is_file($file))
{
require_once($file);
}
}
?>
自动加载类
{
私人$path='';
公共函数 __construct($module,$controller)
{
$this->path=__DIR__."/../../Application/".$module."/Controller/".$controller."Controller.class.php";
}
公共函数 PutFile()
{
if(is_file($this->path)) #判断文件是否存在
{
require_once($this->path);
}
否则
{
返回 false;
}
}
}
?>
{
公共 $aa=2;
公共函数action()
{
echo "home-->test----->action";
echo "";
";
print_r($_GET);
echo "
}
}
管理中的
{
公共 $aa=2;
公共函数action()
{
echo "管理---->测试----->操作";
echo "";
";
print_r($_GET);
echo "
}
}
相关文章