目標(biāo)
本篇腐碱,我們來實現(xiàn)類庫自動加載年缎,以及路由解析忍弛。
類庫自動加載
常規(guī)加載
常規(guī)加載一般使用include或者require歼争,它們最根本的區(qū)別在于錯誤處理的方式不一樣拜马。
include包括并運行指定文件。include一個文件存在錯誤的話沐绒,那么程序不會中斷俩莽,而是繼續(xù)執(zhí)行,并顯示一個警告錯誤乔遮。
include_once的作用和include幾乎相同扮超,唯一的差別在于導(dǎo)入之前會檢查要導(dǎo)入的文件是否已經(jīng)被導(dǎo)入過了,如果有的話就不會再次重復(fù)導(dǎo)入蹋肮。
require會將目標(biāo)文件的內(nèi)容讀入弹灭,并且把本身替換成這些讀入的內(nèi)容榕暇。require一個文件存在錯誤的話,那么程序就會中斷執(zhí)行了,并顯示致命錯誤缠诅。
require_once的作用和require幾乎相同原在,唯一的差別在于導(dǎo)入之前會檢查要導(dǎo)入的文件是否已經(jīng)被導(dǎo)入過了硝全,如果有的話就不會再次重復(fù)導(dǎo)入。
在使用一個文件(類庫)的函數(shù)之前却音,我們需要先使用include或者require,把該文件引入進當(dāng)前文件矢炼,然后才能使用文件中的函數(shù)系瓢。
例如我們要新建一個route對象。
1句灌、core目錄中夷陋,新建route.php:
<?php
/**
* 路由控制
*/
namespace core;
class route{
public function __construct(){
echo 'route is ready!';
}
}
2、根目錄下index.php中涯塔,添加:
$route = new \core\route();
會報錯Fatal error: Class 'core\route' not found in...
需要改成:
include '\core\route.php';
$route = new \core\route();
或者:
require '\core\route.php';
$route = new \core\route();
自動加載
bool spl_autoload_register ([ callable $autoload_function [, bool $throw = true [, bool $prepend = false ]]] )
將函數(shù)注冊到SPL __autoload函數(shù)隊列中。如果該隊列中的函數(shù)尚未激活清蚀,則激活它們匕荸。成功時返回 TRUE,失敗時返回 FALSE枷邪。
spl_autoload_register的一般用法:
spl_autoload_register(function ($class_name) {
require_once $class_name . '.php';
});
$route = new \core\route();
在新建route對象時榛搔,class_name也就是\core\route
會傳入到spl_autoload_register函數(shù)中,該函數(shù)的參數(shù)是一個回調(diào)函數(shù)东揣〖螅回調(diào)函數(shù)拿到class_name,然后進行文件的引入嘶卧。
也就是說尔觉,和常規(guī)加載相比,使用自動加載芥吟,我們不必對每一個類庫單獨進行引入侦铜。
自動加載進階
上例中,spl_autoload_register的回調(diào)函數(shù)是一個匿名函數(shù)钟鸵,而且比較簡單钉稍。下面,我們來寫一個更高級的回調(diào)函數(shù)棺耍。新建aotuload.php贡未,內(nèi)容如下:
<?php
/**
* 自動加載類庫
*/
namespace core;
class autoload{
public static function load($class_name){
if(file_exists($class_name.'.php')){
require_once $class_name.'.php';
return true;
}else{
echo 'error: unable to load '.$class_name.'.php';
return false;
}
}
}
使用的時候,改成:
include CORE.'/autoload.php';
spl_autoload_register('\core\autoload::load');
$route = new \core\route();
加載機制簡析
在使用include的時候蒙袍,會用到php文件系統(tǒng)俊卤。在文件系統(tǒng)中訪問一個文件有三種方式:
1、相對文件名形式如route.php
害幅。它會被解析為 include_path/route.php
瘾蛋,其中 include_path 表示.;C:/laragon/bin/php/php-5.6.16/PEAR
。
假設(shè)當(dāng)前目錄是C:/laragon/www/vkphp
矫限,則該文件名依次被解析為:
C:/laragon/www/vkphp/route.php
C:/laragon/bin/php/php-5.6.16/PEAR/route.php
2哺哼、相對路徑名形式如core/route.php
佩抹,它會被解析為 include_path/core/route.php
。
假設(shè)當(dāng)前目錄是C:/laragon/www/vkphp
取董,則該文件名依次被解析為:
C:/laragon/www/vkphp/core/route.php
C:/laragon/bin/php/php-5.6.16/PEAR/core/route.php
3棍苹、絕對路徑名形式如/core/route.php
,在linux系統(tǒng)中茵汰,它會被解析為/core/route.php
枢里;在windows系統(tǒng)中,它會被解析為 include_path/core/route.php
蹂午,和相對路徑一樣栏豺。
絕對路徑名形如C:/laragon/www/vkphp/core/route.php
或者C:\laragon\www\vkphp\core\route.php
或者 C:\\laragon\\www\\vkphp\\core\\route.php
,在windows系統(tǒng)中豆胸,會被解析為C:/laragon/www/vkphp/core/route.php
奥洼。也就是說,windows中斜線和反斜線和雙反斜線效果相同晚胡。
獲取include_path和設(shè)置include_path的栗子:
echo get_include_path();
ini_set('include_path', ini_get('include_path').PATH_SEPARATOR.'lib_path/libs');
echo get_include_path();
路由控制
隱藏index.php
1灵奖、訪問地址 http://vkphp.dev/index.php ,此時估盘,我們看到“helloworld”和“route is ready!”瓷患。
2、訪問地址 http://vkphp.dev/index.php/index/index 遣妥,可以看到同樣的信息擅编。
3、訪問地址 http://vkphp.dev/index/index 箫踩,則會報404錯誤沙咏。那么,我們怎樣隱藏掉index.php呢班套?答案是添加.htaccess肢藐。
在項目根目錄下,添加.htaccess吱韭,內(nèi)容如下:
Options +FollowSymLinks
IndexIgnore */*
RewriteEngine on
# if a directory or a file exists, use it directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# otherwise forward it to index.php
RewriteRule . index.php
4吆豹、訪問地址 http://vkphp.dev/index/index ,可以看到和1理盆、2中相同的信息痘煤。
獲取URL中的控制器和方法
<?php
/**
* 路由控制
*/
namespace core;
class route{
public $ctrl;
public $action;
public function __construct(){
//echo 'route is ready!';
/**
* 1、隱藏index.php
* 2猿规、獲取URL中的控制器和方法
*/
if(isset($_SERVER['REQUEST_URI']) && $_SERVER['REQUEST_URI'] != '/'){
$path = $_SERVER['REQUEST_URI'];
$patharr = explode('/',trim($path, '/'));
p($patharr);
if(isset($patharr[0])){
if($patharr[0] != 'index.php'){
// 省略了index.php
$this->ctrl = $patharr[0];
if(isset($patharr[1])){
$this->action = $patharr[1];
} else{
$this->action = 'index';
}
}else{
// 沒省略index.php
if(isset($patharr[1])){
$this->ctrl = $patharr[1];
}
if(isset($patharr[2])){
$this->action = $patharr[2];
} else{
$this->action = 'index';
}
}
}else{
$this->ctrl = 'index';
$this->action = 'index';
}
}else{
$this->ctrl = 'index';
$this->action = 'index';
}
}
}
訪問地址 http://vkphp.dev/index/index 或者 http://vkphp.dev/index.php/index/index 衷快,即可看到打印出的patharr信息。
獲取URL中的參數(shù)
<?php
/**
* 路由控制
*/
namespace core;
class route{
public $ctrl;
public $action;
public $params=array();
public function __construct(){
//echo 'route is ready!';
/**
* 1姨俩、隱藏index.php
* 2蘸拔、獲取URL中的控制器和方法
* 3师郑、獲取URL中的參數(shù)
*/
if(isset($_SERVER['REQUEST_URI']) && $_SERVER['REQUEST_URI'] != '/'){
$path = $_SERVER['REQUEST_URI'];
$patharr = explode('/',trim($path, '/'));
//p($patharr);
if(isset($patharr[0])){
if($patharr[0] != 'index.php'){
// 省略了index.php
$this->ctrl = $patharr[0];
if(isset($patharr[1])){
$this->action = $patharr[1];
} else{
$this->action = 'index';
}
$count = count($patharr);
$i=2;
while($i < $count){
$this->params[$patharr[$i]] = $patharr[$i+1];
$i = $i + 2;
}
}else{
// 沒省略index.php
if(isset($patharr[1])){
$this->ctrl = $patharr[1];
}
if(isset($patharr[2])){
$this->action = $patharr[2];
} else{
$this->action = 'index';
}
$count = count($patharr);
$i=3;
while($i < $count){
$this->params[$patharr[$i]] = $patharr[$i+1];
$i = $i + 2;
}
}
}else{
$this->ctrl = 'index';
$this->action = 'index';
}
}else {
$this->ctrl = 'index';
$this->action = 'index';
}
p($this->params);
}
}
訪問地址 http://vkphp.dev/index/index/id/3/name/voidking 或者 http://vkphp.dev/index.php/index/index/id/3/name/voidking ,即可看到打印出的params信息调窍。
支持localhost
訪問地址 http://localhost/vkphp/index.php/index/index/id/3/name/voidking 宝冕,無法正常獲取控制器、方法和參數(shù)邓萨,修改如下:
<?php
/**
* 路由控制
*/
namespace core;
class route{
public $ctrl='index';
public $action='index';
public $params=array();
public function __construct(){
//echo 'route is ready!';
/**
* 1地梨、隱藏index.php
* 2、獲取URL中的控制器和方法
* 3缔恳、獲取URL中的參數(shù)
*/
if(isset($_SERVER['REQUEST_URI']) && $_SERVER['REQUEST_URI'] != '/' ){
$path = $_SERVER['REQUEST_URI'];
$patharr = explode('/',trim($path, '/'));
}else{
$patharr = array();
}
if(isset($_SERVER['HTTP_HOST']) && ($_SERVER['HTTP_HOST'] == 'localhost' || $_SERVER['HTTP_HOST'] == '127.0.0.1') ){
// 去掉項目名稱
$patharr = array_slice($patharr,1,count($patharr)-1);
}
if(isset($patharr[0])){
if($patharr[0] == 'index.php'){
// 去掉index.php
$patharr = array_slice($patharr,1,count($patharr)-1);
}
if(isset($patharr[0])){
$this->ctrl = $patharr[0];
}
if(isset($patharr[1])){
$this->action = $patharr[1];
}
$count = count($patharr);
$i=2;
while($i < $count){
if(isset($patharr[$i+1])){
$this->params[$patharr[$i]] = $patharr[$i+1];
}
$i = $i + 2;
}
}
p($this->ctrl);
p($this->action);
p($this->params);
}
}
源碼分享
https://github.com/voidking/vkphp/releases/tag/v1.1.0