<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ![](https://img.kancloud.cn/29/1f/291f59a028d3b6ed5ef3055aa87865c6_800x320.png) ## 目錄 [TOC] ## 表單提交中的Get和Post的異同點 get 請求一般用于向服務端獲取數據,post 一般向服務端提交數據 get 傳輸的參數在 url 中,傳遞參數大小有限制,post 沒有大小限制, get 不安全,post 安全性比get高 get請求在服務端用Request.queryString 接受 ,post 請求在服務端用Requset.form 接受 ## echo(),print(),print_r()的區別 echo是PHP語句, print和print\_r是函數,語句沒有返回值,函數可以有返回值(即便沒有用) print() 只能打印出簡單類型變量的值(如int,string) print\_r() 可以打印出復雜類型變量的值(如數組,對象) echo 輸出一個或者多個字符串 ## 數組[‘a’, ‘b’, ‘c’] 轉換成字符串 ‘abc’ ~~~ echo implode(‘’,[‘a’, ‘b’, ‘c’]); echo join([‘a’, ‘b’, ‘c’],''); ~~~ ## 獲取字符串’aAbB’中A首次出現的位置 ~~~ $str=‘aAbB’; echo strpos($str,"A"); ~~~ ## 編寫一段用最小代價實現將字符串完全反序, e.g. 將 “1234567890” 轉換成 “0987654321”. ~~~ (1)使用函數 echo strrev("Hello World!"); (2) 不使用函數 $s = '1234567890'; $o = ''; $i = 0; while(isset($s[$i]) && $s[$i] != null) { $o = $s[$i++].$o; } echo $o; ~~~ ## 請用遞歸實現一個階乘求值算法 F(n): n=5;F(n)=5!=5*4*3*2*1=120 ~~~ function F($n){ if($n==0){ return 1; }else{ return $n* F($n-1); } }var_dump(F(5)); ~~~ ## 將字符長fang-zhi-gang 轉化為駝峰法的形式:FangZhiGang //方法一 ~~~ function Fun($str){ if(isset($str) && !empty($str)){ $newStr=''; if(strpos($str,'-')>0){ $strArray=explode('-',$str); $len=count($strArray); for ($i=0;$i<$len;$i++){ $newStr.=ucfirst($strArray[$i]); } } return $newStr; } } ~~~ //方法二 ~~~ function Fun($str){ $arr1=explode('_',$str); $str = implode(' ',$arr1); return ucwords($str); } var_dump(Fun("fang-zhi-gang")); //FangZhiGang ~~~ ## 數組內置的排序方法有哪些? ~~~ sort($array); //數組升序排序 rsort($array); //數組降序排序 asort($array); //根據值,以升序對關聯數組進行排序 ksort($array); //根據建,以升序對關聯數組進行排序 arsort($array); //根據值,以降序對關聯數組進行排序 krsort($array); // 根據鍵,以降序對關聯數組進行排序 ~~~ 可參考:https://www.runoob.com/php/php-arrays-sort.html ## 用PHP寫出顯示客戶端IP與服務器IP的代碼 ~~~ $_SERVER["REMOTE_ADDR"] $_SERVER["SERVER_ADDR"] ~~~ ## 語句include和require的區別是什么?為避免多次包含同一文件,可用(?)語句代替它們? 1、加載失敗的處理方式不同 include與require除了在處理引入文件的方式不同外,最大的區別就是: include在引入不存在的文件時,產生一個警告且腳本還會繼續執行, require則會導致一個致命性錯誤且腳本停止執行。 `<?php` `include?'hello.php';` `echo?'world';` `?>` 如果hello.php不存在,echo ‘world’這句是可以繼續執行的。 `<?php` `require?'hello.php';` `echo?'world';` `?>` 如果hello.php不存在,echo ‘hello’這句是不會執行的,到require時就停止了。 2、include()是有條件包含函數,而 require()則是無條件包含函數。 `if(FALSE){` `include?'file.php';?//file.php不會被引入` `}` `if(FALSE){` `require?'file.php';?//file.php將會被引入` `}` 3、文件引用方式 include有返回值,而require沒有 `$retVal?=?include(’somefile.php’);` `if(!empty($retVal)){` `echo?"文件包含成功";` `}else{` `echo?"文件包含失敗";` `}` 可以用include\_once,require\_once代替,表示文件只引入一次,引入之后則不在引入,作為優化點 ## PHP 不使用第三個變量實現交換兩個變量的值 ~~~ list($b,$a)=array($a,$b); var_dump($a,$b); ~~~ ## 寫一個方法獲取文件的擴展名 ~~~ //方法一 function get_extension($file){ return substr(strrchr($file,'.'), 1); } //方法二 function get_extension($file){ return end(explode('.', $file)); } echo get_extension('fangzhigang.png'); //png ~~~ ## 用PHP打印出前一天的時間格式是2017-3-22 22:21:21 ~~~ $a = date("Y-m-d H:i:s", strtotime("-1 days")); ~~~ ## PHP 如何接口調用? 使用curl調用http接口: ~~~ public function authenticationApi($data,$url){ $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $data); //輸出格式可以轉為數組形式的json格式 $tmpInfo = curl_exec($ch); curl_close($ch); return $tmpInfo; } ~~~ ## 用PHP header()函數實現頁面404錯誤提示功能 ~~~ Header("HTTP/1.1 404 Not Found"); ~~~ ## composer是什么?Composer和PHP有什么關系? Composer是PHP的一個依賴(dependency)管理工具,在我們的項目中聲明所依賴的外部工具庫(libraries),Composer 可以幫助我們安裝這些依賴的庫文件。Composer可以全局安裝也可以局部安裝,默認不是全局安裝的,是基于指定項目的某個目錄進行安裝的。 ## composer團隊協作怎么保證版本統一? 安裝組件使用composer install 而不是composer update, .lock文件加入版本控制當中。 ## OOP思想,特征和其意義 抽象、封裝、繼承和多態是面向對象的基礎。 抽象:提取現實世界中某事物的關鍵特性,為該事物構建模型的過程。對同一事物在不同的需求下,需要提取的特性可能不一樣。得到的抽象模型中一般包含:屬性(數據)和操作(行為)。這個抽象模型我們稱之為類。對類進行實例化得到對象。 封裝:封裝可以使類具有獨立性和隔離性;保證類的高內聚。只暴露給類外部或者子類必須的屬性和操作。類封裝的實現依賴類的修飾符(public、protected和private等) 繼承:對現有類的一種復用機制。一個類如果繼承現有的類,則這個類將擁有被繼承類的所有非私有特性(屬性和操作)。這里指的繼承包含:類的繼承和接口的實現。 多態:多態是在繼承的基礎上實現的。多態的三個要素:繼承、重寫和父類引用指向子類對象。父類引用指向不同的子類對象時,調用相同的方法,呈現出不同的行為;就是類多態特性。多態可以分成編譯時多態和運行時多態。 幫助理解: https://www.cnblogs.com/waj6511988/p/6974291.html ## OOP的七大設計原則是什么? * 開閉原則:對擴展開放,對修改關閉 * 里氏替換原則:繼承 必須保證 父類中的性質在子類中仍然成立 * 依賴倒置原則:面向接口編程,而不面向實現類 * 單一職責原則:控制 類的 粒度的大小 ,增強內聚性,減少耦合 * 接口隔離原則:要為各個類提供所需的專用接口 * 迪米特法則:迪米特法則(Law of Demeter)又叫作最少知識原則(The Least Knowledge Principle),一個類對于其他類知道的越少越好,就是說一個對象應當對其他對象有盡可能少的了解,只和朋友通信,不和陌生人說話。英文簡寫為: LOD。 * 合成復用原則:盡可能使用組合或者聚合等關系來關聯類,其次才考慮使用繼承。 前五個合稱 SOLID原則(單一職責原則、開放關閉原則、里氏替換原則、接口隔離原則和依賴倒置原則) ## mvc框架的生命周期說一下 * model:存放向數據庫請求來的數據 * view:存放組件、圖片、頁面模板html文件 * controller:獲取或改變model里的數據返回給頁面渲染數據 用戶請求進來,先加載配置文件,框架初始化,然后匹配路由地址,尋找到對應的controller的文件地址,引入加載文件,實例化controller,根據路由匹配得到的方法和參數,調用并傳參到方法,此處可能需要讀取db,model層則負責數據庫存取,提供封裝好的方法給到controller層調用,controller層得到數據后,通過引入view層文件,傳遞數據到view層,渲染html模板后輸出。 ![](https://img.kancloud.cn/8f/e2/8fe26fc6abd5efbda1eb1163209adca0_694x509.png) 可以參考:https://www.jb51.net/article/49498.htm ## session與cookie的區別是什么? 1、保持狀態: cookie和session都是用來跟蹤瀏覽器用戶身份的會話方式。 2、使用方式: (1)cookie機制:如果不在瀏覽器中設置過期時間,cookie被保存在內存中,生命周期隨瀏覽器的關閉而結束,這種cookie簡稱會話cookie。如果在瀏覽器中設置了cookie的過期時間,cookie被保存在硬盤中,關閉瀏覽器后,cookie數據仍然存在,直到過期時間結束才消失。 ? ? ?Cookie是服務器發給客戶端的特殊信息,cookie是以文本的方式保存在客戶端,每次請求時都帶上它 (2)session機制:當服務器收到請求需要創建session對象時,首先會檢查客戶端請求中是否包含sessionid。如果有sessionid,服務器將根據該id返回對應session對象。如果客戶端請求中沒有sessionid,服務器會創建新的session對象,并把sessionid在本次響應中返回給客戶端。通常使用cookie方式存儲sessionid到客戶端,在交互中瀏覽器按照規則將sessionid發送給服務器。如果用戶禁用cookie,則要使用URL重寫,可以通過response.encodeURL(url) 進行實現;API對encodeURL的結束為,當瀏覽器支持Cookie時,url不做任何處理;當瀏覽器不支持Cookie的時候,將會重寫URL將SessionID拼接到訪問地址后。 3、存儲內容: cookie只能保存字符串類型,以文本的方式;session通過類似與Hashtable的數據結構來保存,能支持任何類型的對象(session中可含有多個對象) 4、存儲的大小: cookie:單個cookie保存的數據不能超過4kb; session大小沒有限制。 5、安全性: cookie:針對cookie所存在的攻擊:Cookie欺騙,Cookie截獲; session的安全性大于cookie。 ## 為什么session的安全性大于cookie? 1. sessionID存儲在cookie中,若要攻破session首先要攻破cookie; 2. sessionID是要有人登錄,或者啟動session\_start才會有,所以攻破cookie也不一定能得到sessionID; 3. 第二次啟動session\_start后,前一次的sessionID就是失效了,session過期后,sessionID也隨之失效。 4. sessionID是加密的 5. 綜上所述,攻擊者必須在短時間內攻破加密的sessionID,這很難。 ## session與cookie的應用場景有哪些? cookie: (1)判斷用戶是否登陸過網站,以便下次登錄時能夠實現自動登錄(或者記住密碼)。如果我們刪除cookie,則每次登錄必須從新填寫登錄的相關信息。 (2)保存上次登錄的時間等信息。 (3)保存上次查看的頁面。 (4)瀏覽計數。 session: Session用于保存每個用戶的專用信息,變量的值保存在服務器端,通過SessionID來區分不同的客戶。 (1)網上商城中的購物車。 (2)保存用戶登錄信息。 (3)將某些數據放入session中,供同一用戶的不同頁面使用。 (4)防止用戶非法登錄。 ## php7新特性 標量類型聲明 返回值類型聲明 語法糖:null合并運算符,太空船操作符 define允許定義常量數組, 匿名類, 新增了一些函數intdiv(),隨機函數, **1、php7.0相比于php5.6的新特性** 參考:http://php.net/manual/zh/migration70.new-features.php **2、php7.1相對于php7.0的新特性** 參考:http://php.net/manual/zh/migration71.new-features.php **3、php7.2相對于php7.1的新特性** 參考:http://php.net/manual/zh/migration72.new-features.php ## php8新特性 新增聯合類型(Union Types); 添加了 WeakMap; 添加了 ValueError 類; 新增的特性大多是語法糖,主要是JIT。 JIT是一種編譯器策略,它將代碼表述為一種中間狀態,在運行時將其轉換為依賴于體系結構的機器碼,并即時執行,在PHP8中,Zend VM不需要解釋某些操作碼,并且這些指令將直接作為CPU級指令執行。 **IT和opcache區別** 要說明opcode cache與JIT的區別,得先明白,**字節碼,又叫中間碼與機器碼的區別。** 簡答的說,提升php執行效率,更快了。 JIT參考[鳥哥博客](https://www.laruence.com/2020/06/27/5963.html) ## 手寫一個單例模式吧 所謂單例模式,即在應用程序中最多只有該類的一個實例存在,一旦創建,就會一直存在于內存中! 單例設計模式常應用于數據庫類設計,采用單例模式,只連接一次數據庫,防止打開多個數據庫連接。 單例模式的編寫遵循**三私一公**,代碼如下 ~~~ <?php class Database { private $instance; private function__construct() { // Do nothing. } private function__clone() { // Do nothing. } public static function getInstance() { if (!(self::$instance instanceof self)) { self::$instance = new self(); } return self::$instance; } } $a = Database::getInstance(); $b = Database::getInstance(); // true var_dump($a === $b); ~~~ ## php垃圾回收機制 >關鍵詞:使用了引用計數器 1. PHP可以自動進行內存管理,清除不需要的對象,主要使用了引用計數。 2. 在zval結構體中定義了ref\_count和is\_ref , ref\_count是引用計數 ,標識此zval被多少個變量引用 , 為0時會被銷毀 。 is\_ref標識是否使用的 &取地址符強制引用。 3. 為了解決循環引用內存泄露問題 , 使用同步周期回收算法。 4. 當數組或對象循環的引用自身 , unset掉數組的時候 , 當refcount-1后還大于0的 , 就會被當成疑似垃圾 , 會進行遍歷 ,并且模擬的刪除一次refcount-1如果是0就刪除 ,如果不是0就恢復。 參考:https://www.php.net/manual/zh/features.gc.php ## php-fpm是什么? PHP5.3.3開始集成了php-fpm模塊,不再是第三方的包了。PHP-FPM提供了更好的PHP[進程管理](https://baike.baidu.com/item/%E8%BF%9B%E7%A8%8B%E7%AE%A1%E7%90%86)方式,可以有效控制內存和進程、可以平滑[重載](https://baike.baidu.com/item/%E9%87%8D%E8%BD%BD)PHP配置。 重點: >php-fpm是fastcgi的實現。 ## php-fpm的運行模型? >多進程同步阻塞模式 php-fpm是一種master(主)/worker(子)多進程架構模型。 當PHP-FPM啟動時,會讀取配置文件,然后創建一個Master進程和若干個Worker進程(具體是幾個Worker進程是由php-fpm.conf中配置的個數決定)。Worker進程是由Master進程fork出來的。 master進程主要負責CGI及PHP環境初始化、事件監聽、Worker進程狀態等等,worker進程負責處理php請求。 master進程負責創建和管理woker進程,同時負責監聽listen連接,master進程是多路復用的;woker進程負責accept請求連接,同時處理請求,一個woker進程可以處理多個請求(復用,不需要每次都創建銷毀woker進程,而是達到處理一定請求數后銷毀重新fork創建worker進程),但一個woker進程一次只能處理一個請求。 ![](https://img.kancloud.cn/41/ed/41ed99b258dd1703acd803c8de18db1f_640x226.png) ## cgi,php-cgi,php-fpm,fastcgi的區別? * **cgi** cgi是一個web server與cgi程序(這里可以理解為是php解釋器)之間進行數據傳輸的協議,保證了傳遞的是標準數據。 * **php-cgi** php-cgi是php解釋器。他自己本身只能解析請求,返回結果,不會管理進程。php-fpm是調度管理php-cgi進程的程序。 * **Fastcgi** Fastcgi是用來提高cgi程序(php-cgi)性能的方案/協議。 cgi程序的性能問題在哪呢?"PHP解析器會解析php.ini文件,初始化執行環境",就是這里了。標準的CGI對每個請求都會執行這些步驟,所以處理的時間會比較長。 Fastcgi會先啟一個master,解析配置文件,初始化執行環境,然后再啟動多個worker。當請求過來時,master會傳遞給一個worker,然后立即可以接受下一個請求。這樣就避免了重復勞動,效率自然提高。而且當worker不夠用時,master可以根據配置預先啟動幾個worker等著;當然空閑worker太多時,也會停掉一些,這樣就提高了性能,也節約了資源。這就是Fastcgi的對進程的管理。 * **php-fpm** fastcgi是一個方案或者協議,php-fpm就是FastCGI的后端實現,也就是說,進程分配和管理是FPM來做的。官方對FPM的解釋:【Fastcgi Process Manager】【Fastcgi 進程管理器】。 php-fpm的管理對象是php-cgi,他負責管理一個進程池,來處理來自Web服務器的請求。 對于php.ini文件的修改,php-cgi進程是沒辦法平滑重啟的,有了php-fpm后,就把平滑重啟成為了一種可能,php-fpm對此的處理機制是新的worker用新的配置,已經存在的worker處理完手上的活就可以歇著了,通過這種機制來平滑過度的。 ## php-fpm如何完成平滑重啟? 修改php.ini之后,php-cgi進程的確是沒辦法平滑重啟的。php-fpm對此的處理機制是新的worker用新的配置,已經存在的worker處理完手上的活就可以歇著了,通過這種機制來平滑過度。 ## php-fpm和nginx的通信機制是怎么樣的? 看下nginx的配置文件: Nginx中fastcgi\_pass的配置: ~~~ location ~ .php$ { root /home/wwwroot; fastcgi\_pass 127.0.0.1:9000; #fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock; #fastcgi_pass unix:/tmp/php-cgi.sock; try_files $uri /index.php =404; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } ~~~ 因為nginx不能直接執行php,所以需要借用fastcgi模塊,和php-fpm進行通信。有兩種方式; 1. TCP 2. UNIX Domain Socket TCP是IP加端口,可以跨服務器; 而UNIX Domain Socket不經過網絡,只能用于Nginx跟PHP-FPM都在同一服務器的場景。具體配置: ~~~ 方式1: php-fpm.conf: listen = 127.0.0.1:9000 nginx.conf: fastcgi_pass 127.0.0.1:9000; 方式2: php-fpm.conf: listen = /tmp/php-fpm.sock nginx.conf: fastcgi_pass unix:/tmp/php-fpm.sock; ~~~ 值得一提的是,MySQ命令行客戶端連接mysqld服務也類似有這兩種方式: 使用Unix Socket連接(默認): ~~~ mysql -uroot -p --protocol=socket --socket=/tmp/mysql.sock ~~~ 使用TCP連接: ~~~ mysql -uroot -p --protocol=tcp --host=127.0.0.1 --port=3306 ~~~ ## 怎么選定用tcp還是套接字的方式和nginx通信? tcp方式是面向鏈接的協議,更穩定。 套接字效率更高,但是限制nginx和php-fpm都在一臺服務器。 ## php-fpm在請求鏈路的體現,畫出來? ~~~ www.example.com | | \!/ Nginx | | \!/ 路由到www.example.com/index.php | | \!/ 加載nginx的fast-cgi模塊 | | \!/ fast-cgi監聽127.0.0.1:9000地址 | | \!/ www.example.com/index.php請求到達127.0.0.1:9000 | | \!/ php-fpm 監聽127.0.0.1:9000 | | \!/ php-fpm 接收到請求,啟用worker進程處理請求 | | \!/ php-fpm 處理完請求,返回給nginx | | \!/ nginx將結果通過http返回給瀏覽器 ~~~ ## php-fpm有幾種工作模式? PHP-FPM進程管理方式有動態(Dynamic)、靜態(Static)、按需分配(Ondemand)三種。 **動態** 會初始化創建一部分worker,在運行過程中,動態調整worker數量,最大worker數受pm.max\_children和process.max ~~~csharp listen = 127.0.0.1:9001 pm = dynamic pm.max_children = 10 pm.start_servers = 2 pm.min_spare_servers = 1 pm.max_spare_servers = 6 ~~~ 1. 當空閑進程數小于min\_spare\_servers時,創建新的子進程,總子進程數小于等于pm.max\_children,小于等于process.max 2. 當空閑進程數大于max\_spare\_servers,會殺死啟動時間最長的子進程 3. 如果子進程(idle狀態)數大于max\_children,會打印warning日志,結束處理 4. process小于 max\_children ,計算一個num,啟動num個worker 5. 優點:動態擴容,不浪費系統資源 6. 缺點:所有worker都在工作,新的請求到來需要等待創建worker進程,最長等待1s(內部存在一個1s的定時器,去查看,創建進程),頻繁啟停進程消耗cpu,請求數穩定,不需要頻繁銷毀 **靜態** 啟動固定大小數量的worker,也有1s的定時器,用于統計進程的一些狀態信息,例如空閑worker個數,活動worker個數 ~~~bash pm.max_children = 10 #必須配置這個參數,而且只有這個參數有效 ~~~ 1. 優點:不用動態判斷負載,提升性能 2. 缺點:如果配置成static,只需要考慮max\_children數量,數量取決于cpu的個數和應用的響應時間,一次啟動固定大小進程浪費系統資源 **按需分配** php-fpm啟動的時候不會啟動worker進程,按需啟動worker,有鏈接進來后,才會啟動 ~~~undefined listen = 127.0.0.1:9001 pm = ondemand pm.process_idle_timeout = 60 pm.max_children = 10 ~~~ 連接到來時(只有鏈接,不沒有數據也會創建,telnet也會創建),創建新worker進程,worker進程數的創建收max\_children設置限制,也受限于全局的process.max設置(三種模式都受限此,下文中有全局配置項講解),如果空閑時間超過了process\_idle\_timeout的設置就會銷毀worker進程 * 優點:按流量需求創建,不浪費系統資源, * 缺點:因為php-fpm是短連接的,如果每次請求都先建立連接,大流量場景下會使得master進程變得繁忙,浪費cpu,不適合大流量模式 * 不推薦使用此模式 | 工作模式 | 特點 | | --- | --- | | 動態 | 均衡優先,適合小內存服務器,2g左右 | | 靜態 | 性能優先, 適合大內存機器 | | 按需分配 | 內存優先,適合微小的內存,2g以下 | ## 怎么選定php-fpm的worker進程數? * 動態建立進程個數 * N+20% 到 M/m之間 * N是cpu核數,M是內存,m是每個php進程內存數 * 靜態進程個數 * M/(m\*1.2) * pm.max_requests, 設置最大請求數,達到這個數量以后,會自動長期worker進程,繁殖內存意外增長 注意:PHP程序在執行完成后,或多或少會有內存泄露的問題。這也是為什么開始的時候一個php-fpm進程只占用3M左右內存,運行一段時間后就會上升到20-30M。所以需要每個worker進程處理完一定的請求后,銷毀重新創建。 cpu密集型的pm.max_children不能超過cpu內核數,但是web服務屬于IO密集型的,可以將pm.max_children的值設置大于cpu核數。 ## php-fpm如何優化? (1)避免程序跑死(hang) 在負載較高的服務器上定時重載php-fpm,reload可以平滑重啟而不影響生產系統的php腳本運行,每15分鐘reload一次,定時任務如下: ~~~ 0-59/15 * * * * /usr/local/php/sbin/php-fpm reload ~~~ (2)合理增加單個worker進程最大處理請求數,減少內存消耗 最大處理請求數是指一個php-fpm的worker進程在處理多少個請求后就終止掉,master進程會重新respawn新的。該配置可以避免php解釋器自身或程序引起的memory leaks。默認值是500,可以修改為如下配置: ~~~ pm.max_requests = 1024 ~~~ (3)開啟靜態模式,指定數量的php-fpm進程,減少內存消耗 ## 說下你最常用的php框架(laravel框架)的生命周期? Laravel 是單入口文件的mvc重型框架,里面集成了消息隊列,orm,ioc等功能模塊。laravel的生命周期簡述如下: 從`public\index.php`開始。 注冊加載composer自動生成的`class loader`,初始化第三方依賴,laravel本身實現的也已經高度組件化了。 使用上一步生成的容器`Container`類,從`bootstrap/app.php`腳本獲取 Laravel 應用實例,注冊laravel核心組件。 如果是web請求不是命令行請求,那么**創建 Laravel HTTP Kernel 核心**,請求被發送到`HTTP`內核。 HTTP 內核繼承自 Illuminate\\Foundation\\Http\\Kernel 類,這個類中擁有三個核心成員變量 $app,$router,$bootstrappers。 ~~~ protected $app; protected $router; protected $bootstrappers \= \[ \\Illuminate\\Foundation\\Bootstrap\\LoadEnvironmentVariables::class, # 加載 .env 中的配置信息 \\Illuminate\\Foundation\\Bootstrap\\LoadConfiguration::class, # 加載 config 目錄中所有配置文件的配置信息 \\Illuminate\\Foundation\\Bootstrap\\HandleExceptions::class, # 異常處理 \\Illuminate\\Foundation\\Bootstrap\\RegisterFacades::class, # 注冊門面 \\Illuminate\\Foundation\\Bootstrap\\RegisterProviders::class, # 注冊Service Providers \\Illuminate\\Foundation\\Bootstrap\\BootProviders::class, # 注冊啟動器 \]; ~~~ $app 咱們已經說了足夠多,就是應用容器,我們所有的工作都在這個容器中進行。 $router 路由對象,它提供路由相關的服務,幫助我們把網絡請求分配給對應的路由進行邏輯處理,然后把處理的結果(網絡響應)返回給我們,我們在web.php中定義的路由就是由它來管理的。 $bootstrappers 數組,這個數組中的任務項在網絡請求被處理前運行,我們可以看到**環境檢查,配置加載,異常處理,Facedes 門面注冊,ServiceProvider 注冊**等等任務都需要在網絡請求被處理前被首先執行,而且這些任務是有前后順序的,排在前面的會首先執行,這也很容易理解,因為不管是 Facades 還是 Service Providers 都是定義在 config 目錄中的 app.php 文件中的,只有加載來配置之后才能注冊門面和Service Providers。 結束請求,進行回調,終止 Laravel 應用,Laravel 到此也完成了它的歷史使命。中間件中有一類的中間件,terminable middleware 的處理邏輯就是在這個階段執行的。 **擴展知識【中間件】** Middleware?,在 Kernel 以及它的基類?Illuminate\\Foundation\\Http\\Kernel 中定義了一系列的 middlewares ,借助這些中間件,就可以完成對用戶請求的過濾和安全檢查等等功能。 ~~~ public function __construct(Application $app, Router $router) { $this->app = $app; $this->router = $router; $route->middlewarePriority = $this->middlewarePriority; foreach ($this->middlewareGroups as $key => $middleware) { $router->middlewareGroup($key, $middleware); } foreach ($this->routeMiddleware as $key => $middleware) { $router->aliasMiddleware($key, $middleware); } } ~~~ 中間件的作用:所有請求在處理前需要經過的 HTTP[中間件](https://laravel.com/docs/5.4/middleware),這些中間件處理[HTTP 會話](https://laravel.com/docs/5.4/session)的讀寫、判斷應用是否處于維護模式、驗證[CSRF 令牌](https://laravel.com/docs/5.4/csrf)等等。 ![](https://img.kancloud.cn/1d/1e/1d1e54555ca319d5aaee750cec85661f_572x508.png) **laravel請求生命周期流程圖,如下** ![](https://img.kancloud.cn/92/26/922612cbdd637e1d8f8210b16558b445_1748x696.png) ## 怎么理解 依賴注入(DI)與控制反轉(Ioc)? >這讓我想起了怎么理解nginx正向代理和反向代理... IOC(inversion of control)控制反轉模式;控制反轉是將組件間的依賴關系從程序內部提到外部來管理; DI(dependency injection)依賴注入模式;依賴注入是指將組件的依賴通過外部以參數或其他形式注入; 依賴注入和控制反轉說的實際上是同一個東西,它們是一種設計模式,這種設計模式用來減少程序間的耦合。依賴注入和控制反轉是對同一件事情的不同描述,從某個方面講,就是它們描述的角度不同。 *1*、依賴注入是從應用程序的角度在描述,可以把依賴注入,即:應用程序依賴容器創建并注入它所需要的外部資源; *2*、而控制反轉是從容器的角度在描述,即:容器控制應用程序,由容器反向的向應用程序注入應用程序所需要的外部資源。 **laravel的控制反轉** 是通過反射和遞歸實現的容器,容器作為全局注冊表,使用容器的依賴注入做為一種橋梁來解決依賴,使類之間耦合度更低。 ## php的弱類型是怎么實現的? php是通過c語言進行實現,但是c語言為強類型,那php的弱語言類型是通過PHP底層設計了一個zval(“Zend value”的縮寫)的數據結構,可以用來表示任意類型的PHP值。通過**共同體**實現弱類型變量聲明。 ## 簡單說下對php 底層變量(zval)數據結構的理解 1\. 變量存儲結構 變量的值存儲到以下所示zval結構體中。 zval結構體定義在Zend/zend.h文件,其結構如下: ~~~ typedef struct _zval_struct zval; ... struct _zval_struct { /* Variable information */ zvalue_value value; /* value */ zend_uint refcount__gc; zend_uchar type; /* active type */ zend_uchar is_ref__gc; }; ~~~ PHP使用這個結構來存儲變量的所有數據。和其他編譯性靜態語言不同, PHP在存儲變量時將PHP用戶空間的變量類型也保存在同一個結構體中。這樣我們就能通過這些信息獲取到變量的類型。 zval結構體中有四個字段,其含義分別為: | 屬性名 | 含義 | 默認值 | | :-- | :-- | :-: | | refcount\_\_gc | 表示引用計數 | 1 | | is\_ref\_\_gc | 表示是否為引用 | 0 | | value | 存儲變量的值 | ? | | type | 變量具體的類型 | ? | 2.變量類型: zval結構體的type字段就是實現弱類型最關鍵的字段了,type的值可以為: IS\_NULL、IS\_BOOL、IS\_LONG、IS\_DOUBLE、IS\_STRING、IS\_ARRAY、IS\_OBJECT和IS\_RESOURCE 之一。 從字面上就很好理解,他們只是類型的唯一標示,根據類型的不同將不同的值存儲到value字段。 除此之外,和他們定義在一起的類型還有IS\_CONSTANT和IS\_CONSTANT\_ARRAY。 這和我們設計數據庫時的做法類似,為了避免重復設計類似的表,使用一個標示字段來記錄不同類型的數據。 ## 常見的設計模式有哪些? 簡單說下單例模式,注冊樹模式,適配模式,策略模式,觀察者模式。 **單例模式** 記住三私一公,最容易考察現場擼碼的題。 **工廠模式** ~~~ //簡單工廠模式 //適用場景:創建對象比較少,業務邏輯不太復雜 <?php //產品 class bike { public function product($destination) { print_r($destination); } } class car { public function product($destination) { print_r($destination); } } //工廠 class simpleFactory { public function createBike($obj) { return new $obj(); } } $factory = new simpleFactory(); $bike = $factory->createBike("bike"); $bike->product("hello,bike"); $car = $factory->createBike("car"); $car->product("hello,car"); ?> ~~~ **觀察者模式** ~~~ //觀察者模式 //適用場景:訂閱者通知 //自己對觀察者模式對理解: 需求:有事情變化你要通知我 實現: 1、要通知對人必須在我這里注冊,否則我不知道要通知誰。 2、想要獲取通知的人必須遵守我的規則,實現我指定的通知事件,不然我沒辦法統一通知,(比如高考查分數,只支持電話查詢,你非要微信查我肯定通知不到你) 3、事件發生的時候我會逐一通知你們。 <?php //定義一個事件產生接口 abstract class genEvent { private $ob_servers = []; //增加觀察者 public function addObs($ob_server) { $this->ob_servers[] = $ob_server; } //通知 public function notify() { if(!empty($this->ob_servers)) { foreach($this->ob_servers as $ob_server) { $ob_server->update(); } } } } //定義觀察者接口 interface obServer{ public function update($event_info = null); } class obServer1 implements obServer{ public function update($event_info = null){ echo "觀察者1 收到執行通知\n"; } } class obServer2 implements obServer{ public function update($event_info = null){ echo "觀察者2 收到執行通知\n"; } } class event extends genEvent{ //事件觸發 public function trigger() { $this->notify(); } } //實現 $event = new event(); $event->addObs(new obServer1()); $event->addObs(new obServer2()); $event->trigger(); ?> ~~~ **適配器模式** ~~~ <?php //定義抽象類 abstract class Toy { public abstract function openMouth(); public abstract function closeMouth(); } //定義dog class dog extends Toy { public function openMouth() { echo "Dog open Mouth\n"; } public function closeMouth() { echo "Dog close Mouth\n"; } } //cat class cat extends Toy { public function openMouth() { echo "Cat open Mouth\n"; } public function closeMouth() { echo "Cat close Mouth\n"; } } //紅棗狗可以自己判斷開關 interface redTarget { public function doMouthOpen(); public function doMouthClose(); } interface greenTarget { public function operateMouth($type=0); } //組成適配器 class redAdapter implements redTarget { private $adaptee; //初始化對象 public function __construct(Toy $adaptee) { $this->adaptee = $adaptee; } //委派調用Adaptee的sampleMethod1方法 public function doMouthOpen() { $this->adaptee->openMouth(); } public function doMouthClose() { $this->adaptee->closeMouth(); } } //組成綠色遙控 class greenAdapter implements greenTarget { private $adapter; //初始化對象 public function __contruct(Toy $adapter) { $this->adapter = $adapter; } public function operateMouth($type = 0) { $type ? $this->adapter->openMouth() : $this->adapter->closeMouth(); } } //測試 class testDriver { public function run() { //實例化玩具狗 $dog = new dog(); $adapter_dog = new redAdapter($dog); $adapter_dog->doMouthOpen(); $adapter_dog->doMouthClose(); } } $test = new testDriver(); $test->run(); ?> ~~~ **注冊樹模式** ~~~ //創建單例 class Single{ public $hash; static protected $ins=null; final protected function __construct(){ $this->hash=rand(1,9999); } static public function getInstance(){ if (self::$ins instanceof self) { return self::$ins; } self::$ins=new self(); return self::$ins; } } //工廠模式 class RandFactory{ public static function factory(){ return Single::getInstance(); } } //注冊樹 class Register{ protected static $objects; public static function set($alias,$object){ self::$objects[$alias]=$object; } public static function get($alias){ return self::$objects[$alias]; } public static function _unset($alias){ unset(self::$objects[$alias]); } } //調用 Register::set('rand',RandFactory::factory()); $object=Register::get('rand'); print_r($object); ~~~
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看