首頁 >後端開發 >php教程 >【吐血整理】28個關於PHP核心技術的面試題,幫助跳槽!

【吐血整理】28個關於PHP核心技術的面試題,幫助跳槽!

青灯夜游
青灯夜游轉載
2022-02-15 11:17:5420634瀏覽

這篇文章為大家整理分享28個關於PHP核心技術的面試題,帶大家深入了解PHP核心技術,在面試時可以快速避坑,跳槽必備,值得收藏學習,希望對大家有所幫助!

【吐血整理】28個關於PHP核心技術的面試題,幫助跳槽!

相關推薦:《2022年PHP面試題大匯總(收藏)

1 oop是什麼?

答:oop是物件導向程式設計,物件導向程式設計是一種電腦程式架構,OOP 的一條基本原則是電腦程式是由單一能夠起到子程式作用的單元或物件組合而成。

OOP有三大特點

1、封裝性:也稱為資訊隱藏,就是將一個類別的使用和實作分開,只保留部分介面與方法與外部聯繫,或者說隻公開了一些供開發人員使用的方法。於是開發人員只 需要關注這個類別如何使用,而不用去關心其具體的實現過程,這樣就能實現MVC分工合作,也能有效避免程式間相互依賴,實現程式碼模組間松藕合。

2、繼承性:就是子類別自動繼承其父級類別中的屬性和方法,並可以新增新的屬性和方法或對部分屬性和方法進行重寫。繼承增加了程式碼的可重用性。 PHP只支援單繼承,也就是說一個子類別只能有一個父類別。

3、多態性:子類別繼承了來自父級類別中的屬性和方法,並對其中部分方法進行重寫。於是多個子類別中雖然都具有同一個方法,但是這些子類別實例化的物件呼叫這些相同的方法後卻可以獲得完全不同的結果,而這種技術就是多態性。

多態性增強了軟體的靈活性。

1、易維護

採用物件導向思想設計的結構,可讀性高,由於繼承的存在,即使改變需求,那麼維護也只是在局部模組,所以維護起來是非常方便和較低成本的。

2、高品質

在設計時,可重複使用現有的,在先前的專案的領域中已被測試過的類別使系統滿足業務需求並具有較高的質量。

3、效率高

在軟體開發時,依照設計的需要對現實世界的事物進行抽象,產生類別。使用這樣的方法解決問題,接近日常生活和自然的思考方式,勢必提高軟體開發的效率和品質。

4、易擴展

由於繼承、封裝、多型的特性,自然設計出高內聚、低耦合的系統結構,使得系統更靈活、更容易擴展,而且成本較低。

2 合併兩個陣列有幾種方式,試比較它們的異同

#方式:

##1、array_merge ()

2、' '

3、array_merge_recursive

異同:

array_merge 簡單的合併陣列

array_merge_recursive 合併兩個數組,如果數組中有完全一樣的數據,將它們遞歸合併

array_combine 和' ' :合併兩個數組,前者的值作為新數組的鍵

#3 PHP的is_writeable()函數存在Bug,無法準確判斷一個目錄/檔案是否可寫,請寫一個函數來判斷目錄/檔案是否絕對可寫

答案:其中bug存在兩個方面,

1、在windowns中,當檔案只有唯讀屬性時,is_writeable()函數才會傳回false,當傳回true時,該檔案不一定是可寫的。

如果是目錄,在目錄中新建文件並透過開啟文件來判斷;

如果是文件,可以透過開啟文件(fopen),來測試文件是否可寫入。

2、在Unix中,當php設定檔中開啟safe_mode時(safe_mode=on),is_writeable()同樣不可用。

讀取設定檔是否safe_mode是否開啟。

/**
* Tests for file writability
*
* is_writable() returns TRUE on Windows servers when you really can't write to
* the file, based on the read-only attribute. is_writable() is also unreliable
* on Unix servers if safe_mode is on.
*
* @access   private
* @return   void
*/
if ( ! function_exists('is_really_writable'))
{
    function is_really_writable($file){
    // If we're on a Unix server with safe_mode off we call is_writable
    if (DIRECTORY_SEPARATOR == '/' AND @ini_get("safe_mode") == FALSE){
        return is_writable($file);
    }
    // For windows servers and safe_mode "on" installations we'll actually
    // write a file then read it. Bah...
    if (is_dir($file)){
        $file = rtrim($file, '/').'/'.md5(mt_rand(1,100).mt_rand(1,100));
        if (($fp = @fopen($file, FOPEN_WRITE_CREATE)) === FALSE){
            return FALSE;
        }
        fclose($fp);
        @chmod($file, DIR_WRITE_MODE);
        @unlink($file);
        return TRUE;
    } elseif ( ! is_file($file) OR ($fp = @fopen($file, FOPEN_WRITE_CREATE)) === FALSE) {
        return FALSE;
    }
    fclose($fp);
    return TRUE;
    }
}

4 PHP的垃圾收集機制是怎麼樣的?

PHP可以自動進行記憶體管理,清除不再需要的物件。 PHP使用了引用計數(reference counting)這個單純的垃圾回收(garbage collection)機制。

每個對像都內含一個引用計數器,每個reference連接到對象,計數器加1。當reference離開生存空間或被設為NULL,計數器會減1。當某個物件的參考計數器為零時,PHP知道你將不再需要使用這個對象,釋放其所佔的記憶體空間。

5 寫一個函數,盡可能高效的,從一個標準url裡取出檔案的副檔名,

例如:http://www.startphp.cn /abc/de/fg.php?id=1需要取出php或.php

<?php
    // 方案一
    function getExt1($url){
        $arr = parse_url($url);
        //Array ( [scheme] => http [host] => www.startphp.cn [path] => /abc/de/fg.php [query] => id=1 )
        $file = basename($arr[&#39;path&#39;]);
        $ext = explode(&#39;.&#39;, $file);
        return $ext[count($ext)-1];
    }
    // 方案二
    function getExt2($url){
        $url = basename($url);
        $pos1 = strpos($url,&#39;.&#39;);
        $pos2 = strpos($url,&#39;?&#39;);
        if (strstr($url,&#39;?&#39;)) {
            return substr($url,$pos1+1,$pos2-$pos1-1);
        } else {
            return substr($url,$pos1);
        }
    }
    $path = "http://www.startphp.cn/abc/de/fg.php?id=1";
    echo getExt1($path);
    echo "<br />";
    echo getExt2($path);
?>

#6 使用正規表示式提取一段識別語言(html或xml)

程式碼區段中指定標籤的指定屬性值(需考慮屬性值對不規則的情況,如大小寫不敏感,屬性名值與等號間有空格等)。此處假設需擷取test標籤的attr屬性值,請自行建立包含該標籤的字串(騰訊)

如下:

<?php
    header("content-type:text/html;charset=utf-8");
    function getAttrValue($str,$tagName,$attrName){
        $pattern1="/<".$tagName."(s+w+s*=s*([&#39;"]?)([^&#39;"]*)())*s+".$attrName."s*=s*([&#39;"]?)([^&#39;"]*)()(s+w+s*=s*([&#39;"]?)([^&#39;"]*)(9))*s*>/i";
        $arr=array();
        $re=preg_match($pattern1,$str,$arr);
        if($re){
            echo"<br/>$arr[6]={$arr[6]}";
        }else{
            echo"<br/>没找到。";
        }
    }
    // 示例
    $str1="<test attr=&#39;ddd&#39;>";
    getAttrValue($str1,"test","attr");//找test标签中attr属性的值,结果为ddd
    $str2="<test2 attr=&#39;ddd&#39;attr2=&#39;ddd2&#39;t1="t1 value"t2=&#39;t2 value&#39;>";
    getAttrValue($str2,"test2","t1");//找test2标签中t1属性的值,结果为t1 value
?>

7 php中WEB上传文件的原理是什么,如何限制上传文件的大小?

上传文件的表单使用post方式,并且要在form中添加enctype='multipart/form-data'。

一般可以加上隐藏域:a477cd11f888a00d3a5c1a04e2bd042a,位置在file域前面。

value的值是上传文件的客户端字节限制。可以避免用户在花时间等待上传大文件之后才发现文件过大上传失败的麻烦。

使用file文件域来选择要上传的文件,当点击提交按钮之后,文件会被上传到服务器中的临时目录,在脚本运行结束时会被销毁,所以应该在脚本结束之前,将其移动到服务器上的某个目录下,可以通过函数move_uploaded_file()来移动临时文件,要获取临时文件的信息,使用$_FILES。

限制上传文件大小的因素有:

客户端的隐藏域MAX_FILE_SIZE的数值(可以被绕开)。

服务器端的upload_max_filesizepost_max_sizememory_limit。这几项不能够用脚本来设置。

自定义文件大小限制逻辑。即使服务器的限制是能自己决定,也会有需要个别考虑的情况。所以这个限制方式经常是必要的。

8 请说明 PHP 中传值与传引用的区别,什么时候传值什么时候传引用?

按值传递:函数范围内对值的任何改变在函数外部都会被忽略

按引用传递:函数范围内对值的任何改变在函数外部也能反映出这些修改

优缺点:按值传递时,php必须复制值。特别是对于大型的字符串和对象来说,这将会是一个代价很大的操作。按引用传递则不需要复制值,对于性能提高很有好处。

9 MySQL数据库中的字段类型varchar和char的主要区别是什么?

Varchar是变长,节省存储空间,char是固定长度。查找效率要char型快,因为varchar是非定长,必须先查找长度,然后进行数据的提取,比char定长类型多了一个步骤,所以效率低一些。

10 静态化如何实现的?伪静态如何实现?

1、 静态化指的是页面静态化,也即生成实实在在的静态文件,也即不需要查询数据库就可以直接从文件中获取数据,指的是真静态。

实现方式主要有两种:一种是我们在添加信息入库的时候就生成的静态文件,也称为模板替换技术。一种是用户在访问我们的页面时先判断是否有对应的缓存文件存在,如果存在就读缓存,不存在就读数据库,同时生成缓存文件。

2、伪静态不是真正意义上的静态化,之所以使用伪静态,主要是为了SEO推广,搜索引擎对动态的文件获取难度大,不利于网站的推广。

实习原理是基于Apache或Nginx的rewrite

主要有两种方式:

一种是直接在配置虚拟机的位置配置伪静态,这个每次修改完成后需要重启web服务器。

另一种采用分布式的,可以在网站的根目录上创建.htaccess的文件,在里面配置相应的重写规则来实现伪静态,这种每次重写时不需要重启web服务器,且结构上比较清晰。

11 如何处理负载,高并发?

1、HTML静态化

效率最高、消耗最小的就是纯静态化的html页面,所以我们尽可能使我们的 网站上的页面采用静态页面来实现,这个最简单的方法其实也是最有效的方法。

2、图片服务器分离

把图片单独存储,尽量减少图片等大流量的开销,可以放在一些相关的平台上,如七牛等

3、数据库集群和库表散列及缓存

数据库的并发连接为100,一台数据库远远不够,可以从读写分离、主从复制,数据库集群方面来着手。另外尽量减少数据库的访问,可以使用缓存数据库如memcache、redis。

4、镜像:

尽量减少下载,可以把不同的请求分发到多个镜像端。

5、负载均衡:

Apache的最大并发连接为1500,只能增加服务器,可以从硬件上着手,如F5服务器。当然硬件的成本比较高,我们往往从软件方面着手。

12 PHP7的新特性?

标量类型声明:PHP 7 中的函数的形参类型声明可以是标量了。在 PHP 5 中只能是类名、接口、array 或者 callable (PHP 5.4,即可以是函数,包括匿名函数),现在也可以使用 string、int、float和 bool 了。 

傳回值類型宣告:增加了對傳回類型宣告的支援。類似於參數類型聲明,傳回類型聲明指明了函數傳回值的類型。可用的類型與參數聲明中可用的類型相同。

NULL 合併運算子:由於日常使用中存在大量同時使用三元表達式和isset()的情況,NULL 合併運算子使得變數存在且值不為NULL, 它就會傳回自身的值,否則傳回它的第二個操作數。

use 加強:從同一namespace 導入的類別、函數和常數現在可以透過單一use 語句一次導入了匿名類別:現在支援透過new class 來實例化一個匿名類別

#13 常見的PHP 安全性攻擊SQL注入:

使用者利用在表單欄位輸入SQL語句的方式來影響正常的SQL執行。

防止:使用mysql_real_escape_string()過濾資料手動檢查每一資料是否為正確的資料類型使用預處理語句並綁定變數參數化SQL:是指在設計與資料庫連結並存取資料時,在需要填入數值或資料的地方,使用參數(Parameter) 來給值,用@或?來表示參數。

XSS攻擊 :跨站點腳本攻擊,由使用者輸入一些資料到你的網站,其中包含客戶端腳本(通常JavaScript)。如果你沒有過濾就輸出資料到另一個web頁面,這個腳本將會被執行。

防止:為了防止XSS攻擊,使用PHP的htmlentities()函數過濾再輸出到瀏覽器。

CSRF:跨站點請求偽造,是指一個頁面發出的請求,看起來就像是網站的信任用戶,但是是偽造的

防止:一般來說,確保用戶來自你的表單,並且匹配每一個你發送出去的表單。有兩點一定要記住:對使用者會話採用適當的安全措施,例如:給每一個會話更新id和使用者使用SSL。產生另一個一次性的令牌並將其嵌入表單,保存在會話中(一個會話變數),在提交時檢查它。如laravel中的 _token

程式碼注入:程式碼注入是利用電腦漏洞透過處理無效資料所造成的。問題出在,當你不小心執行任意程式碼,通常透過檔案包含。寫得很糟糕的程式碼可以允許一個遠端檔案包含並執行。如許多PHP函數,如require可以包含URL或檔名。

防止程式碼注入 過濾用戶輸入 在php.ini中設定禁用allow_url_fopen和allow_url_include。這將禁用require/include/fopen的遠端檔案

14 物件導向的特徵有哪些面向?

主要有封裝,繼承,多態。如果是4個方面則加上:抽象。

封裝:

封裝是保證軟體元件具有優良的模組性的基礎,封裝的目標就是要實現軟體元件的高內聚,低耦合,防止程式相互依賴性而帶來的變動影響.

繼承:

在定義和實作一個類別的時候,可以在一個已經存在的類別的基礎之上來進行,把這個已經存在的類別所定義的內容當作自己的內容,並可以加入若干新的內容,或修改原來的方法使之更適合特殊的需要,這就是繼承。繼承是子類別自動共享父類別資料和方法的機制,這是類別之間的一種關係,提高了軟體的可重複使用性和可擴展性。

多態:

多態是指程式中定義的引用變數所指向的具體類型和透過該引用變數發出的方法呼叫在程式設計時並不確定,而是在程式運行期間才確定,即一個引用變數倒底會指向哪個類別的實例對象,該引用變數發出的方法呼叫到底是哪個類別中實現的方法,必須在由程式運行期間才能決定。

抽象:

抽象就是找出一些事物的相似性和共性之處,然後將這些事物歸為一個類,這個類只考慮這些事物的相似和共通性之處,並且會忽略與當前主題和目標無關的那些方面,將注意力集中在與當前目標相關的方面。例如,看到一隻螞蟻和大象,你能夠想像出它們的相同之處,那就是抽象。

15 說說對SQL語句最佳化有哪些方法? (選擇幾個)

(1)Where子句中:where表之間的連接必須寫在其他Where條件之前,那些可以過濾掉最大數量記錄的條件必須寫在Where子句的末尾.HAVING最後。

(2)用EXISTS取代IN、用NOT EXISTS取代NOT IN。

(3) 避免在索引列上使用計算

(4)避免在索引列上使用IS NULL和IS NOT NULL

(5)對查詢進行最佳化,應盡量避免全表掃描,首先應考慮在where 及order by 涉及的欄位上建立索引。

(6)應盡量避免在where 子句中對欄位進行null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描

(7)應盡量避免在where子句中對欄位進行表達式操作,這將導致引擎放棄使用索引而進行全表掃描

16 MySQL資料庫作發布系統的存儲,一天五萬條以上的增量,預計運維三年,怎麼優化?

(1)設計良好的資料庫結構,讓部分資料冗餘,盡量避免join查詢,提高效率。

(2) 選擇合適的表格欄位資料類型和儲存引擎,適當的添加索引。

(3) 做mysql主從複製讀寫分開。

(4)將資料表分錶,減少單表中的資料量提高查詢速度。

(5)加入快取機制,例如redis,memcached等。

(6)對不常改動的頁面,產生靜態頁面(例如做ob快取)。

(7)書寫高效率的SQL。例如 SELECT * FROM TABEL 改為 SELECT field_1, field_2, field_3 FROM TABLE.

17 對於大流量的網站,您採用什麼樣的方法來解決各頁訪問量統計問題?

(1) 確認伺服器是否能支撐目前存取量。

(2) 最佳化資料庫存取。

(3)禁止外部存取連結(盜鏈), 例如圖片盜鏈。

(4)控制檔下載。

(5)做負載平衡,使用不同主機分流。

(6)使用瀏覽統計軟體,了解訪問量,有針對性的進行最佳化。

18 談談你對 mysql 引擎中的 MyISAM與InnoDB的差異理解?

InnoDB和MyISAM是許多人在使用MySQL時最常用的兩個表格類型,這兩個表格類型各有優劣,視具體應用而定。基本的差異為:MyISAM類型不支援事務處理等高階處理,而InnoDB類型支援。 MyISAM類型的表強調的是效能,其執行數度比InnoDB類型更快,但是不提供事務支持,而InnoDB提供事務支持已經外部鍵等高級資料庫功能。

以下是一些細節和具體實現的差異:

MyISAM與InnoDB的差異是什麼?

1、 儲存結構

MyISAM:每個MyISAM在磁碟上儲存成三個檔案。第一個檔案的名字以表格的名字開始,副檔名指出檔案類型。 .frm檔案儲存表定義。資料檔案的副檔名為.MYD (MYData)。索引檔的副檔名是.MYI (MYIndex)。

InnoDB:所有的表都保存在同一個資料檔案中(也可能是多個文件,或是獨立的表空間檔案),InnoDB表的大小只受限於作業系統檔案的大小,一般為2GB。

2、 儲存空間

MyISAM:可被壓縮,儲存空間較小。支援三種不同的儲存格式:靜態表(默認,但是注意資料末端不能有空格,會被去掉)、動態表、壓縮表。

InnoDB:需要更多的記憶體和存儲,它會在主記憶體中建立其專用的緩衝池用於高速緩衝資料和索引。

3、 可攜性、備份及恢復

MyISAM:資料是以檔案的形式存儲,所以在跨平台的資料轉移中會很方便。在備份和還原時可單獨針對某個表進行操作。

InnoDB:免費的方案可以是拷貝資料檔案、備份 binlog,或是用 mysqldump,在資料量達到幾十G的時候就相對痛苦了。

4、 交易支援

MyISAM:強調的是效能,每次查詢具有原子性,其執行數度比InnoDB類型更快,但不提供交易支援。

InnoDB:提供事務支援事務,外部鍵等高階資料庫功能。具有事務(commit)、回滾(rollback)和崩潰修復能力(crash recovery capabilities)的事務安全(transaction-safe (ACID compliant))型表。

5、 AUTO_INCREMENT

MyISAM:可以和其他欄位一起建立聯合索引。引擎的自動增長列必須是索引,如果是組合索引,自動增長可以不是第一列,他可以根據前面幾列進行排序後遞增。

InnoDB:InnoDB中必須包含只有該欄位的索引。引擎的自動增長列必須是索引,如果是組合索引也必須是組合索引的第一列。

6、 表鎖差異

MyISAM:只支援表級鎖,使用者在操作myisam表時,select,update,delete,insert語句都會給表自動加鎖,如果加鎖以後的表格滿足insert並發的情況下,可以在表格的尾部插入新的資料。

InnoDB:支援交易和行級鎖定,是innodb的最大特色。行鎖大幅提高了多用戶並發操作的新能。但是InnoDB的行鎖,只是在WHERE的主鍵是有效的,非主鍵的WHERE都會鎖全表的。

7、全文索引

MyISAM:支援FULLTEXT類型的全文索引

InnoDB:不支援FULLTEXT類型的全文索引,但innodb可以使用sphinx外掛程式支援全文索引,而且效果更好。

8、 表主鍵

MyISAM:允許沒有任何索引和主鍵的表存在,索引都是保存行的位址。

InnoDB:如果沒有設定主鍵或非空唯一索引,就會自動產生一個6位元組的主鍵(使用者不可見),資料是主索引的一部分,附加索引保存的是主索引的值。

9、 表的特定行數

MyISAM:儲存有表格的總行數,如果select count(*) from table;會直接取出出該值。

InnoDB:沒有保存表格的總行數,如果使用select count(*) from table;就會遍歷整個表,消耗相當大,但是在加了wehre條件後,myisam和innodb處理的方式都一樣。

10、 CURD操作

MyISAM:如果執行大量的SELECT,MyISAM是更好的選擇。

InnoDB:如果你的資料執行大量的INSERT或UPDATE,出於效能方面的考慮,應該使用InnoDB表。 DELETE 從效能上InnoDB比較優,但DELETE FROM table時,InnoDB不會重新建立表,而是一行一行的刪除,在innodb上如果要清空保存有大量資料的表,最好使用truncate table這個指令。

11、 外鍵

MyISAM:不支援

InnoDB:支援

#透過上述的分析,基本上可以考慮使用InnoDB來取代MyISAM引擎了,原因是InnoDB本身很多良好的特點,例如事務支援、預存程序、視圖、行級鎖定等等,在並發很多的情況下,相信InnoDB的表現肯定比MyISAM強很多。另外,任何一種表都不是萬能的,只用恰當的針對業務類型來選擇合適的表類型,才能最大的發揮MySQL的效能優勢。如果不是很複雜的Web應用,非關鍵應用,還是可以繼續考慮MyISAM的,這個具體情況可以自己斟酌。

19 redis 和memache 快取的差異

總結一:

##1 .資料型別

Redis資料型態豐富,支援set list等型別

memcache支援簡單資料型別,需要客戶端自己處理複雜物件

2.持久性

redis支援資料落地持久化儲存

memcache不支援資料持久性儲存

3.分散式儲存

redis支援master-slave複製模式

memcache可以用一致性hash做分佈式

value大小不同

memcache是​​一個記憶體緩存,key的長度小於250字符,單一item儲存要小於1M,不適合虛擬機使用

#4.資料一致性不同

redis使用的是單線程模型,保證了數據按順序提交。

memcache需要使用cas保證資料一致性。 CAS(Check and Set)是一個確保並發一致性的機制,屬於「樂觀鎖」範疇;原理很簡單:拿版本號,操作,對比版本號,如果一致就操作,不一致就放棄任何操作

5.cpu利用

redis單執行緒模型只能使用一個cpu,可以開啟多個redis程序

##總結二:1.Redis中,並不是所有的資料都一直儲存在記憶體中的,這是和Memcached相比一個最大的區別。

2.Redis不僅支援簡單的k/v類型的數據,同時也提供list,set,hash等資料結構的儲存。

3.Redis支援資料的備份,即master-slave模式的資料備份。

4.Redis支援資料的持久化,可以將記憶體中的資料保持在磁碟中,重啟的時候可以再次載入進行使用。

我個人認為最本質的不同是Redis在很多方面具備資料庫的特徵,或者說就是一個資料庫系統,而Memcached只是簡單的K/V快取

總結三:redis和memecache的差別在於:

1、儲存方式:

memecache 把資料全部存在記憶體之中,斷電後會掛掉,資料不能超過記憶體大小

redis有部份存在硬碟上,這樣能確保資料的持久性。

2、資料支援類型:

redis在資料支援上比memecache多的多。

3、使用底層模型不同:

新版本的redis直接自己建構了VM 機制,因為一般的系統呼叫系統函數的話,會浪費一定的時間去移動和請求。

4、運行環境不同:

redis目前官方只支持Linux 上去行,從而省去了對於其它系統的支持,這樣的話可以更好的把精力用於本系統環境上的最佳化,雖然後來微軟有一個小組為其寫了補丁。但沒有放到主幹上

memcache只能當做緩存,cache

redis的內容是可以落地的,就是說跟MongoDB有些類似,然後redis也可以當緩存,並且可以設置master-slave

20 redis訊息佇列先進先出需要注意什麼?

答案:通常使用一個list來實作佇列操作,這樣有一個小限制,所以的任務統一都是先進先出,如果想優先處理某個任務就不太好處理了,這就需要讓隊列有優先級的概念,我們就可以優先處理高級別的任務,實現方式有以下幾種方式:

1)单一列表实现:队列正常的操作是 左进右出(lpush,rpop)为了先处理高优先级任务,在遇到高级别任务时,可以直接插队,直接放入队列头部(rpush),这样,从队列头部(右侧)获取任务时,取到的就是高优先级的任务(rpop)

2)使用两个队列,一个普通队列,一个高级队列,针对任务的级别放入不同的队列,获取任务时也很简单,redis的BRPOP命令可以按顺序从多个队列中取值,BRPOP会按照给出的 key 顺序查看,并在找到的第一个非空 list 的尾部弹出一个元素,redis> BRPOP list1 list2 0

list1 做为高优先级任务队列
list2 做为普通任务队列

这样就实现了先处理高优先级任务,当没有高优先级任务时,就去获取普通任务
方式1  最简单,但实际应用比较局限,方式3可以实现复杂优先级,但实现比较复杂,不利于维护
方式2  是推荐用法,实际应用最为合适

21 Redis如何防止高并发?

答:其实redis是不会存在并发问题的,因为他是单进程的,再多的命令都是一个接一个地执行的。我们使用的时候,可能会出现并发问题,比如获得和设定这一对。Redis的为什么 有高并发问题?Redis的出身决定等

Redis是一种单线程机制的nosql数据库,基于key-value,数据可持久化落盘。由于单线程所以redis本身并没有锁的概念,多个客户端连接并不存在竞争关系,但是利用jedis等客户端对redis进行并发访问时会出现问题。发生连接超时、数据转换错误、阻塞、客户端关闭连接等问题,这些问题均是由于客户端连接混乱造成。

同时,单线程的天性决定,高并发对同一个键的操作会排队处理,如果并发量很大,可能造成后来的请求超时。

在远程访问redis的时候,因为网络等原因造成高并发访问延迟返回的问题。

解决办法

在客户端将连接进行池化,同时对客户端读写Redis操作采用内部锁synchronized。

服务器角度,利用setnx变向实现锁机制。

22 做秒杀用什么数据库,怎么实现的?

答:因为秒杀的一瞬间,并发非常大,如果同时请求数据库,会导致数据库的压力非常大,导致数据库的性能急剧下降,更严重的可能会导致数据库服务器宕机。

这时候一般采用内存高速缓存数据库redis来实现的,redis是非关系型数据库,redis是单线程的,通过redis的队列可以完成秒杀过程。

23 什么情况下使用缓存?

答:当用户第一次访问应用系统的时候,因为还没有登录,会被引导到认证系统中进行登录;根据用户提供的登录信息,认证系统进行身份校验,如果通过校验,应该返回给用户一个认证的凭据--ticket;

用户再访问别的应用的时候,就会将这个ticket带上,作为自己认证的凭据,应用系统接受到请求之后会把 ticket送到认证系统进行校验,检查ticket的合法性。如果通过校验,用户就可以在不用再次登录的情况下访问应用系统2和应用系统3了。

实现主要技术点:

1、两个站点共用一个数据验证系统

2、主要通过跨域请求的方式来实现验证及session处理。

24 如何解决异常处理?

答: 抛出异常:使用try…catch,异常的代码放在try代码块内,如果没有触发异常,则代码继续执行,如果异常被触发,就会 抛出一个异常。Catch代码块捕获异常,并创建一个包含异常信息的对象。$e->getMessage(),输出异常的错误信息。

解决异常:使用set_error_handler函数获取异常(也可以使用try()和catch()函数),然后使用set_exception_handler()函数设置默认的异常处理程序,register_shutdown_function()函数来执行,执行机制是,php要把调入的函数调入到内存,当页面所有的php语句都执行完成时,再调用此函数

25 权限管理(RBAC)的实现?

1.首先创建一张用户表:id name auto(保存格式为:控制器-方法)

2.然后在后台中创建一个基类控制器,控制器里封装一个构造方法,当用户登陆成功后,使用TP框架中封装好的session函数获取保存在服务器中的session id,然后实例化模型,通过用户id获取保存在数据表中的auth数据,使用explode函数分割获取到的数据,并使用一个数组保存起来,然后使用TP框架中封装好的常量获取当前控制器和方法,然后把他们组装成字符串,使用in_array函数进行判断该数组中是否含有当前获取到的控制器和方法,如果没有,就提示该用户没有权限,如果有就进行下一步操作

26 怎麼保證促銷商品不會超賣?

答:這個問題是我們當時開發時遇到的一個難點,超賣的原因主要是下的訂單的數目和我們要促銷的商品的數目不一致導致的,每次總是訂單的數比我們的促銷商品的數目要多,當時我們的小組討論了好久,給出了好幾個方案來實現:

第一種方案:在每次下訂單前我們判斷促銷商品的數量夠不夠,不夠不允許下訂單,更改庫存量時加上一個條件,只更改商品庫存大於0的商品的庫存,當時我們使用ab進行壓力測試,當併發超過500,訪問量超過2000時,還是會出現超賣現象。所以被我們否定了。

第二種方案:使用mysql的事務加排他鎖來解決,首先我們選擇資料庫的儲存引擎為innoDB,使用的是排他鎖實現的,剛開始的時候我們測試了下共享鎖,發現還是會出現超賣的現象。有個問題是,當我們進行高並發測試時,對資料庫的效能影響很大,導致資料庫的壓力很大,最終也被我們否定了。

第三種方案:使用檔案鎖定實作。當用戶搶到一件促銷商品後先觸發文件鎖,防止其他用戶進入,該用戶搶到促銷品後再解開文件鎖,放其他用戶進行操作。這樣可以解決超賣的問題,但會導致文件得I/O開銷很大。

最後我們使用了redis的佇列來實作。將要促銷的商品數量以隊列的方式存入redis中,每當用戶搶到一件促銷商品則從隊列中刪除一個數據,確保商品不會超賣。這個操作起來很方便,而且效率極高,最後我們採取這種方式來實現

27 商城秒殺的實現?

答:搶購、秒殺是如今很常見的一個應用場景,主要需要解決的問題有兩個:

  • 高並發對資料庫產生的壓力

  • ##在競爭狀態下如何解決庫存的正確減少("超賣"問題)

對於第一個問題,已經很容易想到用快取來處理搶購,避免直接操作資料庫,例如使用Redis。

第二個問題,我們可以使用redis隊列來完成,把要秒殺的商品放入到隊列中,因為pop操作是原子的,即使有很多用戶同時到達,也是依次執行,文件鎖和事務在高並發下性能下降很快,當然還要考慮其他方面的東西,比如搶購頁面做成靜態的,通過ajax調用接口,其中也可能會出現一個用戶搶多次的情況,這時候需要再加上一個排隊隊列和搶購結果隊列及庫存隊列。

高並發情況下,將用戶進入排隊隊列,用一個線程循環處理從排隊隊列取出一個用戶,判斷用戶是否已在搶購結果隊列,如果在,則已搶購,否則未搶購,庫存減1,寫入資料庫,將使用者入結果佇列。

28 如何處理負載、高並發?

#:從低成本、高效能和高擴張性的角度來說有以下處理方案:

1、HTML靜態化

#其實大家都知道,效率最高、消耗最小的就是純靜態化的html頁面,所以我們盡可能使我們的網站上的頁面採用靜態頁面來實現,這個最簡單的方法其實也是最有效的方法。

2、圖片伺服器分離

把圖片單獨存儲,盡量減少圖片等大流量的開銷,可以放在一些相關的平台上,如騎牛等

3、資料庫叢集與庫表雜湊及快取

資料庫的並發連線為100,一台資料庫遠遠不夠,可以從讀寫分離、主從複製,資料庫叢集方面來著手。另外盡量減少資料庫的訪問,可以使用快取資料庫如memcache、redis。

4、鏡像:

盡量減少下載,可以把不同的請求分送到多個鏡像端。

5、負載平衡:

Apache的最大並發連線為1500,只能增加伺服器,可以從硬體上著手,如F5伺服器。當然硬體的成本比較高,我們往往從軟體方面著手。

負載平衡(Load Balancing) 建立在現有網路結構之上,它提供了一種廉價有效透明的方法擴展網路設備和伺服器的頻寬、增加吞吐量、加強網路資料處理能力,同時能夠提高網路的靈活性和可用性。目前使用最廣泛的負載平衡軟體是Nginx、LVS、HAProxy。

分別來說下三種的優缺點:

#Nginx的優點是:

#工作在網路的7層之上,可以針對http應用做一些分流的策略,例如針對網域、目錄結構,它的正規規則比HAProxy更為強大和靈活,這也是它目前廣泛流行的主要原因之一,Nginx單憑這點可利用的場合就遠多於LVS了。

Nginx對網路穩定性的依賴非常小,理論上能ping通就能進行負載功能,這也是它的優點之一;相反LVS對網路穩定性依賴比較大,這點本人深有體會;

Nginx安裝和設定比較簡單,測試起來比較方便,它基本上能把錯誤用日誌印出來。 LVS的配置、測試就要花比較長的時間了,LVS對網路依賴比較大。

可以承受高負載壓力且穩定,在硬體不差的情況下一般能支撐數萬次的並發量,負載度比LVS相對小些。

Nginx可以透過連接埠偵測到伺服器內部的故障,例如根據伺服器處理網頁回傳的狀態碼、逾時等等,並且會把回傳錯誤的請求重新提交到另一個節點,不過其中缺點就是不支援url來檢測。例如使用者正在上傳一個文件,而處理該上傳的節點剛好在上傳過程中出現故障,Nginx會把上傳切到另一台伺服器重新處理,而LVS就直接斷掉了,如果是上傳一個很大的文件或者很重要的文件的話,使用者可能會因此而不滿。

Nginx不僅是一款優秀的負載平衡器/反向代理軟體,它同時也是功能強大的網路應用伺服器。 LNMP也是近幾年非常流行的web架構,在高流量的環境中穩定性也很好。

Nginx現在作為Web反向加速快取越來越成熟了,速度比傳統的Squid伺服器更快,可以考慮用其作為反向代理加速器。

Nginx可作為中層反向代理使用,這一層面Nginx基本上無對手,唯一可以對比Nginx的就只有lighttpd了,不過lighttpd目前還沒有做到Nginx完全的功能,配置也不那麼清晰易讀,社群資料也遠未Nginx活躍。

Nginx也可作為靜態網頁和圖片伺服器,這方面的效能也無對手。還有Nginx社群非常活躍,第三方模組也很多。

Nginx的缺點是:

Nginx只能支援http、https和Email協議,這樣就在適用範圍上面小些,這個是它的缺點。

對後端伺服器的健康檢查,只支援透過連接埠來檢測,不支援透過url來檢測。不支援Session的直接保持,但能透過ip_hash來解決。

LVS:使用Linux核心叢集實作一個高效能、高可用的負載平衡伺服器,它具有很好的可擴展性(Scalability)、可靠性(Reliability)和可管理性(Manageability)。

LVS的優點是:

抗負載能力強、是工作在網路4層之上僅作分發之用,沒有流量的產生,這個特點也決定了它在負載平衡軟體裡的表現最強的,對記憶體和cpu資源消耗比較低。

配置性比較低,這是一個缺點也是一個優點,因為沒有可太多配置的東西,所以並不需要太多接觸,大大減少了人為出錯的幾率。

工作穩定,因為其本身抗負載能力很強,本身有完整的雙機熱備方案,如LVS Keepalived,不過我們在專案實施中用得最多的還是LVS/DR Keepalived。

無流量,LVS只分發請求,而流量並沒有從它本身出去,這點保證了均衡器IO的效能不會受到大流量的影響。

應用程式範圍比較廣,因為LVS工作在4層,所以它幾乎可以對所有應用做負載平衡,包括http、資料庫、線上聊天室等等。

LVS的缺點是:

軟體本身不支援正規表示式處理,不能做動靜分離;而現在許多網站在這方面都有較強的需求,這是Nginx/HAProxy Keepalived的優勢所在。

如果是網站應用程式比較龐大的話,LVS/DR Keepalived實作起來就比較複雜了,特別後面有Windows Server的機器的話,如果實作及配置還有維護過程就比較複雜了,相對而言,Nginx/HAProxy Keepalived就簡單多了。

HAProxy的特點是:

HAProxy也是支援虛擬主機的。

HAProxy的優點能夠補充Nginx的一些缺點,例如支援Session的保持,Cookie的引導;同時支援透過取得指定的url來偵測後端伺服器的狀態。

HAProxy跟LVS類似,本身就只是一款負載平衡軟體;單純從效率來講HAProxy會比Nginx有更優異的負載平衡速度,在並發處理上也是優於Nginx的。

HAProxy支援TCP協定的負載平衡轉發,可以對MySQL讀取進行負載平衡,對後端的MySQL節點進行偵測與負載平衡,大家可以用LVS Keepalived對MySQL主從做負載平衡。

HAProxy負載平衡策略非常多,HAProxy的負載平衡演算法現在具體如下8種:

① roundrobin,表示簡單的輪詢,這個不多說,這個是負載平衡基本都具備的;

② static-rr,表示根據權重,建議關注;

③ leastconn,表示最少連接者先處理,建議關注;

#④ source,表示根據請求來源IP,這個跟Nginx的IP_hash機制類似,我們用其作為解決session問題的一種方法,建議關注;

⑤ ri,表示根據請求的URI;

⑥ rl_param,表示根據請求的URl參數'balance url_param' requires an URL parameter name;

⑦ hdr(name),表示根據HTTP請求頭來鎖定每一次HTTP請求;

⑧ rdp-cookie(name),表示根據據cookie(name)來鎖定並雜湊每個TCP請求。

Nginx和LVS對比的總結:

Nginx工作在網路的7層,所以它可以針對http應用程式本身來做分流策略,例如針對網域、目錄結構等,相較之下LVS並不具備這樣的功能,所以Nginx單憑這點可利用的場合就遠多於LVS了;但Nginx有用的這些功能使其可調整度要高於LVS,所以經常要去觸碰觸碰,觸碰多了,人為出問題的幾率也會大。

Nginx對網路穩定性的依賴較小,理論上只要ping得通,網頁訪問正常,Nginx就能連得通,這是Nginx的一大優點! Nginx同時還能分辨內外網,如果是同時擁有內外網的節點,就相當於單機擁有了備份線路;LVS就比較依賴於網路環境,目前來看伺服器在同一網段內並且LVS使用direct方式分流,效果較能得到保證。

另外注意,LVS需要向託管商至少申請多一個ip來做Visual IP,似乎是不能用本身的IP來做VIP的。要做好LVS管理員,確實得跟進學習很多有關網路通訊的知識,就不再是一個HTTP那麼簡單了。

Nginx安裝和設定比較簡單,測試起來也很方便,因為它基本上能把錯誤用日誌印出來。 LVS的安裝和配置、測試就要花比較長的時間了;LVS對網路依賴比較大,很多時候不能配置成功都是因為網路問題而不是設定問題,出了問題要解決也相應的會麻煩得多。

Nginx也同樣能承受很高負載且穩定,但負載度和穩定度差LVS還有幾個等級:Nginx處理所有流量所以受限於機器IO和配置;本身的bug也還是難以避免的。

Nginx可以偵測到伺服器內部的故障,例如根據伺服器處理網頁回傳的狀態碼、逾時等等,並且會把回傳錯誤的請求重新提交到另一個節點。目前LVS中 ldirectd也能支援針對伺服器內部的情況來監控,但LVS的原理使其無法重發請求。例如使用者正在上傳一個文件,而處理該上傳的節點剛好在上傳過程中出現故障,Nginx會把上傳切到另一台伺服器重新處理,而LVS就直接斷掉了,如果是上傳一個很大的文件或者很重要的文件的話,使用者可能會因此而惱火。

Nginx對請求的非同步處理可以幫助節點伺服器減輕負載,假如使用apache直接對外服務,那麼出現很多的窄頻鏈結時apache伺服器將會佔用大量記憶體而不能釋放,使用多一個Nginx做apache代理的話,這些窄頻連結會被Nginx擋住,apache上就不會堆積過多的請求,這樣就減少了相當多的資源佔用。這點使用squid也有相同的作用,即使squid本身配置為不緩存,對apache還是有很大幫助的。

Nginx能支援http、https和email(email的功能比較少用),LVS所支援的應用程式在這點上會比Nginx更多。在使用上,一般最前端所採取的策略應是LVS,也就是DNS的指向應為LVS均衡器,LVS的優點令它非常適合做這個任務。

重要的ip位址,最好交由LVS託管,例如資料庫的ip、webservice伺服器的ip等等,這些ip位址隨著時間推移,使用面會越來越大,如果更換ip則故障會接踵而至。所以將這些重要ip交給 LVS託管是最為穩健的,這樣做的唯一缺點就是需要的VIP數量會比較多。

Nginx可當LVS節點機器使用,一是可以利用Nginx的功能,二是可以利用Nginx的效能。當然這一層面也可以直接使用squid,squid的功能方面就比Nginx弱不少了,性能上也有所遜色於Nginx。

Nginx也可作為中層代理使用,這一層面Nginx基本上無對手,唯一可以撼動Nginx的就只有lighttpd了,不過lighttpd目前還沒有能做到Nginx完全的功能,配置也不那麼清晰易讀。另外,中層代理的IP也是重要的,所以中層代理也擁有一個VIP和LVS是最完美的方案了。

具體的應用還得具體分析,如果是比較小的網站(日PV小於1000萬),用Nginx就完全可以了,如果機器也不少,可以用DNS輪詢,LVS所耗費的機器還是比較多的;大型網站或重要的服務,機器不煩惱的時候,要多多考慮利用LVS。

推薦學習:《PHP影片教學

以上是【吐血整理】28個關於PHP核心技術的面試題,幫助跳槽!的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:公众号-PHP面试题。如有侵權,請聯絡admin@php.cn刪除