1. 程式人生 > 實用技巧 >最全PHP面試知識梳理

最全PHP面試知識梳理

演算法與資料結構

BTree和B+tree

  • BTree
    B樹是為了磁碟或者其他儲存裝置而設計的一種多叉平衡查詢樹,相對於二叉樹,B樹的每個內節點有多個分支,即多叉。

    參考文章:www.jianshu.com/p/da5...

  • B+Tree
    B+樹是B樹的變體,也是一種多路搜尋樹。

    參考文章:www.jianshu.com/p/da5...

排序演算法

  • 快速排序 快速排序是十分常用的高效率的演算法,其思想是:先選一個標尺,用它把整個佇列過一遍篩選,以保證其左邊的元素都不大於它,其右邊的元素都不小與它

    function quickSort($arr){
    
      // 獲取陣列長度
      $length = count($arr);
    
      // 判斷長度是否需要繼續二分比較
      if($length <= 1){
        return $arr;
      }
    
      // 定義基準元素
      $base = $arr[0];
    
      // 定義兩個空陣列,用於存放和基準元素的比較後的結果
      $left = [];
      $right = [];
    
      // 遍歷陣列
      for ($i=1; $i < $length; $i++) { 
    
        // 和基準元素作比較
        if ($arr[$i] > $base) {
          $right[] = $arr[$i];
        }else {
          $left[] = $arr[$i];
        }
    
      }
    
      // 然後遞迴分別處理left和right
      $left = quickSort($left);
      $right = quickSort($right);
    
      // 合併
      return array_merge($left,[$base],$right);
      
    }
  • 氣泡排序
    思路:法如其名,就像冒泡一樣,每次從陣列中冒出一個最大的數
    比如:2,4,1
    第一次冒出4:2,1,4
    第二次冒出2:1,2,4

    function bubbleSort($arr){
    
      // 獲取陣列長度
      $length = count($arr);
    
      // 第一層迴圈控制冒泡輪次
      for ($i=0; $i < $length-1; $i++) { 
        
        // 內層迴圈控制從第0個鍵值和後一個鍵值比較,每次冒出一個最大的數
        for ($k=0; $k < $length-$i; $k++) { 
          if($arr[$k] > $arr[$k+1]){
            $tmp = $arr[$k+1];
            $arr[$k+1] = $arr[$k];
            $arr[$k] = $tmp;
          }
        }
      }
    
      return $arr;
    }
  • 選擇排序 思路:每次選擇一個相應的元素,然後將其放到指定的位置

        function selectSort($arr){
         
          // 實現思路
          // 雙重迴圈完成,外層控制輪數,當前的最小值,內層控制比較次數
    
          // 獲取長度
          $length = count($arr);
      
          for ($i=0; $i < $length - 1; $i++) { 
            // 假設最小值的位置
            $p = $i;
      
            // 使用假設的最小值和其他值比較,找到當前的最小值
            for ($j=$i+1; $j < $length; $j++) { 
              // $arr[$p] 是已知的當前最小值
      
              // 判斷當前迴圈值和已知最小值的比較,當發下更小的值時記錄下鍵,並進行下一次比較
              if ($arr[$p] > $arr[$j]) {
                $p = $j; // 比假設的值更小
              }
            }
      
            // 通過內部for迴圈找到了當前最小值的key,並儲存在$p中
            // 判斷 日光當前$p 中的鍵和假設的最小值的鍵不一致增將其互換
            if ($p != $i) {
              $tmp = $arr[$p];
              $arr[$p] = $arr[$i];
              $arr[$i] = $tmp;
            }
          }
          // 返回最終結果
          return $arr;
        }

對PHP後端技術,對PHP架構技術感興趣的朋友,我的官方群1023755567點選此處,一起學習,相互討論。
群內已經有管理將知識體系整理好(原始碼,學習視訊等資料),歡迎加群免費領取。

計算機網路

TCP/UDP區別

  • TCP
    TCP是一種面向連線的、可靠的、基於位元組流的傳輸層通訊協議
    TCP面向連線,提供可靠地資料服務
    TCP首部開銷20位元組
    TCP邏輯通訊通道是全雙工的可靠通道
    TCP連線只能是點到點的
  • UDP
    UDP是參考模型中一種無連線的傳輸層協議,提供面向事務的簡單不可靠的資訊傳遞服務
    UDP無連線,不可靠
    UDP首部開銷8位元組
    UDP邏輯通訊通道是不可靠通道
    UDP沒有擁塞機制,因此網路出現擁堵不會使源主機的傳送效率降低
    UDP支援一對一,多對一,多對多的互動通訊

三次握手,四次揮手,為什麼是三次握手四次揮手

在TCP/IP協議中,TCP協議提供可靠的連線服務,採用三次握手建立一個連線,完成三次握手,客戶端與伺服器開始傳送資料。簡單點說:A與B建立TCP連線時,首先A向B傳送SYN(同步請求),然後B回覆SYN+ACK(同步請求應答),最後A回覆ACK確認,這樣TCP的一次連線(三次握手)就完成了。

  • TCP三次握手

    所謂三次握手,是指簡歷一個TCP連線時需要客戶端和伺服器總共傳送三個包
    三次握手的目的是連線伺服器指定埠,簡歷TCP連線,並同步連線雙方的序列號並交換TCP視窗大小資訊。
    TCP三次握手圖解:
    1. 第一次握手
      客戶端傳送一個TCP的SYN標誌位置1的包,指明客戶打算連線的伺服器的埠,以及初始化序號,儲存在包頭的序列號欄位裡
    2. 第二次握手
      伺服器發揮確認包應答,即SYN標誌位和ACK標誌均為1,同時將確認序號設定為客戶的ISN加1,即X+1
    3. 第三次握手
      客戶端再次傳送確認包,SYN標識為0,ACK標識為1,並且把伺服器發來的序號欄位+1,放在確定欄位中傳送給對方,並且在資料欄位寫入ISN的+1

簡單解釋TCP三次握手:
參考:github.com/jawil/blog.…

  • 四次揮手

    TCP的連線的拆除需要傳送四個包,因此稱為四次揮手。客戶端或伺服器均可主動發起揮手動作。
    由於TCP連線時全雙工的,因此每個方向都必須單獨進行關閉。這個原則是當一方完成他的資料傳送任務後就能傳送一個FIN來終止這個方向的連線。收到一個FIN只意味著這一方向上沒有資料流動,一個TCP連線在收到一個FIN後仍能傳送資料。首先進行關閉的一方將執行主動關閉,而另一方執行被動關閉。
  • 為什麼是三次握手四次揮手
    這是因為服務端的LISTEN狀態下的socket當收到SKY報文的簡歷連線的請求後,它可以把ACK和SYN放在一個報文裡來發送。但關閉連線時,當收到對方的FIN報文通知時,他僅僅表示對方沒有資料傳送給你了,但未必你的所有資料都全部發送給對方了,所以你可以不是馬上回關閉socket,即你可能還會發送一些資料給對方之後,在傳送FIN報文給對方來表示你同意現在可以關閉連線了,所以這裡的ACK和FIN報文多情況下都是分開發送的。

長連線和短連線

TCP在真正的讀寫操作之前,server和client之間必須建立一個連線,當讀寫操作完成後,雙方不再需要這個連結時他們可能釋放這個連線,連線的建立是通過三次握手,釋放則需要四次揮手,所以說每個連線的建立都是需要消耗資源和時間的。

  • TCP短連線

    1. client向server發起連線請求
    2. server接到請求,雙方建立連線
    3. client向server發訊息
    4. server迴應client
    5. 一次讀寫完成,此時雙方任何一個都可以發起close操作
      一般都是client先發起close操作,因為一般的server不會回覆完client就立即關閉連線

所以短連線一般只會在client和server間傳遞一次讀寫操作,短連線管理起來比較簡單,存在的連線都是有用的連線,不需要額外的控制手段

  • 長連線

    1. client向server發起連線
    2. server接到請求後,雙方建立連線
    3. client向server傳送訊息
    4. server迴應client
    5. 一次讀寫完成,連線不關閉
    6. 後續讀寫操作
  • 長/短連線的操作過程

    1. 短連線的操作步驟:
      建立連線 -> 資料傳輸 -> 關閉連線
    2. 長連線的操作步驟:
      建立連線 -> 資料傳輸 -> (保持連線) -> 資料傳輸 -> 關閉連線
  • 長/短連線的優缺點

    1. 長連線可以省去較多的TCP建立和關閉操作,減少資源浪費,節省時間,對於比較頻繁的請求資源的客戶端比較適用於長連線
    2. 短連線對於伺服器來說管理較為簡單,存在的連線都是有用的連線,不需要額外的控制手段

從瀏覽器輸入域名到展示頁面都發生了什麼

  • DNS域名解析
    先找本地hosts檔案,檢查對應域名ip的關係,有則想ip地址傳送請求,沒有再去找DNS伺服器
  • 建立TCP連線
    拿到伺服器IP後,向伺服器傳送求求,三次握手,建立TCP連線
    簡單理解三次握手:
    客戶端:您好,在家不,有你快遞
    服務端:在的,送來吧
    客戶端:好滴,來了
  • 傳送HTTP請求
    與伺服器建立連線後,就可以向伺服器發起請求了。具體請求內容可以在瀏覽器中檢視
  • 伺服器處理請求
    伺服器收到請求後由web伺服器(Apache,Nginx)處理請求,web伺服器解析使用者請求,知道了需要呼叫那些資原始檔,再通過相應的這些資原始檔處理使用者請求和引數,並呼叫資料庫等,然後將結果通過web伺服器返回給瀏覽器
  • 返回響應結果
    在響應結果中都會有一個HTTP狀態碼,諸如我們熟知的200、404、500等
    狀態碼都是由三位數字和原因短語組成,大致為五類:
    1XX 資訊性狀態碼 接收的請求正在處理
    2XX 成功狀態碼 請求正常處理完畢
    3XX 重定向狀態碼 需要附加操作以完成請求
    4XX 客戶端錯誤狀態碼 伺服器也無法處理的請求
    5XX 伺服器錯誤狀態碼 伺服器請求處理出錯
  • 關閉TCP連線
    為了避免伺服器與客戶端雙方資源佔用和消耗,當雙方沒有請求或者響應傳遞時,任意一方都可以發起關閉請求,與建立TCP連線的三次握手類似,關閉TCP連線需要4次揮手
    簡單比喻為:
    客戶端:哥們,我這邊沒有資料要傳了,咱們關閉連線吧
    服務端:好的,我看看我這邊還有資料不
    服務端:兄弟,我這邊也沒資料要傳給你了,咱們可以關閉連線了
    客戶端:好嘞
  • 瀏覽器解析HTML
  • 瀏覽器佈局渲染

設計模式

設計模式是一套被反覆使用、多數人知曉的、經過分類編目的、程式碼設計經驗的總結。使用設計模式是為了可重用程式碼、讓程式碼更容易被他人理解、保證程式碼可靠性。

單例模式

當需要保證物件只有一個例項的時候,單例模式是非常有用的。他把建立物件的控制權交給一個單一的點上,任何時候應用程式都只會存在且僅存在一個例項。單例類不應該能在類的外部進行例項化。一個單例類應該具備以下幾個因素:

  • 必須擁有一個訪問級別為private的建構函式,用於阻止類被隨意例項化
  • 必須擁有一個儲存類的例項的靜態變數
  • 必須擁有一個訪問這個例項的公共靜態方法,該方法通常被命名為getInstance()
  • 必須擁有一個私有的空的clone方法,防止例項被克隆複製

簡單例項:


class Single
{
    public static $_instance;

    private function __construct()
    {
    }

    private function __clone()
    {
    }

    public static function getInstance()
    {
        if (!self::$_instance) {
            self::$_instance = new self();
        }
        return self::$_instance;
    }

    public function sayHi()
    {
        echo "Hi \n";
    }
}

$single = Single::getInstance();
$single->sayHi();

工廠模式

工廠模式解決的是如何不通過new建立例項物件的方法

工廠模式是一種類,它具有為你建立物件的某些方法,你可以使用工廠類建立物件而不使用new。這樣,如果你想要更改所建立的物件型別只需要更改工廠即可,使用該工廠的所有程式碼會自動更改。

工廠模式往往配合介面一起使用,這樣應用程式就不必要知道這些被例項化的類的具體細節,只要知道工廠返回的是支援某個介面的類就可以方便的使用了。

簡單舉例:



/**
 * 抽象出一個人的介面
 * Interface Person
 */
interface Person
{
    public function showInfo();
}

/**
 * 一個繼承於抽象人介面的學生類
 * Class Student
 */
class Student implements Person
{
    public function showInfo()
    {
        echo "這是一個學生 \n";
    }
}

/**
 * 一個繼承於抽象人介面的老師類
 * Class Teacher
 */
class Teacher implements Person
{
    public function showInfo()
    {
        echo "這是一個老師 \n";
    }
}

/**
 * 人類工廠
 * Class PersonFactory
 */
class PersonFactory
{
    public static function factory($person_type)
    {
        // 將傳入的型別首字母大寫
        $class_name = ucfirst($person_type);

        if(class_exists($class_name)){
            return new $class_name;
        }else{
            throw  new Exception("類:$class_name 不存在",1);
        }
    }
}

// 需要一個學生
$student = PersonFactory::factory('student');
echo $student->showInfo();

// 需要一個老師的時候
$teacher = PersonFactory::factory('teacher');
echo $teacher->showInfo();

快取相關

Redis和Memcached的區別

  • Redis和Memcache都是將資料存放在記憶體中,都是記憶體資料庫。但是Memcache還可以快取其他東西,比如圖片、視訊
  • Redis不只支援簡單的k/v型別的資料,同時還提供list、set、hash等資料結構的儲存
  • 虛擬記憶體,當實體記憶體用完時Redis可以將一些很久沒有用到的value交換到磁碟
  • 過期策略,memcache在set時就指定,例如set key1 0 0 8即永不過期,redis可以通過expire設定,例如:expire name 10
  • 分散式,設定memcache叢集,利用magent做一主多從;redis也可以做一主多從。
  • 儲存安全,memcache掛掉後,資料沒了;redis可以定期儲存在磁碟(持久化)
  • 災難恢復,memcache掛掉後資料不可恢復;redis資料丟失後可以通過aof恢復
  • redis支援資料的備份,即master-slave模式的資料備份
  • 應用場景不同:redis除了可以做nosql資料庫之外,還能做訊息佇列、資料堆疊和資料快取等。memcache適合於快取sql語句、資料集、使用者臨時性資料、延遲查詢資料和session等

redis有哪些資料結構

  • String
    字串型別是redis最基礎的資料結構,首先鍵是字串型別,而且其他幾種結構都是在字串型別基礎上構建的
    字串型別實際上可以是字串、數字、二進位制(圖片、音訊),單最大不能超過512M
    使用場景:

    1. 快取
      字串最經典的使用場景,redis作為快取層,mysql作為儲存層,絕大部分請求資料都是redis中獲取,由於redis具有支撐高併發特性,所以快取通常能起到加速讀寫和降低後端壓力的作用
    2. 計數器
      許多應用都會使用redis作為技術的基礎工具,它可以實現快速技術、查詢快取的功能。
    3. 共享session
      處於負載均衡的考慮,分散式服務會將使用者資訊的訪問均衡到不同伺服器,使用者重新整理一次訪問可訥訥個會需要重新登入,為了避免這個問題可以使用redis將使用者session集中管理,在這種模式下只要保證redis的高可用和擴充套件性,每次獲取使用者更新或查詢登入資訊都直接從redis中集中獲取
    4. 限速
      出於安全考慮,每次進行登入時讓使用者輸入手機驗證碼,為了簡訊介面不被頻繁訪問,會限制使用者每分鐘獲取驗證碼的頻率
  • Hash
    在redis中雜湊型別是指鍵本身又是一種鍵值對結構,如value = {{field1,value1}...{fieldn,valuen}}
    使用場景:

    1. 雜湊結構相對於字串序列化快取資訊更加直觀,並且在更新操作上更加便捷。
  • list
    列表型別是用來儲存多個有序的字串,列表的每個字串成為一個元素,一個列表最多可以儲存2的32次方減1個元素。在redis中,可以對列表插入(push)和彈出(pop),還可以獲取指定範圍的元素列表。列表是一種比較靈活的資料結構,它可以充當棧和佇列的角色。
    使用場景:

    1. 訊息佇列
      redis的lpush+brpop命令組合就可以實現阻塞佇列,生產者客戶端是用lpush從列表左側插入元素,多個消費者客戶端使用brpop命令阻塞式的搶列表尾部的元素,多個客戶端保證了消費的負載均衡的高可用性。
    2. 使用技巧列表

      lpush+lpop=Stack(棧)
      lpush+rpop=Queue(佇列)
      lpush+ltrim=Capped Collection(有限集合)
      lpush+brpop=Message Queue(訊息佇列)
  • set
  • sortedset

redis是單執行緒的麼,為什麼

因為CPU並不是Redis的瓶頸,Redis的瓶頸最有可能是機器記憶體或者網路頻寬。既然單執行緒容易實現,而且CPU不會成為瓶頸,那麼久順理成章的採用了單執行緒的方案。

當然單個Redis程序是沒辦法使用多核的 ,但是它來就不是非常計算密集型的服務。如果單核效能不夠用,可以多開幾個程序。

redis的部署方式,主從、叢集

參考文章:segmentfault.com/a/11...

redis的哨兵模式

參考文章:www.cnblogs.com/xifen...

redis的持久化策略

  • RDB(快照持久化)
  • AOF(只追加檔案持久化)

參考文章:segmentfault.com/a/11...

PHP基礎

  1. 雙引號單引號區別

    • 雙引號解釋變數,單引號不解釋變數
    • 雙引號裡插入單引號,其中單引號裡如果有變數的話,變數解釋
    • 雙引號的變數名後面必須要有一個非數字、字母、下劃線的特殊字元,或者用{}講變數括起來,否則會將變數名後面的部分當做一個整體,引起語法錯誤
    • 能使單引號字元儘量使用單引號,單引號的效率比雙引號要高
  2. GET和POST提交方式的區別

    • GET產生一個TCP資料包;POST產生兩個TCP資料包;
      對於GET方式的請求,瀏覽器會把http header和data一併傳送出去,伺服器響應200(返回資料)
      對於POST,瀏覽器先發送header,伺服器響應100 continue,瀏覽器再發送data,伺服器響應200 ok(返回資料)。
    • GET在瀏覽器回退時是無害的,而POST會再次提交請求
    • GET請求會被瀏覽器主動cache,而POST不會,除非手動設定
    • GET請求引數會被完整保留在瀏覽器歷史記錄裡,而POST中的引數不會被保留
    • GET請求只能進行url編碼,而POST支援多種編碼方式
    • GET比POST更不安全,因為引數直接暴露在URL上,所以不能用來傳遞敏感資訊
  3. 如何獲取客戶端的真實ip
    $_SERVER['REMOTE_ADDR']或getenv('REMOTE_ADDR')
    可以使用ip2long()轉成數字
  4. include和require的區別
    require是無條件包含,也就是如果一個流程里加入require,無論條件成立與否都會先執行require,當檔案不存在或者無法開啟的時候,會提示錯誤,並且會終止程式執行
    include有返回值,而require沒有(可能因為如此require的速度比include快),如果被包含的檔案不存在的化,那麼會提示一個錯誤,但是程式會繼續執行下去

    注意:包含檔案不存在或者語法錯誤的時候require是致命的,而include不是

  5. AJAX的優勢是什麼
    ajax是非同步傳輸技術,可以通過javascript實現,也可以通過JQuery框架實現,實現區域性重新整理,減輕了伺服器的壓力,也提高了使用者體驗
  6. 在程式的開發中,如何提高程式的執行效率

    • 優化SQL語句,查詢語句中儘量不使用select *,用哪個欄位查哪個欄位;
    • 少用子查詢可用表連線代替;
    • 少用模糊查詢;
    • 資料表中建立索引;
    • 對程式中經常用到的資料生成快取;
  7. SESSION與COOKIE的區別

    • 儲存位置:session儲存在伺服器,cookie儲存在瀏覽器
    • 安全性:session安全性高於cookie
      參考連結:www.zhihu.com/questio...
  8. isset和empty的區別

    • isset()函式 一般用來檢測變數是否設定
      若變數不存在則返回 FALSE
      若變數存在且其值為NULL,也返回 FALSE
      若變數存在且值不為NULL,則返回 TURE
    • empty()函式是檢查變數是否為空
      若變數不存在則返回 TRUE
      若變數存在且其值為""、0、"0"、NULL、、FALSE、array()、var $var; 以及沒有任何屬性的物件,則返回 TURE
      若變數存在且值不為""、0、"0"、NULL、、FALSE、array()、var $var; 以及沒有任何屬性的物件,則返回 FALSE
  9. 資料庫三正規化

    • 第一正規化:1NF是對屬性的原子性約束,要求屬性具有原子性,不可再分解;
    • 第二正規化:2NF是對記錄的惟一性約束,要求記錄有惟一標識,即實體的惟一性;
    • 第三正規化:3NF是對欄位冗餘性的約束,即任何欄位不能由其他欄位派生出來,它要求欄位沒有冗餘。
  10. 主鍵、外來鍵和索引的區別

    • 定義
      主鍵--唯一標識一條記錄,不能有重複的,不允許為空
      外來鍵--表的外來鍵是另一表的主鍵, 外來鍵可以有重複的, 可以是空值
      索引--該欄位沒有重複值,但可以有一個空值
    • 作用
      主鍵--用來保證資料完整性
      外來鍵--用來和其他表建立聯絡用的
      索引--是提高查詢排序的速度
    • 個數
      主鍵--主鍵只能有一個
      外來鍵--一個表可以有多個外來鍵
      索引--一個表可以有多個唯一索引
  11. 堆和棧的區別
    棧是編譯期間就分配好的記憶體空間,因此你的程式碼中必須就棧的大小有明確的定義;
    堆是程式執行期間動態分配的記憶體空間,你可以根據程式的執行情況確定要分配的堆記憶體的大小。

PHP包管理器Composer與自動載入規範

composer學習地址:docs.phpcomposer.com/0...

composer.json中的自動載入對映

目前PSR-0自動載入、PSR-4自動載入、classmap生成和files引入都是被支援的,PSR-4是首推的方法,因為它提供了更大的易用性。

  • PSR-4
    PSR-4規範瞭如何指定檔案路徑從而自動載入類,同時規範了自動載入檔案的位置。乍一看這是和PSR-0重複了,實際上,在功能上確實有一部分重複。區別在於,PSR-4的規範比較乾淨,去除了相容PHP5.3以前版本的內容。
    PSR-4和PSR-0最大的區別是對下劃線的定義不同,PSR-4中,在類名中使用下劃線是沒有特殊含義的,而在PSR-0的規則中,下劃線或被轉化為目錄分隔符

    在PSR-4的鍵下,你可以定義名稱空間和路徑的對映關係,當自動載入類如Foo\\Bar\\Baz時,名稱空間Foo指向一個名為src/的目錄意味著自動載入器將查詢名為src/Bar/Baz.php檔案並引用它。

    名稱空間的字首必須以\\結尾,以避免類似字首之間的衝突。在安裝和更新期間,PSR-4引用全部組合到一個key=>value陣列中,該陣列可以在生成的檔案vendor/composer/autoload_psr4.php中找到。

    例子:

    {
      "autoload": {
        "psr-4": {
          "App\\": "App/" // 名稱空間App對映到目錄App
        }
      }
    }
  • classmap
    classmap引用的所有組合,都會在安裝、更新的過程中生成並存儲到vendor/composer/autoload_classmap.php檔案中。
    你可以使用classmap生成支援自定義載入的不遵循PSR-4規範的類庫,要配置它指向的目錄,以便能夠準確的搜尋到類檔案

    例子:

    {
      "autoload": {
        "classmap": ["src/", "lib/", "Something.php"]
      }
    }
  • Files
    如果你想要明確指定,在每次請求時都要載入某些檔案,那麼你可以使用files欄位載入。通常作為函式庫的載入方式。

    例子:

    {
      "autoload": {
        "files": ["src/MyLibrary/functions"]
      }
    }

PHP框架

Laravel相關

前端相關

JavaScript

VueJS

  • VueJs雙向資料繫結原理

Linux

Cors跨域

CORS的基本原理是通過設定HTTP請求和返回中header,告知瀏覽器該請求是合法的。這涉及到伺服器端和瀏覽器端雙方的設定:請求的發起(Http Request Header)和伺服器對請求正確的響應(Http response header)。

對PHP後端技術,對PHP架構技術感興趣的朋友,我的官方群1023755567點選此處,一起學習,相互討論。

PHP進階學習思維導圖、面試;文件、視訊資源免費獲取​kdocs.cn

群內已經有管理將知識體系整理好(原始碼,學習視訊等資料),歡迎加群免費領取。

部分資料截圖如下: