日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > php >内容正文

php

PHP自动加载机制

發(fā)布時(shí)間:2023/12/15 php 57 豆豆
生活随笔 收集整理的這篇文章主要介紹了 PHP自动加载机制 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

概述

首先,為什么PHP需要自動(dòng)加載呢?

在PHP面向?qū)ο?OO)編程中,為了方便管理,我們都會(huì)把一個(gè)類寫在一個(gè)單獨(dú)的文件中,那么如果想在A類中使用B類的功能,就需要把B類加載到A類。對(duì)于這樣的需求在最原始的時(shí)候,我們是通過require 和 include 語(yǔ)法實(shí)現(xiàn)將文件加載到另一個(gè)文件中,include 和 require 是PHP中引入文件的兩個(gè)基本方法。

在小規(guī)模開發(fā)中直接使用 include 和 require 不會(huì)有什么不妥,但在大型項(xiàng)目中會(huì)造成大量的 include 和 require 堆積。這樣的代碼既不優(yōu)雅,執(zhí)行效率也很低,而且維護(hù)起來也相當(dāng)困難。

PHP的自動(dòng)加載功能,框架實(shí)現(xiàn)自動(dòng)加載的包括PHP規(guī)范中的PSR0和PSR4原則,Composer的自動(dòng)加載功能等等。

php加載文件方式

  • 常規(guī)加載:include,include_once,requice,requice_one
  • 魔法方法:__autoload()
  • SPL 自動(dòng)加載:spl_autoload_register()
  • include()與require()

    簡(jiǎn)單的文件加載方法:

  • require()

    包含的意思,找不到文件時(shí),會(huì)報(bào)warning的錯(cuò)誤,然后程序繼續(xù)往下執(zhí)行。include語(yǔ)句只有在被執(zhí)行時(shí)才會(huì)讀入要包含的文件。在錯(cuò)誤處理方便,使用include語(yǔ)句,如果發(fā)生包含錯(cuò)誤,程序?qū)⑻^include語(yǔ)句,雖然會(huì)顯示錯(cuò)誤信息但是程序還是會(huì)繼續(xù)執(zhí)行!php處理器會(huì)在每次遇到include()語(yǔ)句時(shí),對(duì)它進(jìn)行重新處理,所以可以根據(jù)不同情況的,在條件控制語(yǔ)句和循環(huán)語(yǔ)句中使用include()來包含不同的文件。

  • include()

    必須的意思,找不到文件時(shí),會(huì)報(bào)fatal error(致命錯(cuò)誤),程序停止往下執(zhí)行。在php文件被執(zhí)行之前,php解析器會(huì)用被引用的文件的全部?jī)?nèi)容替換require語(yǔ)句,然后與require語(yǔ)句之外的其他語(yǔ)句組成個(gè)新的php文件,最好后按新的php文件執(zhí)行程序代碼。

  • require_once()

    類似于include(),系統(tǒng)會(huì)進(jìn)行判斷,如果已經(jīng)包含,則不會(huì)再包含第二次。

  • include_once()

    類似于require(),系統(tǒng)會(huì)進(jìn)行判斷,如果已經(jīng)包含,則不會(huì)再包含第二次。

  • 共同點(diǎn):能包含位于獨(dú)立文件中的代碼,可以減少代碼的重復(fù),實(shí)現(xiàn)代碼結(jié)構(gòu)的模塊化,方便調(diào)用。

    • 注意事項(xiàng)

      • 加載文件格式

        include/require 包含進(jìn)來的文件必須要加<?php ?>因?yàn)樵诎瑫r(shí),首先理解文件內(nèi)容是普通字符串,碰到<?php ?>標(biāo)簽時(shí),才去解釋。

      • 路徑要求

        可以用絕對(duì)路徑,也可以用相對(duì)路徑;windows下正反斜線都可以,linux下只認(rèn)正斜線,所以最好用正斜線。

      • 如何選擇

        比如是系統(tǒng)配置,缺少了,網(wǎng)站不讓運(yùn)行,自然用require,如果是某一段統(tǒng)計(jì)程序,少了,對(duì)網(wǎng)站只是少統(tǒng)計(jì)人數(shù)罷了,不是必須要的,可以用include而加不加once是效率上的區(qū)別,加上once,雖然系統(tǒng)幫你考慮了只加載一次,但系統(tǒng)的判斷會(huì)是效率降低,因此,更應(yīng)該在開發(fā)之初,就把目錄結(jié)構(gòu)調(diào)整好,盡量不要用_once的情況。

      • 特殊用法

        利用include/require返回被包含頁(yè)面的返回值

        1
        2
        a.php頁(yè)面中: ..... return $value;
        b.php頁(yè)面中:$v = include("a.php");

    __autoload()自動(dòng)加載

    • PHP5及之后的版本,使用尚未定義的類時(shí)會(huì)自動(dòng)調(diào)用__autoload函數(shù),所以我們可以通過編寫__autoload函數(shù)來讓php自動(dòng)加載類,而不必寫一個(gè)長(zhǎng)長(zhǎng)的包含文件列表。

      需明確的是對(duì)于__autoload()函數(shù),PHP在找不到類的時(shí)候會(huì)自動(dòng)執(zhí)行,但是PHP內(nèi)部并沒有定義這個(gè)函數(shù)。

      這個(gè)函數(shù)需要開發(fā)者自定義,并且編寫內(nèi)部邏輯,PHP只負(fù)責(zé)在需要的時(shí)候自動(dòng)調(diào)用執(zhí)行。而且在調(diào)用的時(shí)候會(huì)自動(dòng)傳人要加載的類名作為參數(shù)。

    • 用法:首先需要在需要加載文件的代碼中,定義__autoload()函數(shù),并且編寫內(nèi)部邏輯。PHP在找不到類的時(shí)候會(huì)自動(dòng)執(zhí)行__autoload()函數(shù)。下面是A.php需要加載B.php的例子:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      //文件 B.php 不做修改
      //文件 A.php
      <?php
      class A{
      public function test(){
      $b_object = new B();
      $b_object->echo_info();
      }
      }
      function __autoload($classname){
      require $classname.'.php';//include 'b.php';
      }
      $a_object = new A();
      $a_oject->test();
      ?>
      命令行輸入:#php a.php
      輸出: “我是class B中的方法執(zhí)行結(jié)果“
    • 缺陷:一個(gè)項(xiàng)目中僅能有一個(gè)這樣的 __autoload() 函數(shù),因?yàn)?PHP 不允許函數(shù)重名,也就是說你不能聲明2個(gè)__autoload()函數(shù)文件,否則會(huì)報(bào)致命錯(cuò)誤。

      如果項(xiàng)目比較大,加載每個(gè)文件都使用同樣的規(guī)則顯然是不現(xiàn)實(shí)的,那么我們可能就需要在__autoload()中編寫復(fù)雜的規(guī)則邏輯來滿足加載不同文件的需求。

      這同樣會(huì)使得__autoload()函數(shù)變得復(fù)雜臃腫,難以維護(hù)管理

    SPL 自動(dòng)加載

    PHP在實(shí)例化一個(gè)對(duì)象時(shí)(實(shí)際上在實(shí)現(xiàn)接口,使用類常數(shù)或類中的靜態(tài)變量,調(diào)用類中的靜態(tài)方法時(shí)都會(huì)如此),首先會(huì)在系統(tǒng)中查找該類(或接口)是否存在,如果不存在的話就嘗試使用autoload機(jī)制來加載該類。而autoload機(jī)制的主要執(zhí)行過程為:

    • 檢查執(zhí)行器全局變量函數(shù)指針autoload_func是否是NULL;
    • 如果 autoload_func==NULL ,則查找系統(tǒng)是否定義 __autoload() 函數(shù),如果定義了,則執(zhí)行并返回加載結(jié)果。如果沒有定義,則報(bào)錯(cuò)并退出;
    • 如果 autoload_func 不等于NULL,則直接執(zhí)行 autoload_func 指向的函數(shù)加載類,此時(shí)并不檢查 __autoload() 函數(shù)是否定義。

    通過上述PHP自動(dòng)加載流程,可知PHP實(shí)際上提供了兩種方法來實(shí)現(xiàn)自動(dòng)裝載機(jī)制:(1)使用用戶定義的__autoload()函數(shù),這通常在PHP源程序中來實(shí)現(xiàn);(2)設(shè)計(jì)一個(gè)函數(shù),將autoload_func指針指向它,這通常使用C語(yǔ)言在PHP擴(kuò)展中實(shí)現(xiàn),即 SPL autoload機(jī)制,即本節(jié)中的SPL自動(dòng)加載。如果兩種方式都實(shí)現(xiàn)了,也就是 autoload_func 不等于NULL,程序只會(huì)執(zhí)行第二種方式,__autoload() 函數(shù)是不會(huì)被執(zhí)行的。

    • 用法

      通過spl_autoload_register('my_autoload'),實(shí)現(xiàn)了 當(dāng)程序執(zhí)行找不到類B時(shí),會(huì)執(zhí)行 自定義的 my_autoload()函數(shù),加載B類。實(shí)際上 spl_autoload_register('my_autoload') 的作用就是 把a(bǔ)utoload_func 指針指向 my_autoload()。

      示例:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      B.php文件不變
      A.php
      <?php
      class A{
      public function test(){
      $b_object = new B();
      $b_object->echo_info();
      }
      }

      function __autoload($classname){
      require $classname.'.php';//include 'b.php';
      }

      function my_autoload($classname){
      require $classname.'.php';//include 'b.php';
      echo 'my_autoload ';
      }

      spl_autoload_register('my_autoload');
      $a_object = new A();
      $a_object->test();

      結(jié)果:my_autoload 我是class B中的方法執(zhí)行結(jié)果
      ?>
    • SPL 自動(dòng)加載整個(gè)過程

      針對(duì)上述的示例,假如把spl_autoload_register('my_autoload')改成 spl_autoload_register()不添加任何參數(shù),B類也能被加載。

      為什么呢?

      因?yàn)镾PL擴(kuò)展內(nèi)部自己定義了一個(gè)自動(dòng)加載函數(shù) spl_autoload(),實(shí)現(xiàn)了自動(dòng)加載的功能,如果我們不定義自己的自動(dòng)加載函數(shù),并且程序里寫了spl_autoload_register()(如果不傳參數(shù),必須是第一次執(zhí)行才會(huì)有效)或者 spl_autoload_register('spl_autoload'),那么autoload_func 指針就會(huì)指向內(nèi)部函數(shù) spl_autoload()。程序執(zhí)行的時(shí)候如果找不到相應(yīng)類就會(huì)執(zhí)行該自動(dòng)加載函數(shù)。

      SPL 是怎么實(shí)現(xiàn)autoload_func 指針指向不同的函數(shù)呢?

      在SPL內(nèi)部定義了 一個(gè)函數(shù) spl_autoload_call() 和 一個(gè)全局變量autoload_functions。autoload_functions本質(zhì)上是一個(gè)HashTable,不過我們可以將其簡(jiǎn)單的看作一個(gè)鏈表,鏈表中的每一個(gè)元素都是一個(gè)函數(shù)指針,指向一個(gè)具有自動(dòng)加載類功能的函數(shù)。

      spl_autoload_call()的作用就是按順序遍歷 autoload_functions,使得autoload_func指向每個(gè)自動(dòng)加載函數(shù),如果加載成功就停止,如果不成功就繼續(xù)遍歷下個(gè)自動(dòng)加載函數(shù),直到加載成功或者遍歷完所有的函數(shù)。

      autoload_functions 這個(gè)列表是誰(shuí)來維護(hù)的呢?

      由spl_autoload_register() 這個(gè)函數(shù)維護(hù)。我們說的自動(dòng)加載函數(shù)的注冊(cè),其實(shí)就是通過·spl_autoload_register()·把自動(dòng)加載函數(shù)加入到autoload_functions 列表。

      相關(guān)SPL自動(dòng)加載函數(shù)

      1
      2
      spl_autoload_functions() //打印autoload_functions列表
      spl_autoload_unregister() //注銷自動(dòng)加載函數(shù)

    參考:

  • PHP-自動(dòng)加載原理分析
  • php自動(dòng)加載方式集合
  • 總結(jié)

    以上是生活随笔為你收集整理的PHP自动加载机制的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。