PHP從基礎到高級總結

1、 PHP基礎

基礎類型: integer, string,  boolean, float, array, object, resource, NULL
    標量類型: boolean、integer、float/double、string
    複合類型: array 、 object
    特殊類型: resource、 null

超級全局變量:
    $GLOBALS, $_SERVER, $_REQUEST, $_POST, $_GET, $_COOKIE, $_FILES, $_ENV, $_SESSION

    $_POST
        可以接收類型:
            application/x-www-form-urlencoded
            multipart/form-data
    php://input
        訪問請求的原始數據的只讀流, 包括$_POST支持的類型和application/json
            //php
            $_POST = json_decode(file_get_contents('php://input'),true);

    $_SERVER['PHP_SELF']            返回當前執行腳本的文件名。
    $_SERVER['GATEWAY_INTERFACE']   返回服務器使用的 CGI 規範的版本。
    $_SERVER['SERVER_ADDR']         返回當前運行腳本所在的服務器的 IP 地址。
    $_SERVER['SERVER_NAME']         返回當前運行腳本所在的服務器的主機名(好比 www.baidu.cn)。
    $_SERVER['SERVER_SOFTWARE']     返回服務器標識字符串(好比 Apache/2.2.24)。
    $_SERVER['SERVER_PROTOCOL']     返回請求頁面時通訊協議的名稱和版本(例如,「HTTP/1.0」)。
    $_SERVER['REQUEST_METHOD']      返回訪問頁面使用的請求方法(例如 POST)。
    $_SERVER['REQUEST_TIME']        返回請求開始時的時間戳(例如 1577687494)。
    $_SERVER['QUERY_STRING']        返回查詢字符串,若是是經過查詢字符串訪問此頁面。
    $_SERVER['HTTP_ACCEPT']         返回來自當前請求的請求頭。
    $_SERVER['HTTP_ACCEPT_CHARSET'] 返回來自當前請求的 Accept_Charset 頭( 例如 utf-8,ISO-8859-1)
    $_SERVER['HTTP_HOST']           返回來自當前請求的 Host 頭。
    $_SERVER['HTTP_REFERER']        返回當前頁面的完整 URL(不可靠,由於不是全部用戶代理都支持)。
    $_SERVER['HTTPS']               是否經過安全 HTTP 協議查詢腳本。
    $_SERVER['REMOTE_ADDR']         返回瀏覽當前頁面的用戶的 IP 地址。
    $_SERVER['REMOTE_HOST']         返回瀏覽當前頁面的用戶的主機名。
    $_SERVER['REMOTE_PORT']         返回用戶機器上鍊接到 Web 服務器所使用的端口號。
    $_SERVER['SCRIPT_FILENAME']     返回當前執行腳本的絕對路徑。
    $_SERVER['SERVER_ADMIN']        該值指明瞭 Apache 服務器配置文件中的 SERVER_ADMIN 參數。
    $_SERVER['SERVER_PORT']         Web 服務器使用的端口。默認值爲 「80」。
    $_SERVER['SERVER_SIGNATURE']    返回服務器版本和虛擬主機名。
    $_SERVER['PATH_TRANSLATED']     當前腳本所在文件系統(非文檔根目錄)的基本路徑。
    $_SERVER['SCRIPT_NAME']         返回當前腳本的路徑。
    $_SERVER['SCRIPT_URI']          返回當前頁面的 URI。


PHP全局處理:
    register_shutdown_function //註冊一個會在php停止時執行的函數
    set_error_handler          //設置用戶自定義的錯誤處理函數(用戶級別錯誤,trigger_error)
    set_exception_handler      //設置用戶自定義的異常處理函數(用戶級別異常,throw)
    session_set_save_handler   //設置用戶自定義會話存儲函數
    spl_autoload_register      //自動加載器, 區別於__auto_load()只能加載一次

魔術變量:
    __LINE__    文件中的當前行號
    __FILE__    文件的完整路徑和文件名。若是用在被包含文件中,則返回被包含的文件名。
    __DIR__     文件所在的目錄。若是用在被包括文件中,則返回被包括的文件所在的目錄。
    __FUNCTION__    函數被定義時的名字(區分大小寫)。
    __CLASS__   類被定義時的名字。
    __METHOD__  類中的方法被定義時的名字。
    __NAMESPACE__   當前命名空間的名稱。

PHP魔術方法:
    對象析構、解構
        __construct     對象析構函數
        __destruct      對象解構函數
    屬性重載
        __set          給不可訪問屬性賦值時調用
        __get          讀取不可訪問屬性的值時調用
        __isset        對不可訪問屬性調用 isset() 或 empty() 時調用
        __unset        對不可訪問屬性調用 unset() 時調用
    方法重載
        __call         在對象中調用一個不可訪問方法時調用
        __callStatic   在靜態上下文中調用一個不可訪問方法時調用, 靜態方式調用該方法
    對象序列化
        __sleep        對對象進行serialize()時調用, 用於清理對象,並返回一個包含對象中全部應被序列化的變量名稱的數組。
        __wakeup       unserialize()時調用, 用於預先準備對象須要的資源。
    對象字符串化
        __toString     類被當成字符串時返回一個字符串。
    對象調用函數化
        __invoke       當嘗試以調用函數的方式調用一個對象時調用
    導出類
        __set_state    當調用 var_export() 導出類時, 靜態方式調用該方法
        __debugInfo    當調用var_dump() 打印類時,若是定義該方法則只會打印該方法返回值,不然打印所有成員



設置、異常、錯誤處理:
    設置
        ini_set('max_execution_time', -1);              腳本執行的超時時間
        ini_set('default_socket_timeout', -1);          基於socket流的默認超時時間
        ini_set('memory_limit', -1);                    設置腳本執行最大內存
        ini_set('error_reporting', E_ALL | E_STRICT);   錯誤級別
        ini_set('display_errors', 'On');                開啓錯誤回寫,開啓狀態下,若出現錯誤,則報錯,出現錯誤提示
        ini_set('log_errors', 'On');                    開啓錯誤日誌, 記錄到error_log指定的路徑
        ini_set('date.timezone','Asia/Shanghai');       時區設置
        error_reporting(7);                             錯誤級別,同ini配置
        set_time_limit(0);                              設置腳本最大執行時間,同ini配置, 隻影響腳本自己執行的時間
        ignore_user_abort();                            關閉瀏覽器,PHP後臺繼續運行

    函數、描述:
        debug_backtrace()   生成 backtrace。
        debug_print_backtrace() 打印 backtrace。
        error_get_last()    返回最後發生的錯誤。
        error_log() 向服務器錯誤記錄、文件或遠程目標發送錯誤消息。
        error_reporting()   規定報告哪一個錯誤。
        restore_error_handler() 恢復以前的錯誤處理程序。
        restore_exception_handler() 恢復以前的異常處理程序。
        set_error_handler() 設置用戶自定義的錯誤處理函數。
        set_exception_handler() 設置用戶自定義的異常處理函數。
        trigger_error() 建立用戶級別的錯誤消息。
        user_error()    trigger_error() 的別名。
    錯誤類型:
        1       E_ERROR 運行時致命的錯誤。不能修復的錯誤。終止執行腳本。
        2       E_WARNING   運行時非致命的錯誤。不終止執行腳本。
        4       E_PARSE 編譯時語法解析錯誤。解析錯誤僅僅由分析器產生。
        8       E_NOTICE    運行時通知。表示腳本遇到可能會表現爲錯誤的狀況,可是在能夠正常運行的腳本里面也可能會有相似的通知。
        16      E_CORE_ERROR    在 PHP 初始化啓動過程當中發生的致命錯誤。該錯誤相似 E_ERROR,可是是由 PHP 引擎核心產生的。
        32      E_CORE_WARNING  PHP 初始化啓動過程當中發生的警告 (非致命錯誤) 。相似 E_WARNING,可是是由 PHP 引擎核心產生的。
        64      E_COMPILE_ERROR 致命編譯時錯誤。相似 E_ERROR, 可是是由 Zend 腳本引擎產生的。
        128     E_COMPILE_WARNING   編譯時警告 (非致命錯誤)。相似 E_WARNING,可是是由 Zend 腳本引擎產生的。
        256     E_USER_ERROR    用戶產生的錯誤信息。相似 E_ERROR, 可是是由用戶本身在代碼中使用PHP函數 trigger_error()來產生的。
        512     E_USER_WARNING  用戶產生的警告信息。相似 E_WARNING, 可是是由用戶本身在代碼中使用 PHP 函數 trigger_error() 來產生的。
        1024    E_USER_NOTICE   用戶產生的通知信息。相似 E_NOTICE, 可是是由用戶本身在代碼中使用 PHP 函數 trigger_error() 來產生的。
        2048    E_STRICT    啓用 PHP 對代碼的修改建議,以確保代碼具備最佳的互操做性和向前兼容性。
        4096    E_RECOVERABLE_ERROR 可被捕捉的致命錯誤。它表示發生了一個可能很是危險的錯誤,可是尚未致使 PHP 引擎處於不穩定的狀態。 若是該錯誤沒有被用戶自定義句柄捕獲 (參見 set_error_handler()),將成爲一個 E_ERROR 從而腳本會終止運行。
        8192    E_DEPRECATED    運行時通知。啓用後將會對在將來版本中可能沒法正常工做的代碼給出警告。
        16384   E_USER_DEPRECATED   用戶產生的警告信息。相似 E_DEPRECATED, 可是是由用戶本身在代碼中使用 PHP 函數 trigger_error() 來產生的。
        32767   E_ALL   E_STRICT 除非的全部錯誤和警告信息。
垃圾回收機制
    < 5.2
        若是refcount值爲0,PHP會當作垃圾釋放掉
        這種回收機制有缺陷,對於環狀引用的變量沒法回收
    >= 5.3
        發現一個zval容器中的refcount在增長,說明不是垃圾
        發現一個zval容器中的refcount在減小,若是減到了0,直接當作垃圾回收
        發現一個zval容器中的refcount在減小,並無減到0,PHP會把該值放到緩衝區,當作有多是垃圾的懷疑對象。
        當緩衝區達到了臨界值,PHP會自動調用一個方法去遍歷每個值,若是發現是垃圾就清理

    引用計數:
        ## php4-php6
        * php變量存在一個叫"zval"的變量容器中。
        * zval變量容器包含:變量值(value)、變量類型(type)、是不是屬於引用集合(is_ref__gc)、引用次數(refcount__gc)
        * 新變量中"is_ref"被默認設置爲 FALSE,由於沒有任何自定義的引用生成。
        * xdebug_debug_zval()顯示"refcount"和"is_ref"的值。
        * 把一個變量賦值給另外一變量將增長引用次數(refcount)。


    回收機制:
        < 5.2
            若是refcount值爲0,PHP會當作垃圾釋放掉
            這種回收機制有缺陷,對於環狀引用的變量沒法回收
        >= 5.3
            發現一個zval容器中的refcount在增長,說明不是垃圾
            發現一個zval容器中的refcount在減小,若是減到了0,直接當作垃圾回收
            發現一個zval容器中的refcount在減小,並無減到0,PHP會把該值放到緩衝區,當作有多是垃圾的懷疑對象。
            當緩衝區達到了臨界值,PHP會自動調用一個方法去遍歷每個值,若是發現是垃圾就清理
        具體:
         * 使用引用計數器和同步算法來進行處理
         * 把全部可能根變量容器,放在根緩衝區,在根緩衝區滿了時,纔對緩衝區內部全部不一樣的變量容器執行垃圾回收操做。
         * 引用計數減小,將會推到垃圾回收週期,經過檢查哪些變量容器的引用次數是零,來發現哪部分是垃圾。
         * 引用計數減小到零,所在變量容器將被清除(free)。

2、 PHP-fpm

基本操做
    #啓動PHP服務
    /usr/local/php/sbin/php -S 127.0.0.1:8080 -t [目錄] [&]

    #啓動php-fpm
    /usr/local/php/sbin/php-fpm
    /usr/local/php/sbin/php-fpm -c /usr/local/php/etc/php.ini -y /usr/local/php/etc/php-fpm.conf

    #關閉php-fpm
    kill -INT `cat /usr/local/php/var/run/php-fpm.pid`

    #重啓php-fpm
    kill -USR2 `cat /usr/local/php/var/run/php-fpm.pid`

工做原理
    PHP提供的SAPI
        apache2handler 、mode_php
        fastcgi
        cli
        isapi

    FastCGI的工做原理:
        1. Server啓動時載入FastCGI進程管理器
        2. FastCGI進程管理器自身初始化,啓動多個CGI解釋器進程(可見多個php-cgi)並等待來自Server的鏈接
        3. 當客戶端請求到達Server時,FastCGI進程管理器選擇並鏈接到一個CGI解釋器。
           Web server將CGI環境變量和標準輸入發送到FastCGI子進程php-cgi。
        4. FastCGI子進程完成處理後將標準輸出和錯誤信息從同一鏈接返回Server。
            當FastCGI子進程關閉鏈接時,請求便告處理完成。
            FastCGI子進程接着等待並處理來自FastCGI進程管理器(運行在Web Server中)的下一個鏈接。

    運行模式
        static      靜態模式,啓動時分配固定的worker進程。
        ondemand    按需分配,當收到用戶請求時fork worker進程。
        dynamic     動態模式,啓動時分配固定的進程。伴隨着請求數增長,在設定的浮動範圍調整worker進程。

    進程池參數
        pm.max_children:限定php-fpm的最大進程數,靜態模式默認分配work數。
        pm.start_servers:動態方式下的起始php-fpm進程數量。
        pm.min_spare_servers:動態方式空閒狀態下的最小php-fpm進程數量。
        pm.max_spare_servers:動態方式空閒狀態下的最大php-fpm進程數量。


    運行原理
        master進程負責CGI、PHP公共環境的初始化及事件監聽操做。
        worker進程負責請求的處理功能。在worker進程處理請求時,無需再次初始化PHP運行環境,這也是php-fpm性能優異的緣由之一。

        master:
            1. cgi初始化階段:
                分別調用fcgi_init()和 sapi_startup()函數,註冊進程信號以及初始化sapi_globals全局變量。

            2. php環境初始化階段:
                由cgi_sapi_module.startup 觸發。
                實際調用php_cgi_startup函數,而php_cgi_startup內部又調用php_module_startup執行。
                php_module_startup主要功能:
                    a).加載和解析php配置;
                    b).加載php模塊並記入函數符號表(function_table);
                    c).加載zend擴展 ;
                    d).設置禁用函數和類庫配置;
                    e).註冊回收內存方法;

            3. php-fpm初始化階段:
                執行fpm_init()函數。
                負責解析php-fpm.conf文件配置,獲取進程相關參數(容許進程打開的最大文件數等),初始化進程池及事件模型等操做。

            4. php-fpm運行階段:
                執行fpm_run() 函數,運行後主進程發生阻塞。
                該階段分爲兩部分:fork子進程 和 循環事件。fork子進程部分交由fpm_children_create_initial函數處理。
                循環事件部分經過fpm_event_loop函數處理,其內部是一個死循環,負責事件的收集工做。

        worker:
            1. 接收客戶端請求:
                執行fcgi_accept_request函數,其內部經過調用accept 函數獲取客戶端請求。

            2. 處理請求階段:
                首先,分別調用fpm_request_info、php_request_startup獲取請求內容及註冊全局變量($_GET、$_POST、$_SERVER、$_ENV、$_FILES);
                而後根據請求信息調用php_fopen_primary_script訪問腳本文件;
                最後交給php_execute_script執行。php_execute_script內部調用zend_execute_scripts方法將腳本交給zend引擎處理。

            3. 請求結束階段:
                執行php_request_shutdown函數。
                此時 回調register_shutdown_function註冊的函數及__destruct()方法,發送響應內容、釋放內存等操做。

3、PHP新特性

PHP5的zvalue面臨的問題:
        1. 結構體的大小爲24個字節
        2. 沒有預留任何的自定義字段
        3. PHP的zval大部分都是按值傳遞, 寫時拷貝的值, 但對象和資源, 他們永遠都是按引用傳遞,因此它有倆套引用計數, 一個是zval中的, 另一個是obj自身的計數,結構變得複雜, 維護性下降
        4. PHP應用的寫時分離是的複製性能問題
        5. 許多局部變量使用堆內存分配
    
        <?php
            $array = range(1, 100000);
            function dummy($array) {}
    
            $i = 0;
            $start = microtime(true);
            while($i++ < 100) {
                dummy($array);
            }
            printf("Used %sS\n", microtime(true) - $start);
    
            $i = 0;
            $b = &$array; //注意這裏, 假設我不當心把這個Array引用給了一個變量
            $start = microtime(true);
            while($i++ < 100) {
                dummy($array);
            }
            printf("Used %sS\n", microtime(true) - $start);
        ?>
    
Zval容器變化
    ### version < 7
    zval變量容器 {
        value,      -- 變量值(16字節)
        type,       -- 變量類型(2字節)
        is_ref__gc  -- 是不是屬於引用集合(2字節)
        refcount__gc -- 引用次數(4字節)
    }
    
    ### ### version >= 7
    zval變量容器 {
        value,          -- 變量值(16字節)
        u1聯合體 {
            type_info   -- 類型信息
            ZEND_ENDIAN_LOHI_4  -- 簡化賦值, 四個字符變量的結構體
        }
        u2聯合體 {
            var_flags
            next        --hash碰撞鏈
            cache_slot
            lineno      --行號(AST,對象生成樹槽點)
            num_args
            fe_pos      --foreach位置
            fe_iter_idx --foreach迭代器索引
        }
    }
    
    具體:
        對於在zval的value字段中能保存下的值, 就再也不對他們進行引用計數了, 而是在拷貝的時候直接賦值, 這樣就省掉了大量的引用計數相關的操做
        ZEND_ENDIAN_LOHI_4做用是簡化賦值,保證在大端或者小端的機器上,定義的字段都按照同樣順序排列存儲, 從而咱們在賦值的時候, 不須要對它的字段分別賦值, 而是能夠統一賦值

4、 PHP安全機制

攻擊手段: SQL注入、XSS、CSRF、DDOS、Session固定攻擊、 Session劫持攻擊、文件上傳漏洞

PHP漏洞:
    1. 精度繞過缺陷
        floor((0.1+0.7)*10)  // = 7
    2. 類型轉換的缺陷
        var_dump('66hh' == 66); // true
    3. 鬆散比較符的缺陷
        var_dump(0=="gg");  //true
        var_dump(0==="gg"); //false
        var_dump(1=="gg");  //false
    4. md5繞過(Hash比較缺陷)
        var_dump(md5('QNKCDZO') == md5(240610708));
        字符串       md5
        QNKCDZO     0e830400451993494058024219903391
        240610708   0e462097431906509019562988736854
        aabg7XSs    0e087386482136013740957780965295
        aabC9RqS    0e041022518165728065344349536299
        s878926199a 0e545993274517709034328855841020
    6. sha1()與md5()加密函數漏洞缺陷
        var_dump(sha1($_GET['name']) === sha1($_GET['password']))   //請求/?name[]=a&password[]=b
    7. 字符串處理函數漏洞缺陷
        函數接受到了不符合的類型,例如數組類型,函數將發生錯誤。
        在5.3以前, 顯示了報錯的警告信息後,將return 0, 即判斷其爲正確。
    8. parse_str函數變量覆蓋缺陷
        parse_str函數的做用就是解析字符串並註冊成變量,在註冊變量以前不會驗證當前變量是否存在,因此直接覆蓋掉已有變量。

參考:
    http://www.freebuf.com/articles/rookie/161474.html
    
提示站點安全係數:
    register_globals = Off   -- 關閉全局註冊變量功能
    error_reporting = E_ALL|E_STRICT   -- 配置預警模式,若是有未初始化的,就會預警
    display_errors = On      -- 不顯示頁面錯誤信息
    log_errors = On          -- 保存錯誤信息到本地
    allow_url_include = Off  -- 不容許加載遠程php文件
    allow_url_fopen   = Off  -- 不容許打開遠程文件(影響fopen,file_put_contents)
    magic_quotes_gpc  = On   -- get,post,cookie變量的過濾,過濾有單引號,雙引號,反斜槓,空字符,都用反斜槓轉義($_SERVER變量不會過濾)
    magic_quotes_runtime= On -- 對文件或者數據庫中取出的數據過濾
    safe_mode = On           -- 限制函數使用權限和操做目錄文件權限等功能。檢驗用戶是否有操做文件權限。
    disable_functions        -- 禁用的函數
    expose_php  = Off        -- 隱藏php版本信息
    display_startup_errors = Off -- 不在頁面顯示php程序啓動時產生的錯誤

站點攻擊:
    1.跨網站腳本攻擊(Cross Site Scripting, XSS)
        描述:
            攻擊者將惡意代碼注入到網頁上,其餘用戶在加載網頁時就會執行代碼,
            攻擊者可能獲得包括但不限於更高的權限(如執行一些操做)、私密網頁內容、會話和cookie等各類內容。
        例如:
            <?php  echo "歡迎您,".$_GET['name'];
            彈出一個對話框:http://localhost/test.php?name=<script>alert(123456)</script>
        防範方法:
            使用htmlspecialchars函數將特殊字符轉換成HTML編碼,過濾輸出的變量

    2.跨網站請求僞造攻擊(Cross Site Request Forgeries, CSRF)
        描述:
            攻擊者僞造目標用戶的HTTP請求,而後此請求發送到有CSRF漏洞的網站,網站執行此請求後,引起跨站請求僞造攻擊。
            攻擊者利用隱蔽的HTTP鏈接,讓目標用戶在不注意的狀況下單擊這個連接,
            因爲是用戶本身點擊的,而他又是合法用戶擁有合法權限,因此目標用戶可以在網站內執行特定的HTTP連接,從而達到攻擊者的目的。
        例如:
            某個購物網站購買商品時,採用http://www.shop.com/buy.php?item=watch&num=100
            item參數肯定要購買什麼物品,num參數肯定要購買數量,若是攻擊者以隱藏的方式發送給目標用戶連接
            ,那麼若是目標用戶不當心訪問之後,購買的數量就成了100個。
        防範方法:
            一、檢查網頁的來源
            二、檢查內置的隱藏變量
            三、使用POST,不要使用GET,處理變量也不要直接使用$_REQUEST

    3. Session固定攻擊(Session Fixation)
        描述:
            攻擊者預先設定session id,讓合法用戶使用這個session id來訪問被攻擊的應用程序,一旦用戶的會話ID被成功固定,攻擊者就能夠經過此session id來冒充用戶訪問應用程序。
        例如:
            1.攻擊者訪問網站http:///www.bank.com,獲取他本身的session id,如:SID=123;
            2.攻擊者給目標用戶發送連接,並帶上本身的session id,如:http:///www.bank.com/?SID=123;
            3.目標用戶點擊了http:///www.bank.com/?SID=123,像往常同樣,輸入本身的用戶名、密碼登陸到網站;
            4.因爲服務器的session id不改變,如今攻擊者點擊http:///www.bank.com/?SID=123,他就擁有了目標用戶的身份,能夠隨心所欲了。
        防範方法:
            1.按期更改session id
            2.更改session的名稱, session的默認名稱是PHPSESSID
            3.關閉透明化session id , int_set("session.use_trans_sid", 0);
            4.只從cookie檢查session id
                int_set("session.use_cookies", 1);//表示使用cookies存放
                session id int_set("session.use_only_cookies", 1);//表示只使用cookies存放session id
            5.使用URL傳遞隱藏參數
                $sid = md5(uniqid(rand()), TRUE));
                $_SESSION["sid"] = $sid;

    4. Session劫持攻擊(Session Hijacking)
        描述:
            攻擊者利用各類手段來獲取目標用戶的session id。
            一旦獲取到session id,那麼攻擊者能夠利用目標用戶的身份來登陸網站,獲取目標用戶的操做權限。
            攻擊者獲取目標用戶session id的方法:
                a.暴力破解:嘗試各類session id,直到破解爲止;
                b.計算:若是session id使用非隨機的方式產生,那麼就有可能計算出來;
                c.竊取:使用網絡截獲,xss攻擊等方法得到
        防範方法:
            1.按期更改session id
            2.更改session的名稱
            3.關閉透明化session id
            4.設置HttpOnly。經過設置Cookie的HttpOnly爲true,能夠防止客戶端腳本訪問這個Cookie,從而有效的防止XSS攻擊。

參考:
    PHP安全之Web攻擊: http://www.cnblogs.com/luyucheng/p/6234524.html
    PHP代碼安全雜談: http://www.freebuf.com/articles/rookie/161474.html
    
    接口安全:
        Token機制, 分配appkey, appSecret
        數據校驗,  sign+timestamp+token
        過載保護
        異常封裝

5、棧內存和堆內存的區別:

程序的內存分配
        棧(stack):有編譯器自動分配和釋放,存放函數的參數、局部變量、臨時變量、函數返回地址等;
        堆(heap):通常有程序員分配和釋放,若是沒有手動釋放,在程序結束時可能由操做系統自動釋放, 稍有不慎會引發內存泄漏。

    申請後系統的響應
        棧:只要棧的剩餘空間大於所申請的空間,系統將爲程序提供內存,不然將報異常提示棧溢出。
        堆:在記錄空閒內存地址的鏈表中尋找一個空間大於所申請空間的堆結點,而後將該結點從空閒結點鏈表中刪除,並將該結點的空間分配給程序。

    申請大小限制
        棧:在Windows下,棧是向低地址擴展的數據結構,是一塊連續的內存的區域。
            若是申請的空間超過棧的剩餘空間時,將提示overflow。所以,能從棧得到的空間較小。
        堆:堆是向高地址擴展的數據結構,是不連續的內存區域。堆的大小受限於計算機系統中有效的虛擬內存。
            因而可知,堆得到的空間比較靈活,也比較大。

    分配效率
        棧:由系統自動分配,速度較快。但程序員是沒法控制的。
        堆:由new分配的內存,通常速度比較慢,並且容易產生內存碎片,不過用起來最方便。

    存儲內容
        棧:在棧中,第一個進棧的是主函數下一條指令的地址,而後是函數的各個參數,在大多數編譯器中,參數是由右往左入棧,而後是函數中的局部變量。注意,靜態變量不入棧。出棧則恰好順序相反。
        堆:通常在堆的頭部用一個字節存放堆的大小,具體內容由程序員安排。

6、性能分析

XDebug
    在php.ini內以下設置
        zend_extension = "D:\xampp\php\ext\php_xdebug.dll"
        xdebug.collect_includes = 1
        xdebug.profiler_enable = 0
        xdebug.profiler_enable_trigger = 1
        xdebug.profiler_output_dir = "D:\xampp\tmp"
        xdebug.profiler_output_name = "cachegrind.out.%u.log"
    配置完畢後重啓Nginx,在zf2項目URL中加入XDEBUG_PROFILE便可開啓Xdebug Log輸出
    參考:https://avnpc.com/pages/how-to-debug-under-zf2

xhprof
    安裝xhprof, 修改php.ini,  echo "extension=xhprof.so" > /etc/php5/fpm/conf.d/xhprof.ini
    UI裏列出了:
        funciton name : 函數名
        calls: 調用次數
        Incl. Wall Time (microsec): 函數運行時間(包括子函數)
        IWall%:函數運行時間(包括子函數)佔比
        Excl. Wall Time(microsec):函數運行時間(不包括子函數)
        EWall%:函數運行時間(不包括子函數)
    注入方式
        1. 直接注入
            //開啓xhprof
            xhprof_enable(XHPROF_FLAGS_MEMORY | XHPROF_FLAGS_CPU);
            //在程序結束後收集數據
            register_shutdown_function(function() {
                $xhprof_data = xhprof_disable();

                //讓數據收集程序在後臺運行
                if (function_exists('fastcgi_finish_request')) {
                    fastcgi_finish_request();
                }

                //保存xhprof數據
                ...
            });

        2.  fpm配置注入
            vi /usr/local/php7/etc/php-fpm.ini
            修改配置:auto_prepend_file = /opt/htdocs/xhgui/external/header.php

        3. Nginx注入
            fastcgi_param PHP_VALUE "auto_prepend_file=/opt/htdocs/xhgui/external/header.php";
相關文章
相關標籤/搜索