'php 中高級面試題(經典)'

"

近來看了許多PHP面試題,有的題目有答案,有的沒有。還是決心全部記錄一下,部分答案是借鑑網上的資料,部分是自己總結。有的題目可能有冗餘,有的答案不是很細化,哪裡總結的不完整或不正確,歡迎大家留言指正,補充。

1. Mysql常用優化方法 有哪些,請儘可能列出?

答:選取合適的字段屬性 ; 儘量把字段設置為not null;儘量少用join,少用子查詢,如果有多表業務邏輯需求,儘量使用程序解決數據整合問題,單表查詢數據,然後整合,將壓力放在程序上(服務層),而不是數據層;使用UNION代替手動創建的臨時表; 鎖定表;合理使用索引(注意sql語句的寫法,儘量避免索引失效);少用like這種查詢語句,雖然很方便,但是是以消耗系統性能為代價的。

2. mysql 數據庫表的類型有哪些?

答: MyISAM、InnoDB、HEAP、BOB、ARCHIVE、CSV等

常用的2種:MyISAM、InnoDB

MyISAM:成熟、穩定、易於管理,快速讀取。一些功能不支持(事務等),表級鎖。

InnoDB:支持事務、外鍵等特性、數據行鎖定。空間佔用大,不支持全文索引等。

3. 如何預防sql注入?

答: 目前好多框架中自帶的數據庫操作model已經集成了sql注入預防功能,底層一般都是使用pdo面向對象預編譯執行。

如果使用mysqli原生連接的話,可以使用過濾函數,過濾字符,轉義字符等方法。

例如:strip_tags(),mysql_escape_string(),htmlspecialchars()等函數進行過濾

4. 談談悲觀鎖與樂觀鎖的區別與聯繫?

答:

悲觀鎖:顧名思義,就是很悲觀,每次去拿數據的時候都認為別人會修改,所以每次在拿數據的時候都會上鎖,這樣別人想拿這個數據就會block直到它拿到鎖。

傳統的關係型數據庫裡邊就用到了很多這種鎖機制,比如行鎖,表鎖等,讀鎖,寫鎖等,都是在做操作之前先上鎖。

樂觀鎖: 顧名思義,就是很樂觀,每次去拿數據的時候都認為別人不會修改,所以不會上鎖,但是在更新的時候會判斷一下在此期間別人有沒有去更新這個數據,可以使用版本號等機制。

樂觀鎖適用於多讀的應用類型,這樣可以提高吞吐量,像數據庫如果提供類似於write_condition機制的其實都是提供的樂觀鎖。

悲觀鎖和樂觀鎖的區別:

兩種鎖各有優缺點,不可認為一種好於另一種,像樂觀鎖適用於寫比較少的情況下,即衝突真的很少發生的時候,這樣可以省去了鎖的開銷,加大了系統的整個吞吐量。但如果經常產生衝突,上層應用會不斷的進行retry,這樣反倒是降低了性能,所以這種情況下用悲觀鎖就比較合適。

5. 如何處理系統的高併發,高負載?

答:

1. html文件儘量靜態化

2. 客戶端(一般是APP與瀏覽器) 儘量使用本地緩存 ,減少調用服務端接口次數

3. 客戶端(一般是APP與瀏覽器) 限制訪問接口頻次(例如某個按鈕連續被點擊.......)

4. 圖片服務器分離,把圖片,視頻資源放在單獨的文件服務器上,減少主服務器的網絡開銷,例如放在阿里雲的oss上(很方便,例如圖片的壓縮,裁剪,視頻的封面圖獲取等等操作很方便,當然oss也有一定的費用.....)

5. 數據庫集群,可以讀寫分離,主從複製。

6. 使用緩存,例如redis,在服務層與數據層中間加入緩存層,讓請求盡最大的可能訪問緩存(命中緩存),減少數據庫的訪問

7. 使用負載均衡,可以使用nginx作為反向代理負載均衡器,apache集群(當然並不是只有nginx這一種方式),因為nginx處理高併發比較好,apache的穩定性又比較好,二者結合,比較合適。

8. 站點層攔截,例如,同一個用戶,同一個請求,幾秒之內只能請求幾次,可以使用緩存實現,使用緩存記錄時間信息,(相當於限流,限速....), 此種限制方式,建議還是在服務端的接口入口處加上吧,因為和我們後端合作的客戶端(app,web),往往不會考慮這些負載啊,速度啊,壓力之類的事情,往往調用接口不合理(如果客戶端沒有架構師指導的話)。

6. session 與cookie的區別?

答:

cookie數據存放在第三方應用的瀏覽器上,session數據放在服務器上。

cookie不是很安全,別人可以分析存放在本地的COOKIE,進行COOKIE欺騙,考慮到安全應當使用session。

session會在一定時間內保存在服務器上。當訪問增多,會比較佔用你服務器的性能,考慮到減輕服務器性能方面,應當使用COOKIE。

單個cookie保存的數據不能超過4K,很多瀏覽器都限制一個站點最多保存20個cookie。

session的過期時間,指的是靜默時間,例如:某個用戶的登錄session設置的是20分鐘過期時間,如果前18分鐘用戶都沒有任何操作,在第19分鐘訪問了session,有了操作,那麼,過期時間重新計算,從0開始計數。而cookie設置了20分鐘,無論有無訪問,20分鐘到了,就是過期了

另外 session可以設置存放形式,默認是文件(file)形式,可以設置為user形式,將session放在緩存或數據庫中。

7. php的魔術方法有哪些?

答:

__construct() 實例化對象時被調用,當__construct和以類名為函數名的函數同時存在時,__construct將被調用,另一個不被調用。

__destruct() 當刪除一個對象或對象操作終止時被調用。

__call() 對象調用某個方法,若方法存在,則直接調用;若不存在,則會去調用__call函數。(此方法工作中很常見,很常用)

__get() 讀取一個對象的屬性時,若屬性存在,則直接返回屬性值;若不存在,則會調用__get函數。

__set() 設置一個對象的屬性時,若屬性存在,則直接賦值;若不存在,則會調用__set函數。

__toString() 打印一個對象的時被調用。如echo $obj;或print $ob

__clone() 克隆對象時被調用。如:$t=new Test();$t1=clone $t;

__sleep() serialize(序列化)之前被調用。若對象比較大,想刪減一點東東再序列化,可考慮一下此函數。

__wakeup() unserialize(反序列化)時被調用,做些對象的初始化工作。

__isset() 檢測對象一個不存在的屬性時被調用。如:isset($c->name)。

__unset() 刪除對象一個不存在的屬性時被觸發。如:unset($c->name)。

__set_state() 調用var_export時,被調用。用__set_state的返回值做為var_export的返回值。

__autoload() 實例化一個對象時,如果對應的類不存在,則該方法被調用。(此方法,工作中很常用,尤其自己封一個框架用的時候,避免需要引入很多類文件,可以使用此方法)

8. 請手寫一個冒泡排序

答:直接上代碼了,我寫的這個方法,還可以優化............

/**

* 冒泡排序

* TODO 核心思想,相鄰的2個值,進行比較,如果後一個值大於前一個值,將此時2個位置的值,進行互換

*/

function maoPaoSort($arr){

if(!is_array($arr)){

return false;

}

$len = count($arr);

$lenSon = $len-1;

for($i=0;$i<$len;$i++){

for($j=0;$j<$lenSon;$j++){

//TODO 每次進來,就可以將比較大的值向上冒一位

if($arr[$j]>$arr[$j+1]){

//將大的值,臨時保存起來

$tempData = $arr[$j];

$arr[$j] = $arr[$j+1];

$arr[$j+1] = $tempData;

}

}

}

return $arr;

}

$arr = [100,80,70,200,60,40,90];

var_dump(maoPaoSort($arr))

9. redis 與memcacahe、mongoDB的區別與聯繫?

答:都是非關係型數據庫,性能都非常高,但是mongoDB和memcache、redis是不同的兩種類型。後兩者主要用於數據的緩存,前者主要用在查詢和儲存大數據方面,是最接近數據庫的文檔型的非關係數據庫。

從數據存儲位置上來分,memcache的數據存在內存中,而redis既可以存儲在內存中,也可以存儲的到磁盤中,達到持久化存儲的功能,memcache一旦斷電,數據全部丟失,redis可以利用快照和AOF把數據存到磁盤中,當恢復時又從磁盤中讀取到內存中,當物理內存使用完畢後,可以把數據寫入到磁盤中。

從存儲數據的類型上來分,memcache和redis存儲的方式都是鍵值對,只不過redis值的類型比較豐富,有string(字符串),hash(哈希),list(列表),set(集合)zset(有序集合),而memcache主要存儲的是字符串

從架構層次來分,Redis支持master-slave(主—從)模式應用,memcache支持分佈式。

從存儲數據的大小上來分,Redis單個value的最大限制是1GB,memcached只能保存1MB的數據。但是Memcache在存儲100K以上的數據,性能稍微好一點。

另外redis只支持單核,memcache可以支持多核,當然關於redis取代memcache的說法,在一般情況下,兩者性能都很高,在大多的業務場景選擇上,redis的選擇可能更加具有優勢,因為其存儲的類型相對比較豐富,例如隊列,在工作中比較常用。

10. $this和self、parent 這3個此分別代表什麼,在哪些場景下使用?

$this 當前對象

self 當前類

parent 當前類的父類

$this 在當前類中使用,使用->調用屬性和方法。

self 也在當前類中使用,不過需要使用::調用。

parent 在類中使用。

11. redis單線程有什麼優勢與缺點?

優點:

1. 代碼更清晰,處理邏輯更簡單

2. 不用去考慮各種鎖的問題,不存在加鎖釋放鎖操作,沒有因為可能出現死鎖而導致的性能消耗

3. 不存在多進程或者多線程導致的切換而消耗CPU

缺點:

因為是單線程的,無法發揮多核cpu的優勢,容易阻塞。

12. php 的運行模式有哪些?

答:

1)cgi 通用網關接口(Common Gateway Interface))

2) fast-cgi 常駐 (long-live) 型的 CGI

3) cli 命令行運行 (Command Line Interface)

4)web模塊模式 (apache等web服務器運行的模塊模式)

具體參考資料:https://www.cnblogs.com/liangxiaofeng/p/5339557.html

13. apache和nginx的區別(轉)?

答:

Nginx:

輕量級,採用 C 進行編寫,同樣的 web 服務,會佔用更少的內存及資源

抗併發,nginx 以 epoll and kqueue 作為開發模型,處理請求是異步非阻塞的,負載能力比 apache 高很多,而 apache 則是阻塞型的。在高併發下 nginx 能保持低資源低消耗高性能 ,而 apache 在 PHP 處理慢或者前端壓力很大的情況下,很容易出現進程數飆升,從而拒絕服務的現象。

nginx 處理靜態文件能力較好

nginx 的設計高度模塊化,編寫模塊相對簡單

nginx 配置簡潔,正則配置讓很多事情變得簡單,而且改完配置能使用 -t 測試配置有沒有問題,apache 配置複雜 ,重啟的時候發現配置出錯了,會很崩潰(這一點確實是深受其害啊...........)

nginx 作為負載均衡服務器,支持 7 層負載均衡

nginx 本身就是一個反向代理服務器,而且可以作為非常優秀的郵件代理服務器

Apache:

apache 的 rewrite 比 nginx 強大,在 rewrite 頻繁的情況下,考慮用 apache

apache 模塊超多,基本想到的都可以找到

apache 更為成熟,少 bug ,nginx 的 bug 相對較多

apache 穩定性特別好

apache 對 PHP 支持比較簡單,nginx 需要配合其他後端用

apache 在處理動態請求有優勢,nginx 在這方面是雞肋,一般動態請求要 apache 去做,nginx 適合靜態和反向。

總結:

兩者最核心的區別在於 apache 是同步多進程模型,一個連接對應一個進程,而 nginx 是異步的,多個連接(萬級別)可以對應一個進程

一般來說,需要性能的 web 服務,用 nginx 。如果不需要性能只求穩定,更考慮 apache ,後者的各種功能模塊實現得比前者,例如 ssl 的模塊就比前者好,可配置項多。epoll(freebsd 上是 kqueue ) 網絡 IO 模型是 nginx 處理性能高的根本理由,但並不是所有的情況下都是 epoll 大獲全勝的,如果本身提供靜態服務的就只有寥寥幾個文件,apache 的 select 模型或許比 epoll 更高性能。當然,這只是根據網絡 IO 模型的原理作的一個假設,真正的應用還是需要實測了再說的。

更為通用的方案是,前端 nginx 抗併發,後端 apache 集群,配合起來會更好。

14.nginx的epoll模型的介紹以及io多路複用模型

連接:http://www.mamicode.com/info-detail-2283798.html

15. 如何查看sql語句是否使用了索引?

此方法,個人認為對於mysql索引優化很有用處,可以作為其中一個判斷依據,去判斷sql語句是否合理。

答:使用explain 關鍵字

例如: select * from bu_course_lesson => explain select * from bu_course_lesson 通過查看結果的type值可以看出,如果type是all那麼就沒有使用索引

16 . foreach 與for循環的對比

對於for循環來說,每一次都要判斷$i 是否到達長度,小於繼續,否則終止循環;

對於foreach來說,它依賴於 IEnumerable(迭代器), 第一次 var a in GetList() 時 調用 GetEnumerator 返回第一個對象 並 賦給a,以後每次再執行 var a in GetList() 的時候 調用 MoveNext.直到循環結束,期間GetList()方法只執行一次.

在固定長度或長度不需要計算的時候for循環效率高於foreach.

在不確定長度,或計算長度有性能損耗的時候,用foreach比較方便.

並且foreach的時候會鎖定集合中的對象.期間不能修改.

17. php的fpm進程管理器的三種模式,優缺點是什麼?

https://blog.csdn.net/tzhennan/article/details/84920895

18 .serialize() /unserialize()函數的作用?

serialize()和unserialize()在php手冊上的解釋是:

serialize — 產生一個可存儲的值的表示,返回值為字符串,此字符串包含了表示 value 的字節流,不丟失其類型和結構,可以存儲於任何地方。

unserialize — 從已存儲的表示中創建 PHP 的值

這2個方法在數組或對象放入緩存時,推介使用。例如將數組放入redis緩存,應該將數組序列化,再放入,不建議使用json_encode() 方法。

19. PHP處理上傳文件信息數組中的文件類型$_FILES[‘type’]由客戶端瀏覽器提供,有可能是黑客偽造的信息,請寫一個函數來確保用戶上傳的圖像文件類型真實可靠?

答:用getimagesize()函數來判斷上傳圖片的類型比$_FILES函數的type更可靠。同一個文件,使用不同的瀏覽器php返回的type類型是不一樣的,由瀏覽器提供type類型的話,就有可能被黑客利用向服務器提交一個偽裝撐圖片後綴的可執行文件。

<?php

$file=$_FILES['file'];

if(!empty($file))

{

var_dump($file);

var_dump(getimagesize($file["tmp_name"]));

}

?>

20 .寫出、你能想到的所有HTTP返回狀態值,並說明用途?

答:

200 (成功) 服務器已成功處理了請求。 通常,這表示服務器提供了請求的網頁。

301 (永久移動) 請求的網頁已永久移動到新位置。 服務器返回此響應(對 GET 或 HEAD 請求的響應)時,會自動將請求者轉到新位置。

302 (臨時移動) 服務器目前從不同位置的網頁響應請求,但請求者應繼續使用原有位置來進行以後的請求。

401 (未授權) 請求要求身份驗證。 對於需要登錄的網頁,服務器可能返回此響應。

403 (禁止) 服務器拒絕請求。

404 (未找到) 服務器找不到請求的網頁。

500 (服務器內部錯誤) 服務器遇到錯誤,無法完成請求。

501 (尚未實施) 服務器不具備完成請求的功能。 例如,服務器無法識別請求方法時可能會返回此代碼。

502 (錯誤網關) 服務器作為網關或代理,從上游服務器收到無效響應。

503 (服務不可用) 服務器目前無法使用(由於超載或停機維護)。 通常,這只是暫時狀態。

504 (網關超時) 服務器作為網關或代理,但是沒有及時從上游服務器收到請求。

505 (HTTP 版本不受支持) 服務器不支持請求中所用的 HTTP 協議版本。

21. php 的垃圾回收機制是什麼樣的?

答:PHP可以自動進行內存管理,清除不再需要的對象。PHP使用了引用計數(referencecounting)這種單純的垃圾回收(garbagecollection)機制。每個對象都內含一個引用計數器,每個reference連接到對象,計數器加1。當reference離開生存空間或被設為NULL,計數器減1。當某個對象的引用計數器為零時,PHP知道你將不再需要使用這個對象,釋放其所佔的內存空間。

"

相關推薦

推薦中...