2021年最新PHP 面試、筆試題匯總(二)
二十一、語句include和require的區(qū)別
require是無條件包含,也就是如果一個流程里加入require,無論條件成立與否都會先執(zhí)行require,當(dāng)文件不存在或者無法打開的時候,會提示錯誤,并且會終止程序執(zhí)行
include有返回值,而require沒有(可能因為如此require的速度比include快),如果被包含的文件不存在的化,那么會提示一個錯誤,但是程序會繼續(xù)執(zhí)行下去
注意:包含文件不存在或者語法錯誤的時候require是致命的,而include不是
require_once,include_once表示了只包含一次,避免了重復(fù)包含
?
二十二、php中傳值與傳引用的區(qū)別,并說明傳值什么時候傳引用
變量默認(rèn)總是傳值賦值,那也就是說,當(dāng)將一個表達(dá)式的值賦予一個變量時,整個表達(dá)式的值被賦值到目標(biāo)變量,這意味著:當(dāng)一個變量的賦予另外一個變量時,改變其中一個變量的值,將不會影響到另外一個變量
php也提供了另外一種方式給變量賦值:引用賦值。這意味著新的變量簡單的引用(換言之,成為了其別名或者指向)了原始變量。改動的新的變量將影響到原始變量,反之亦然。
使用引用賦值,簡單地將一個&符號加到將要賦值的變量前(源變量)
對象默認(rèn)是傳引用
對于較大的數(shù)據(jù),可以考慮傳引用,這樣可以節(jié)省內(nèi)存的開銷
?
二十三、PHP 不使用第三個變量實現(xiàn)交換兩個變量的值
//方法一$a.=$b;$b=str_replace($b,"",$a);$a=str_replace($b,"",$a);//方法二list($b,$a)=array($a,$b);var_dump($a,$b);
二十四、mysql優(yōu)化
MySQL查詢SQL優(yōu)化
?
二十五、redis 和 memache 緩存的區(qū)別
1.數(shù)據(jù)類型
redis支持多種數(shù)據(jù)類型(5種):hash string list set zset
memcache 只支持key-value
2.持久性
redis 支持兩種持久化方式 RDB、AOF
memcache 不支持持久化
3.分布式存儲
redis支持master-slave復(fù)制模式
memcache可以使用一致性hash做分布式
4.value大小不同
memcache是一個內(nèi)存緩存,key的長度小于250字符,單個item存儲要小于1M,不適合虛擬機(jī)使用
5.線程模型
memcache是master+worker的線程模型,其中master完成網(wǎng)絡(luò)監(jiān)聽后投遞到worker線程,由worker線程處理
redis是單進(jìn)程單線程模型,即單個線程完成所有的事情
這兩種實現(xiàn)造成下面的差異,即redis更容易實現(xiàn)多種數(shù)據(jù)結(jié)構(gòu),類似列表,集合,hash,有序集合等,由于是單線程的,如果單實例部署redis,不能全面用到服務(wù)器多核的優(yōu)勢,通常部署時,都會通過多實例的方式去部署
6.內(nèi)存管理
redis:redis沒有自己得內(nèi)存池,而是直接使用時分配,即什么時候需要什么時候分配,內(nèi)存管理的事交給內(nèi)核,自己只負(fù)責(zé)取和釋放,直接malloc和free即可。內(nèi)存管理沒有什么特殊的算法,通過使用google的jmalloc庫來做內(nèi)存管理(申請,釋放)
memcache:memcached是有自己得內(nèi)存池的,即預(yù)先分配一大塊內(nèi)存,然后接下來分配內(nèi)存就從內(nèi)存池中分配,這樣可以減少內(nèi)存分配的次數(shù),提高效率,這也是大部分網(wǎng)絡(luò)服務(wù)器的實現(xiàn)方式,只不過各個內(nèi)存池的管理方式根據(jù)具體情況而不同。使用了類似linux的內(nèi)存管理,即slab內(nèi)存管理方式。
7.其他
redis支持事務(wù),頻道(發(fā)布-訂閱),集群;memcache不支持
?
二十六、apche 和 nginx 的優(yōu)缺
nginx輕量級,比apache占用更少的內(nèi)存及資源,抗并發(fā)
nginx處理請求是異步非阻塞的,而apache 則是阻塞型的,在高并發(fā)下nginx 能保持低資源低消耗高性能。
apache 相對于nginx 的優(yōu)點:
rewrite比nginx 的rewrite 強(qiáng)大,少bug,穩(wěn)定。(需要性能用nginx,求穩(wěn)定就apache)。
?
二十七、一個函數(shù)的參數(shù)不能是對變量的引用,除非在php.ini中把 allow_call_time_pass_reference 設(shè)為on。
在PHP函數(shù)調(diào)用的時候,基本數(shù)據(jù)類型默認(rèn)會使用值傳遞,而不是引用傳遞。allow_call_time_pass_reference 選項的作用為是否啟用在函數(shù)調(diào)用時強(qiáng)制參數(shù)被按照引用傳遞。如果把a(bǔ)llow_call_time_pass_reference 配置為on,那么在函數(shù)調(diào)用的時候會默認(rèn)使用引用傳值。但是不推薦使用這種方法,原因是該方法在未來的版本中很可能不再支持。如果想使用引用傳遞,那么推薦在函數(shù)調(diào)用的時候顯式地使用&進(jìn)行引用傳遞。
?
二十八、什么是內(nèi)存管理?
內(nèi)存管理主要是指程序運行時對計算機(jī)內(nèi)存資源的分配、使用和釋放等技術(shù),內(nèi)存管理的目標(biāo)是高效、快速地分配內(nèi)存同時及時地釋放和回收內(nèi)存資源。內(nèi)存管理主要包括是否有足夠的內(nèi)存供程序使用,從內(nèi)存池中獲取可用內(nèi)存,使用后及時銷毀并重新分配給其他程序使用。
在PHP開發(fā)過程中,如果遇到大數(shù)組等操作,那么可能會造成內(nèi)存溢出等問題。一些常見的處理方法如下:
1)通過ini_set(‘memory_limit’,‘64M’)方法重置php可以使用的內(nèi)存大小,一般在遠(yuǎn)程主機(jī)上是不能修改php.ini文件的,只能通過程序設(shè)置。注:在safe_mode(安全模式)下,ini_set會失效。
2)另一方面可以對數(shù)組進(jìn)行分批處理,及時銷毀無用的變量,盡量減少靜態(tài)變量的使用,在需要數(shù)據(jù)重用時,可以考慮使用引用(&)。同時對于數(shù)據(jù)庫、文件操作完要及時關(guān)閉,對象使用完要及時調(diào)用析構(gòu)函數(shù)等。
3)及時使用unset()函數(shù)釋放變量,使用時需要注意以下兩點:
① unset()函數(shù)只能在變量值占用內(nèi)存空間超過256字節(jié)時才會釋放內(nèi)存空間。
② 只有當(dāng)指向該變量的所有變量都銷毀后,才能成功釋放內(nèi)存。
?
二十九、Memcache的特征和特性
1)協(xié)議簡單。
2)基于libevent的事件處理。
3)內(nèi)置內(nèi)存存儲方式。
4)Memcached不互相通信的分布式。
(1)單個item 最大的數(shù)據(jù)為1MB。
(2)單進(jìn)程最大的使用內(nèi)存為2GB,需要更多內(nèi)存時可開多個端口。
(3)Memcached是多線程,非阻塞io復(fù)用的網(wǎng)絡(luò)模型,Redis是單線程。
(4)鍵長最大為250字節(jié)。
?

三十、共享Session的方式
1)基于NFS的Session共享。NFS(Network File System)最早由Sun公司為解決Unix網(wǎng)絡(luò)主機(jī)間的目錄共享而研發(fā)。僅需將共享目錄服務(wù)器mount到其他服務(wù)器的本地session目錄即可。
2)基于數(shù)據(jù)庫的Session共享。
3)基于Cookie的Session共享。原理是將全站用戶的Session信息加密、序列化后以Cookie的方式,統(tǒng)一種植在根域名下(如:.host.com),利用瀏覽器訪問該根域名下的所有二級域名站點時,會傳遞與之域名對應(yīng)的所有Cookie內(nèi)容的特性,從而實現(xiàn)用戶的Cookie化Session 在多服務(wù)間的共享訪問。
4)基于緩存(Memcache)的Session共享。Memcache是一款基于Libevent多路異步I/O技術(shù)的內(nèi)存共享系統(tǒng),簡單的key + value數(shù)據(jù)存儲模式使得代碼邏輯小巧高效,因此在并發(fā)處理能力上占據(jù)了絕對優(yōu)勢,目前能達(dá)到2000/s平均查詢,并且服務(wù)器CPU消耗依然不到10%。
?
三十一、memcache或redis雪崩如何解決?
造成原因:通常,在一個網(wǎng)站里,mysql數(shù)據(jù)庫處理的請求比較少(20%),負(fù)載80%,緩存技術(shù)處理大多數(shù)請求(80%)
如果memcache或redis掛掉,所有請求都會在mysql處理,數(shù)據(jù)庫的處理能力不足會直接宕機(jī)。這時候就算重啟緩存和mysql也是無濟(jì)于事的,因為緩存重啟后,數(shù)據(jù)已經(jīng)丟失,數(shù)據(jù)請求還是會走mysql,mysql還是會死掉(死循環(huán))
解決方法:
緩存預(yù)熱
1:先啟動緩存,再啟動數(shù)據(jù)庫。(但是此時不提供對外服務(wù))
2:通過一個PHP腳本把常用的key寫入緩存中
3:開放對外服務(wù)【熱點數(shù)據(jù)已經(jīng)緩存,請求會被緩存處理,減輕mysql壓力】
?
三十二、Redis持久化的方式?
1.Aof(append only file)
redis執(zhí)行命令時,會把我們執(zhí)行的命令通過日志形式進(jìn)行追加。安全性高,但是影響性能。
2.Rdb
按照制定規(guī)則進(jìn)行持久化
save 900 1 (900s內(nèi)1次redis操作 會做一次持久化)
save 300 10 (300s內(nèi)10次redis操作 會做一次持久化)
save 60 10000 (60s內(nèi)10000次redis操作 會做一次持久化)
但是可能會存在數(shù)據(jù)丟失,比如:12:00做過一次持久化,正常的話,12:15會再做持久化,如果12:14緩存死掉,那么14分鐘的數(shù)據(jù)會丟失。不大安全,但是性能比aof好很多
?
三十三、Linux系統(tǒng)中,進(jìn)程間通信的方式。
管道:
管道分為有名管道和無名管道
無名管道是一種半雙工的通信方式,數(shù)據(jù)只能單向流動,而且只能在具有親緣關(guān)系的進(jìn)程間使用.進(jìn)程的親緣關(guān)系一般指的是父子關(guān)系。無明管道一般用于兩個不同進(jìn)程之間的通信。當(dāng)一個進(jìn)程創(chuàng)建了一個管道,并調(diào)用fork創(chuàng)建自己的一個子進(jìn)程后,父進(jìn)程關(guān)閉讀管道端,子進(jìn)程關(guān)閉寫管道端,這樣提供了兩個進(jìn)程之間數(shù)據(jù)流動的一種方式。
有名管道也是一種半雙工的通信方式,但是它允許無親緣關(guān)系進(jìn)程間的通信。
消息隊列:
消息隊列是消息的鏈表,存放在內(nèi)核中并由消息隊列標(biāo)識符標(biāo)識.消息隊列克服了信號傳遞信息少,管道只能承載無格式字節(jié)流以及緩沖區(qū)大小受限等特點.消息隊列是UNIX下不同進(jìn)程之間可實現(xiàn)共享資源的一種機(jī)制,UNIX允許不同進(jìn)程將格式化的數(shù)據(jù)流以消息隊列形式發(fā)送給任意進(jìn)程.對消息隊列具有操作權(quán)限的進(jìn)程都可以使用msget完成對消息隊列的操作控制.通過使用消息類型,進(jìn)程可以按任何順序讀信息,或為消息安排優(yōu)先級順序.
信號:
信號是一種比較復(fù)雜的通信方式,用于通知接收進(jìn)程某個事件已經(jīng)發(fā)生.
信號量:
信號量是一個計數(shù)器,可以用來控制多個線程對共享資源的訪問.,它不是用于交換大批數(shù)據(jù),而用于多線程之間的同步.它常作為一種鎖機(jī)制,防止某進(jìn)程在訪問資源時其它進(jìn)程也訪問該資源.因此,主要作為進(jìn)程間以及同一個進(jìn)程內(nèi)不同線程之間的同步手段.
共享內(nèi)存:
共享內(nèi)存就是映射一段能被其他進(jìn)程所訪問的內(nèi)存,這段共享內(nèi)存由一個進(jìn)程創(chuàng)建,但多個進(jìn)程都可以訪問.共享內(nèi)存是最快的IPC(進(jìn)程間通信)方式,它是針對其它進(jìn)程間通信方式運行效率低而專門設(shè)計的.它往往與其他通信機(jī)制,如信號量,配合使用,來實現(xiàn)進(jìn)程間的同步與通信.
socket:
可用于不同及其間的進(jìn)程通信
文件,互斥量等,不過我在swoole源碼中看到了通過eventfd這種方式做進(jìn)程通信的
?
三十四、海量數(shù)據(jù)處理相關(guān)總結(jié)
1、海量日志數(shù)據(jù),提取出某日訪問百度次數(shù)最多的那個IP。
算法思想:分而治之+Hash
IP地址最多有2^32=4G種取值情況,所以不能完全加載到內(nèi)存中處理
可以考慮采用“分而治之”的思想,按照IP地址的Hash(IP)%1024值,把海量IP日志分別存儲到1024個小文件中。這樣,每個小文件最多包含4MB個IP地址
對于每一個小文件,可以構(gòu)建一個IP為key,出現(xiàn)次數(shù)為value的Hash map,同時記錄當(dāng)前出現(xiàn)次數(shù)最多的那個IP地址
可以得到1024個小文件中的出現(xiàn)次數(shù)最多的IP,再依據(jù)常規(guī)的排序算法得到總體上出現(xiàn)次數(shù)最多的IP
?
三十五、兩臺mysql服務(wù)器,其中一臺掛了,怎么讓業(yè)務(wù)端無感切換,并保證正常情況下講臺服務(wù)器的數(shù)據(jù)是一致的
不是核心業(yè)務(wù)的話,先停寫,把備機(jī)拉起來,查看兩臺機(jī)器的日志,進(jìn)行數(shù)據(jù)補(bǔ)償,開寫。
如果是核心業(yè)務(wù)的話,現(xiàn)在所有的寫操作都在正常的狀態(tài)機(jī)器上。把好的這臺機(jī)器的備機(jī)拉起來,當(dāng)主機(jī)。
備機(jī)的數(shù)據(jù)不一致怎么辦?
你要勇敢懟回去,你們每秒多少寫入操作。按照百萬級表,每秒1000的寫入效率,正常的設(shè)計是,分布在2臺機(jī)器上每臺500。這個級別的數(shù)據(jù)同步,出現(xiàn)差異的概率 可以忽略不計的。有一臺出現(xiàn)問題,另一臺也可以抗住。
?

三十六、redis是如何進(jìn)行同步的,同步的方式,同步回滾怎么辦,數(shù)據(jù)異常怎么辦
redis 集群主從同步的簡單原理
Redis的復(fù)制功能是基于內(nèi)存快照的持久化策略基礎(chǔ)上的,也就是說無論你的持久化策略選擇的是什么,只要用到了Redis的復(fù)制功能,就一定會有內(nèi)存快照發(fā)生
當(dāng)Slave啟動并連接到Master之后,它將主動發(fā)送一個SYNC命令( 首先Master會啟動一個后臺進(jìn)程,將數(shù)據(jù)快照保存到文件中[rdb文件] Master 會給Slave 發(fā)送一個
Ping命令來判斷Slave的存活狀態(tài) 當(dāng)存活時 Master會將數(shù)據(jù)文件發(fā)送給Slave 并將所有寫命令發(fā)送到Slave )。Slave首先會將數(shù)據(jù)文件保存到本地之后再將數(shù)據(jù)加載到內(nèi)存中。
當(dāng)?shù)谝淮捂溄踊蛘呤枪收虾螅匦逻B接都會先判斷Slave的存活狀態(tài)再做全部數(shù)據(jù)的同步,之后只會同步Master的寫操作(將命令發(fā)送給Slave)
問題:
當(dāng) Master 同步數(shù)據(jù)時 若數(shù)據(jù)量較大 而Master本身只會啟用一個后臺進(jìn)程 來對多個Slave進(jìn)行同步 , 這樣Master就會壓力過大 , 而且Slave 恢復(fù)的時間也會很慢!
redis 主從復(fù)制的優(yōu)點:
(1)在一個Redis集群中,master負(fù)責(zé)寫請求,slave負(fù)責(zé)讀請求,這么做一方面通過將讀請求分散到其他機(jī)器從而大大減少了master服務(wù)器的壓力,另一方面slave專注于提供
讀服務(wù)從而提高了響應(yīng)和讀取速度。
(2)在一個Redis集群中,如果master宕機(jī),slave可以介入并取代master的位置,因此對于整個Redis服務(wù)來說不至于提供不了服務(wù),這樣使得整個Redis服務(wù)足夠安全。
(3)水平增加Slave機(jī)器可以提高性能
?
三十七、如何解決跨域
JSONP
添加響應(yīng)頭,允許跨域
代理的方式
?
三十八、寫出以下輸出
Q: "aa" == 1, "aa" == 0, 1 == "1", 1==="1", "12asdsad" + 1, "asdjkfgj12"+1A: false, true, true, false, 13, 1
why:
php中 字符串==0 恒成立
php中 字符串和數(shù)字相加,如果字符串開頭是數(shù)字,則等于字符串開頭的數(shù)字(字符串第一個位置開始,到第一個非數(shù)字和.的位置截止)+數(shù)字
?
三十九、什么是服務(wù)容器、控制反轉(zhuǎn)(IoC)、依賴注入(DI)
服務(wù)容器是用來管理類依賴與運行依賴注入的工具。Laravel框架中就是使用服務(wù)容器來實現(xiàn) 控制反轉(zhuǎn) 和 依賴注入 。
控制反轉(zhuǎn)(IoC) 就是說把創(chuàng)建對象的 控制權(quán) 進(jìn)行轉(zhuǎn)移,以前創(chuàng)建對象的主動權(quán)和創(chuàng)建時機(jī)是由自己把控的,而現(xiàn)在這種權(quán)力轉(zhuǎn)移到第三方,也就是 Laravel 中的容器。
依賴注入(DI)則是幫助容器實現(xiàn)在運行中動態(tài)的為對象提供提依賴的資源。
?
四十、Composer自動加載原理
composer加載核心思想是通過composer的配置文件在引用入口文件(autoload.php)時,將類和路徑的對應(yīng)關(guān)系加載到內(nèi)存中,最后將具體加載的實現(xiàn)注冊到spl_autoload_register函數(shù)中.最后將需要的文件包含進(jìn)來.
?
四十一、一個請求到PHP,Nginx的主要過程。完整描述整個網(wǎng)絡(luò)請求過程,原理。
1)、FastCGI進(jìn)程管理器php-fpm自身初始化,啟動主進(jìn)程php-fpm和啟動start_servers個CGI 子進(jìn)程。主進(jìn)程php-fpm主要是管理fastcgi子進(jìn)程,監(jiān)聽9000端口。fastcgi子進(jìn)程等待來自Web Server的連接。
2)、當(dāng)客戶端請求到達(dá)Web Server Nginx是時,Nginx通過location指令,將所有以php為后綴的文件都交給127.0.0.1:9000來處理,即Nginx通過location指令,將所有以php為后綴的文件都交給127.0.0.1:9000來處理。
3)FastCGI進(jìn)程管理器PHP-FPM選擇并連接到一個子進(jìn)程CGI解釋器。Web server將CGI環(huán)境變量和標(biāo)準(zhǔn)輸入發(fā)送到FastCGI子進(jìn)程。
4)、FastCGI子進(jìn)程完成處理后將標(biāo)準(zhǔn)輸出和錯誤信息從同一連接返回Web Server。當(dāng)FastCGI子進(jìn)程關(guān)閉連接時,請求便告處理完成。
5)、FastCGI子進(jìn)程接著等待并處理來自FastCGI進(jìn)程管理器(運行在 WebServer中)的下一個連接。
?
四十二、PHP的魔術(shù)方法
__set() // 在給不可訪問屬性賦值時,__set()會被調(diào)用
__get() // 讀取不可訪問屬性的值時,__get()會被調(diào)用
__isset() //當(dāng)對不可訪問屬性調(diào)用isset()或empty(),__isset()會被調(diào)用
__unset() // 當(dāng)對不可訪問屬性調(diào)用unset()時,__unset()會被調(diào)用
__call() // 在對象中調(diào)用一個不可訪問方法時,__call()會被調(diào)用
__callStatic() // 在靜態(tài)上下文中調(diào)用一個不可訪問的方法時,__callStatic會被調(diào)用
__construct() // 構(gòu)造函數(shù)的類會在每次創(chuàng)建新對象時先調(diào)用此方法,所以非常適合在使用對象之前做一些初始化工作。
__destruct() // 析構(gòu)函數(shù)會在到某個對象的所有引用都被刪除或者當(dāng)對象被顯式銷毀時執(zhí)行。
__sleep() // serialize()函數(shù)會檢查類中是否存在一個魔術(shù)方法__sleep(),如果存在,該方法會先被調(diào)用,然后再執(zhí)行序列化操作。此功能可以用于清理對象,并返回一個包含對象中所有應(yīng)被序列化的變量名稱的數(shù)組。如果該方法未返回任何內(nèi)容,則 NULL 被序列化,并產(chǎn)生一個 E_NOTICE 級別的錯誤。
__wakeup() // unserialize()函數(shù)會檢查是否存在一個__wakeup()方法,如果存在,則會先調(diào)用該方法,然后再執(zhí)行反序列化操作。__wakeup() 經(jīng)常用在反序列化操作中,例如重新建立數(shù)據(jù)庫連接,或執(zhí)行其它初始化操作。
?
四十三、字符編碼UTF8、GBK、GB2312的區(qū)別。
utf8是國際編碼。通用性較好。
gbk是國內(nèi)編碼。通用型較utf8差,但是占用數(shù)據(jù)庫比utf8小。
gb2312是一個簡體中文字符集的中國國家標(biāo)準(zhǔn),共收錄6763個漢字。
?
四十四、MySQL默認(rèn)的排序方式是什么
MyIsam存儲引擎:在沒有任何刪除,修改的操作下,執(zhí)行select不帶order by那么會按照插入的順序下進(jìn)行排序。
InnDB存儲引擎:在相同的情況下,select不帶order by會根據(jù)主鍵來排序,從小到大。
?
四十五、OSI七層網(wǎng)絡(luò)模型
物理層:建立、維護(hù)、斷開物理連接
數(shù)據(jù)鏈路層:建立邏輯鏈接、進(jìn)行硬件地址尋址、差錯校驗等功能(SDLC、HDLC、PPP、STP)
網(wǎng)絡(luò)層:進(jìn)行邏輯地址尋址,實現(xiàn)不同網(wǎng)絡(luò)之間的路徑選擇(IP、IPX、OSPF)
傳輸層:定義傳輸數(shù)據(jù)的協(xié)議端口號,以及流程和差錯校驗(TCP,UDP)數(shù)據(jù)包一旦離開網(wǎng)卡即進(jìn)入網(wǎng)絡(luò)傳輸層
會話層:建立、管理、終止會話
表示層:數(shù)據(jù)的表示、安全、壓縮
應(yīng)用層:網(wǎng)絡(luò)服務(wù)與最終用戶的一個接口;協(xié)議有:HTTP、FTP、TFTP、SMTP、DNS、TELNET、HTTPS、POP3、DHCP
