PHP 小白之路

Hello PHP

讓我們在桌面創(chuàng)建一個 hello.php的文件

<?php
     echo "Hello World!";

執(zhí)行php hello.php
Hooray!!! 我們得到了一個輸出 Hello World! 的程序

我們如何通過Http請求輸出"Hello World!"呢?
借助 Http 服務器后裸。例如使用 nginx,監(jiān)聽 http 請求冒滩,當有對 php 文件的請求發(fā)生時微驶,我們將它轉發(fā)給 php-fpmphp-fpm 執(zhí)行我們想要執(zhí)行的 php文件并拿到結果开睡,原路返回

PHP 類

通常情況下因苹,我們需要使用類來執(zhí)行特定的功能,那么上面的程序我們可以改寫為下面這樣篇恒,我們使用類 Hello 來輸出了 Hello World!

<?php
    class Hello {
        public function index() {
            echo "Hello World!";
        }
    }
    (new Hello())->index();

可是如果我們把所有類都寫在一個文件里容燕,這個文件將變得臃腫和難以維護。

<?php
    class Hello {
        public function index() {
            echo "Hello World!";
        }
    }
    (new Hello())->index();
    class h2{
        function __construct(){
            echo "H2!";
        }
    }
    (new h2());
  • 所以通常情況下婚度,一個文件中我們只放一個類蘸秘,一個類只負責一件事情,我們的類的調用也通常是在另外的文件中蝗茁。

修改 hello.php

<?php
    class Hello {
        public function index() {
            echo "Hello World!";
        }
    }

在桌面新建一個 use.php的文件, 我們將使用這個新的 php 文件作為入口調用 hello.php

<?php 
    $hello = new Hello();
    $hello->index();

執(zhí)行php use.php醋虏,我們得到了一個報錯

PHP Fatal error:  Uncaught Error: Class "Hello" not found in /Users/zhangmingsheng/Desktop/use.php:2
Stack trace:
#0 {main}
  thrown in /Users/zhangmingsheng/Desktop/use.php on line 2

Fatal error: Uncaught Error: Class "Hello" not found in /Users/zhangmingsheng/Desktop/use.php:2
Stack trace:
#0 {main}
  thrown in /Users/zhangmingsheng/Desktop/use.php on line 2

找不到 Class "Hello",這是因為我們在 use.php 中并沒有將 Hello 類加載進來

PHP 類的加載

我們可以使用 include 或者 require 方法來加載 php 文件

include在包含文件不存在時會發(fā)出警告、在多次包含同一個文件時會重復解析和執(zhí)行哮翘;而require在包含文件不存在時會引發(fā)致命錯誤颈嚼、在多次包含同一個文件時只包含一次。使用include_once和require_once可以避免重復包含的問題饭寺。在實際開發(fā)中阻课,我們可以根據(jù)具體需求選擇適合的函數(shù)來使用。

在 use.php中添加 include 語句

<?php 
    include '/Users/zhangmingsheng/Desktop/hello.php';
    $hello = new Hello();
    $hello->index();

執(zhí)行php use.php艰匙,成功輸出Hello World!

命名空間

為防止重名限煞,php 引入了命名空間,默認情況下员凝,所有常量署驻、類和函數(shù)名都放在全局空間下,就和PHP支持命名空間之前一樣。
命名空間通過關鍵字namespace 來聲明旺上。

  • 如果一個文件中包含命名空間瓶蚂,它必須在其它所有代碼之前聲明命名空間。
<?php  
// 定義代碼在 'MyProject' 命名空間中  
namespace MyProject;  

使用命名空間:別名/導入 use

<?php
use My\Full\Classname as Another;
// 下面的例子與 use My\Full\NSname as NSname 相同
use My\Full\NSname;
  • use導入可以使用 as 添加別名宣吱,如果沒有使用 as窃这,則最后一段路徑名將作為別名

使用命名空間改寫我們的代碼,
修改hello.php

<?php
    namespace HelloSpace;
    class Hello {
        public function index() {
            echo "Hello World!";
        }
    }

修改use.php

<?php 
    use HelloSpace\Hello;
    $hello = new Hello();
    $hello->index();

執(zhí)行php use.php征候,我們得到了一個報錯

PHP Fatal error:  Uncaught Error: Class "HelloSpace\Hello" not found in /Users/zhangmingsheng/Desktop/use.php:3
Stack trace:
#0 {main}
  thrown in /Users/zhangmingsheng/Desktop/use.php on line 3

Fatal error: Uncaught Error: Class "HelloSpace\Hello" not found in /Users/zhangmingsheng/Desktop/use.php:3
Stack trace:
#0 {main}
  thrown in /Users/zhangmingsheng/Desktop/use.php on line 3

找不到 Class "HelloSpace\Hello"钦听,原來,use 并不能直接用來加載 php 文件倍奢,使用 use 的前提是朴上,use 的目標類文件已經(jīng)被加載,否則就會報錯卒煞,我們仍然需要使用 include 語句來加載 hello.php

添加 include 語句痪宰,一切恢復正常

<?php 
    include '/Users/zhangmingsheng/Desktop/hello.php';
    use HelloSpace\Hello;
    $hello = new Hello();
    $hello->index();

use 的特殊性

在上面的例子中我們看到,use 并不能直接用來加載 php 文件畔裕,使用 use 的前提是衣撬,類文件已經(jīng)被加載,否則就會報找不到類的錯誤扮饶。
但是 use 又有它的特殊性具练,就是 use 可以作為前向引用,什么意思呢甜无,我們對use.php進行下微調

<?php 
    use HelloSpace\Hello;
    include '/Users/zhangmingsheng/Desktop/hello.php';
    $hello = new Hello();
    $hello->index();

再次執(zhí)行php use.php, 成功輸出了Hello World!
啊咧咧扛点?不是說需要先 include 么,為什么這次又可以了呢岂丘?

  • 這是因為我們雖然聲明了 use HelloSpace\Hello;陵究,但是還沒有開始調用 Hello 類,
    use 可以提前聲明我要使用 Hello奥帘,只要保證在真正使用 Hello 前铜邮,Hello 類可以完成加載。

所以如果我們再次如下調整寨蹋,猜猜結果會怎樣呢松蒜?

<?php 
    use HelloSpace\Hello;
    $hello = new Hello();
    $hello->index();
    include '/Users/zhangmingsheng/Desktop/hello.php';

沒錯,我們又獲得了找不到 Class "HelloSpace\Hello"的報錯

關于use 的前向引用已旧,在 laravel 框架的入口文件也有體現(xiàn)

<?php
//注意這兩個 use 聲明
use Illuminate\Contracts\Http\Kernel;
use Illuminate\Http\Request;

define('LARAVEL_START', microtime(true));

/*
|--------------------------------------------------------------------------
| Check If The Application Is Under Maintenance
|--------------------------------------------------------------------------
|
| If the application is in maintenance / demo mode via the "down" command
| we will load this file so that any pre-rendered content can be shown
| instead of starting the framework, which could cause an exception.
|
*/

if (file_exists($maintenance = __DIR__.'/../storage/framework/maintenance.php')) {
    require $maintenance;
}

/*
|--------------------------------------------------------------------------
| Register The Auto Loader
|--------------------------------------------------------------------------
|
| Composer provides a convenient, automatically generated class loader for
| this application. We just need to utilize it! We'll simply require it
| into the script here so we don't need to manually load our classes.
|
*/

require __DIR__.'/../vendor/autoload.php';

/*
|--------------------------------------------------------------------------
| Run The Application
|--------------------------------------------------------------------------
|
| Once we have the application, we can handle the incoming request using
| the application's HTTP kernel. Then, we will send the response back
| to this client's browser, allowing them to enjoy our application.
|
*/

$app = require_once __DIR__.'/../bootstrap/app.php';

$kernel = $app->make(Kernel::class);

$response = $kernel->handle(
    $request = Request::capture()
)->send();

$kernel->terminate($request, $response);

我們發(fā)現(xiàn) autoload.php自動加載文件是在 use 聲明后才require 進來的秸苗,這里就展示了 use 的特殊性。

那既然提到了自動加載评姨,那什么是自動加載呢难述?

PHP自動加載

在編寫面向對象(OOP) 程序時萤晴,很多開發(fā)者為每個類新建一個 PHP 文件吐句。 這會帶來一個煩惱:每個腳本的開頭胁后,都需要包含(include)一個長長的列表(每個類都有個文件)。

spl_autoload_register() 函數(shù)可以注冊任意數(shù)量的自動加載器嗦枢,當使用尚未被定義的類(class)和接口(interface)時自動去加載攀芯。通過注冊自動加載器,腳本引擎在 PHP 出錯失敗前有了最后一個機會加載所需的類文虏。

像 class 一樣的結構都可以以相同方式自動加載侣诺。包括類、接口氧秘、trait 和枚舉年鸳。

在桌面創(chuàng)建自動加載類Autoloader

<?php
    class Autoloader{
        function __construct(){
            spl_autoload_register(array(__CLASS__, 'autoload'));
        }

        public static function autoload($class){
            include '/Users/zhangmingsheng/Desktop/hello.php';
        }
    }

此類中,我們注冊了自動加載函數(shù)autoload丸相,當遇到未加載的類的時候搔确,就去 include hello.php
正常情況下,這里會根據(jù)$class參數(shù)判斷具體要 include 哪個文件灭忠,我們這里做了簡化膳算,只 include hello.php

接著,我們修改 use.php

<?php 
    include 'autoloader.php';
    new Autoloader();
    use HelloSpace\Hello;
    $hello = new Hello();
    $hello->index();

運行 php use.php弛作,成功輸出 Hello World涕蜂!
我們發(fā)現(xiàn),我們這次并沒有在 use.php中直接 include hello.php映琳,而是通過autoloader自動加載了hello.php机隙。
將引入 autoloader 的兩條語句注釋,再次運行萨西,報錯黍瞧,找不到 Class "HelloSpace\Hello"
這就是php的自動加載機制一個簡單的演示

自動類加載器

  • 想想我們之前的自動加載模型原杂,還有哪些地方可以改進印颤?
    對,我們不是根據(jù)實際需要的類進行相應類的加載〈┮蓿現(xiàn)在我們來完善它年局,寫一個可用的自動加載器吧

前面我們已經(jīng)簡單講過 namespace,namespace像 java 的 package 一樣咸产,可以防止類名重復引發(fā)問題矢否。但 java 的 package 還有一個附帶的作用,就是 package可以推倒出類文件的目錄脑溢,這樣當我們知道一個類的 package 的時候僵朗,我們也能推斷出如何加載這個類赖欣。那我們 php 的 namespace 是否也可以具有這樣的功能呢?答案是可以的

  • 與目錄和文件的關系很像验庙,PHP 命名空間也允許指定層次化的命名空間的名稱顶吮。

因此,命名空間的名字可以使用分層次的方式定義:

<?php
namespace MyProject\Sub\Level;  //聲明分層次的單個命名空間

const CONNECT_OK = 1;
class Connection { /* ... */ }
function Connect() { /* ... */  }

我們現(xiàn)在讓我們的程序的命名空間與目錄名對應起來
在桌面創(chuàng)建 HelloSpace 目錄粪薛,將桌面的hello.php移入其中

<?php
    namespace HelloSpace;
    class Hello {
        public function index() {
            echo "Hello World!";
        }
    }

我們按照命名空間對應目錄名的規(guī)則悴了,修改autoloader.php

<?php
    class Autoloader{
        function __construct(){
            spl_autoload_register(array(__CLASS__, 'autoload'));
        }

        public static function autoload($class){
            $filePath = str_replace('\\', '/', $class);
            require_once $filePath . '.php';
        }
    }

運行 php use.php,成功輸出 HelloWorld违寿!

  • 可是在我們開發(fā)的時候有時候命名空間并不一定和目錄名完全對應湃交,為了兼容這種情況,我們就需要使用 Map藤巢,設置他們的對應關系

修改autoloader.php 使我們可以添加Map映射

<?php
    class Autoloader{
        protected $base_dir = "/Users/zhangmingsheng/desktop";
        protected $maps = [];
        function __construct(){
            spl_autoload_register(array(__CLASS__, 'autoload'));
        }

        public function autoload($class){
            //完整的類名由命名空間名和類名組成
            //得到命名空間名
            $pos = strrpos($class, '\\');
            $namespace = substr($class, 0, $pos);
            //得到類名
            $realClass = strtolower(substr($class, $pos + 1));
            //根據(jù)命名空間名和類名得到文件路徑
            $this->mapLoad($namespace, $realClass);
        }

        protected function mapLoad($namespace, $realClass){
            if(isset($this->maps[$namespace])){
                $namespace = $this->maps[$namespace];
            }
            //處理路徑, 將命名空間中的\替換成/. 由于 namespace 有些帶有\(zhòng)有些不帶有\(zhòng), 所以需要rtrim處理
            $namespace = rtrim(str_replace('\\', '/', $namespace),'/').'/';
            $filePath = $this->base_dir . '/' . $namespace . $realClass . '.php';
            //將該文件包含進來即可
            if(file_exists($filePath)){
                require_once $filePath;
            }else{
                echo sprintf("%s文件不存在", $filePath);
            }
        }


        function addMaps($namespace, $path){
            if(isset($this->maps[$namespace])){
                echo sprintf("%s已經(jīng)存在", $namespace);
                return;
            }
            $this->maps[$namespace] = $path;
        }
    }

接下來搞莺,我們創(chuàng)建一個新的php文件來驗證我們的 autoloader,
在桌面創(chuàng)建目錄 relationship掂咒,在 relationship 目錄下才沧,創(chuàng)建spare目錄, 在 spare 中創(chuàng)建xiaoming.php

<?php
    namespace Spare;
    class Xiaoming {
        public function sing() {
            echo "xiaoming sing!";
        }

        public function dance() {
            echo "xiaoming dance!";
        }
    }

此時xiaoming.php的目錄名是 relationship/spare/xiaoming.php,而 Xiaoming 類的命名空間是 Spare俏扩。

修改use.php糜工,添加 map 映射

<?php 
    include 'autoloader.php';
    $auto = new Autoloader();
    $auto->addMaps('Spare', 'relationship/spare');
    use Spare\Xiaoming;
    $xm = new Xiaoming();
    $xm->dance();

執(zhí)行 php use.php
成功輸出 xiaoming dance!
至此,我們的自動加載器就完成了

laravel Request的生命周期

PHP 主要的工作是處理 Http 請求录淡,所以 PHP 的開發(fā)框架的核心也都圍繞 Http 請求服務捌木,所以了解請求的生命周期對理解 laravel 框架很有幫助
要說生命,那肯定要從生命的誕生開始嫉戚,我們找到 laravel 的入口文件 index.php, 看看它都做了什么

<?php

use Illuminate\Contracts\Http\Kernel;
use Illuminate\Http\Request;

define('LARAVEL_START', microtime(true));

/*
|--------------------------------------------------------------------------
| Check If The Application Is Under Maintenance
|--------------------------------------------------------------------------
|
| If the application is in maintenance / demo mode via the "down" command
| we will load this file so that any pre-rendered content can be shown
| instead of starting the framework, which could cause an exception.
|
*/

if (file_exists($maintenance = __DIR__.'/../storage/framework/maintenance.php')) {
    require $maintenance;
}

/*
|--------------------------------------------------------------------------
| Register The Auto Loader
|--------------------------------------------------------------------------
|
| Composer provides a convenient, automatically generated class loader for
| this application. We just need to utilize it! We'll simply require it
| into the script here so we don't need to manually load our classes.
|
*/

require __DIR__.'/../vendor/autoload.php';

/*
|--------------------------------------------------------------------------
| Run The Application
|--------------------------------------------------------------------------
|
| Once we have the application, we can handle the incoming request using
| the application's HTTP kernel. Then, we will send the response back
| to this client's browser, allowing them to enjoy our application.
|
*/

$app = require_once __DIR__.'/../bootstrap/app.php';

$kernel = $app->make(Kernel::class);

$response = $kernel->handle(
    $request = Request::capture()
)->send();

$kernel->terminate($request, $response);

use 語句前面已經(jīng)講過了刨裆,我們往后看
首先定義LARAVEL_START常量,然后判斷是否處于maintenance模式彬檀。之后才進入正題:

  • 加載autoload.php
  • 加載 app.php
  • 初始化Http\Kernel
  • 處理 request
  • 處理 response

前面已經(jīng)簡單講述過autoload帆啃,現(xiàn)在我們看下 laravel 的app到底是什么, app 是一個 service container,那什么是service container呢?
這里引用下文檔原文

The Laravel service container is a powerful tool for managing class dependencies and performing dependency injection. Dependency injection is a fancy phrase that essentially means this: class dependencies are "injected" into the class via the constructor or, in some cases, "setter" methods.

上面的定義中提到了依賴注入窍帝,那什么是依賴注入呢努潘?可以看下我之前寫的一篇短文,依賴注入(DI),控制反轉(IOC),依賴反轉(依賴倒置/DIP)

短文中顯示的舉例了什么是依賴注入坤学,同時也提到 laravel的app使用自動加載來隱式的完成了依賴注入的

可能看到這里疯坤,雖然知道了 app 能做什么,但是依然想不明白app到底做了啥深浮。

  • app其實為你提供了一個workspace, 它為你管理依賴關系压怠,從而可以讓你把精力集中在業(yè)務邏輯中。

它就像是炒菜鍋飞苇,使你能專注在如何炒好菜菌瘫,調好味道蜗顽,而不用擔心一不留神,火就把菜燒成了灰燼雨让,而我們炒菜的第一步雇盖,就是要有一個炒菜鍋

有了app后,我們進入Http\Kernel的初始化
我們來看下Illuminate\Foundation\Http\Kernel.php

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末宫患,一起剝皮案震驚了整個濱河市刊懈,隨后出現(xiàn)的幾起案子这弧,更是在濱河造成了極大的恐慌娃闲,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件匾浪,死亡現(xiàn)場離奇詭異皇帮,居然都是意外死亡,警方通過查閱死者的電腦和手機蛋辈,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門属拾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人冷溶,你說我怎么就攤上這事渐白。” “怎么了逞频?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵纯衍,是天一觀的道長。 經(jīng)常有香客問我苗胀,道長襟诸,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任基协,我火速辦了婚禮歌亲,結果婚禮上,老公的妹妹穿的比我還像新娘澜驮。我一直安慰自己陷揪,他們只是感情好,可當我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布杂穷。 她就那樣靜靜地躺著悍缠,像睡著了一般。 火紅的嫁衣襯著肌膚如雪亭畜。 梳的紋絲不亂的頭發(fā)上扮休,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天,我揣著相機與錄音拴鸵,去河邊找鬼玷坠。 笑死蜗搔,一個胖子當著我的面吹牛,可吹牛的內容都是我干的八堡。 我是一名探鬼主播樟凄,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼兄渺!你這毒婦竟也來了缝龄?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤挂谍,失蹤者是張志新(化名)和其女友劉穎叔壤,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體口叙,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡炼绘,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了妄田。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片俺亮。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖疟呐,靈堂內的尸體忽然破棺而出脚曾,到底是詐尸還是另有隱情,我是刑警寧澤启具,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布本讥,位于F島的核電站,受9級特大地震影響富纸,放射性物質發(fā)生泄漏囤踩。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一晓褪、第九天 我趴在偏房一處隱蔽的房頂上張望堵漱。 院中可真熱鬧,春花似錦涣仿、人聲如沸勤庐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽愉镰。三九已至,卻和暖如春钧汹,著一層夾襖步出監(jiān)牢的瞬間丈探,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工拔莱, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留碗降,地道東北人隘竭。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像讼渊,于是被迫代替她去往敵國和親动看。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內容

  • Welcome 目前網(wǎng)絡上充斥著大量的陳舊信息爪幻,讓PHP新手誤入歧途菱皆,傳播著錯誤的實踐和糟糕的代碼,這必須得到糾正...
    layjoy閱讀 21,672評論 7 118
  • PHP優(yōu)化 默認安裝的 PHP 就像是在百貨商店里購買的普通套裝挨稿,雖然合身仇轻,卻不完美。調優(yōu)的 PHP 就像是定做的...
    師娘哪里去了閱讀 508評論 0 0
  • Nginx的工作原理 1.Nginx的模塊與工作原理 Nginx由內核和模塊組成叶组,其中拯田,內核的設計非常微小和簡潔历造,...
    架構飛毛腿閱讀 6,021評論 1 27
  • PHP基礎知識 1. 引用變量 概念:在PHP中引用意味著用不同的名字訪問同一個變量內容甩十。 定義方式:使用&符號 ...
    LeeShun閱讀 424評論 0 0
  • PHP不權威總結 歡迎閱讀 本文目標用戶是我自己,系統(tǒng)地持續(xù)集成PHP方方面面的知識吭产,但不會事無巨細的一一列舉侣监,只...
    liufxlucky365閱讀 340評論 0 0