從零開始打造自己的PHP框架——第1章

目標(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

書簽

從零開始打造自己的PHP框架

PHP 檔案引入路徑問題

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末宝剖,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子歉甚,更是在濱河造成了極大的恐慌万细,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,997評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件铃芦,死亡現(xiàn)場離奇詭異雅镊,居然都是意外死亡襟雷,警方通過查閱死者的電腦和手機刃滓,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來耸弄,“玉大人咧虎,你說我怎么就攤上這事〖瞥剩” “怎么了砰诵?”我有些...
    開封第一講書人閱讀 163,359評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長捌显。 經(jīng)常有香客問我茁彭,道長,這世上最難降的妖魔是什么扶歪? 我笑而不...
    開封第一講書人閱讀 58,309評論 1 292
  • 正文 為了忘掉前任理肺,我火速辦了婚禮,結(jié)果婚禮上善镰,老公的妹妹穿的比我還像新娘妹萨。我一直安慰自己,他們只是感情好炫欺,可當(dāng)我...
    茶點故事閱讀 67,346評論 6 390
  • 文/花漫 我一把揭開白布乎完。 她就那樣靜靜地躺著,像睡著了一般品洛。 火紅的嫁衣襯著肌膚如雪树姨。 梳的紋絲不亂的頭發(fā)上摩桶,一...
    開封第一講書人閱讀 51,258評論 1 300
  • 那天,我揣著相機與錄音娃弓,去河邊找鬼典格。 笑死,一個胖子當(dāng)著我的面吹牛台丛,可吹牛的內(nèi)容都是我干的耍缴。 我是一名探鬼主播,決...
    沈念sama閱讀 40,122評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼挽霉,長吁一口氣:“原來是場噩夢啊……” “哼防嗡!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起侠坎,我...
    開封第一講書人閱讀 38,970評論 0 275
  • 序言:老撾萬榮一對情侶失蹤蚁趁,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后实胸,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體他嫡,經(jīng)...
    沈念sama閱讀 45,403評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,596評論 3 334
  • 正文 我和宋清朗相戀三年庐完,在試婚紗的時候發(fā)現(xiàn)自己被綠了钢属。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,769評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡门躯,死狀恐怖淆党,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情讶凉,我是刑警寧澤染乌,帶...
    沈念sama閱讀 35,464評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站懂讯,受9級特大地震影響荷憋,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜褐望,卻給世界環(huán)境...
    茶點故事閱讀 41,075評論 3 327
  • 文/蒙蒙 一勒庄、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧譬挚,春花似錦锅铅、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,705評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至漆腌,卻和暖如春贼邓,著一層夾襖步出監(jiān)牢的瞬間阶冈,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,848評論 1 269
  • 我被黑心中介騙來泰國打工塑径, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留女坑,地道東北人。 一個月前我還...
    沈念sama閱讀 47,831評論 2 370
  • 正文 我出身青樓统舀,卻偏偏與公主長得像匆骗,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子誉简,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,678評論 2 354

推薦閱讀更多精彩內(nèi)容