目錄php
PHP發展這麼多年,技術、架構都已經革新,瞭解現代PHP很重要,最近在看Model PHP這本書,系統的瞭解下PHP相關的概念。html
是類的部分實現(即常量、屬性和方法),能夠混入一個或多個現有的php類中。
性狀有兩個做用:代表類能夠作什麼(接口);提供模塊化實現(像是類)。git
好比說兩個無關的類須要擁有一個共同的方法,繼承、接口都不太合理(一是屬性不一樣;二是代碼重複),使用性狀能夠共同使用某個方法。api
舉例 汽車和快遞員均可能都須要查詢地理位置數組
trait Geocodable{ protected $address; protected $geocoder //獲取經緯度 public function getLatitude(){ } }
使用性狀:緩存
<?php Class Car{ use Geocodable; //類的實現 ... }
生成器提供了一種更容易的方法來實現簡單的對象迭代,相比較定義類實現 Iterator 接口(正常迭代)的方式,性能開銷和複雜性大大下降。服務器
生成器容許你在 foreach 代碼塊中寫代碼來迭代一組數據而不須要在內存中建立一個數組, 那會使你的內存達到上限,或者會佔據可觀的處理時間。相反,你能夠寫一個生成器函數,就像一個普通的自定義函數同樣, 和普通函數只返回一次不一樣的是, 生成器能夠根據須要 yield 屢次,以便生成須要迭代的值。閉包
生成器根據需求計算出要迭代的值;及時計算併產出後續值,不佔用寶貴的內存資源。架構
一個簡單的例子就是使用生成器來從新實現 range() 函數。 標準的 range() 函數須要在內存中生成一個數組包含每個在它範圍內的值,而後返回該數組, 結果就是會產生多個很大的數組。 好比,調用 range(0, 1000000) 將致使內存佔用超過 100 MB。ide
作爲一種替代方法, 咱們能夠實現一個 xrange() 生成器, 只須要足夠的內存來建立 Iterator 對象並在內部跟蹤生成器的當前狀態,這樣只須要不到1K字節的內存。
Example #1 將 range() 實現爲生成器
<?php function xrange($start, $limit, $step = 1) { if ($start < $limit) { if ($step <= 0) { throw new LogicException('Step must be +ve'); } for ($i = $start; $i <= $limit; $i += $step) { yield $i; } } else { if ($step >= 0) { throw new LogicException('Step must be -ve'); } for ($i = $start; $i >= $limit; $i += $step) { yield $i; } } } /* * 注意下面range()和xrange()輸出的結果是同樣的。 */ echo 'Single digit odd numbers from range(): '; foreach (range(1, 9, 2) as $number) { echo "$number "; } echo "\n"; echo 'Single digit odd numbers from xrange(): '; foreach (xrange(1, 9, 2) as $number) { echo "$number "; } ?>
以上例程會輸出:
Single digit odd numbers from range(): 1 3 5 7 9 Single digit odd numbers from xrange(): 1 3 5 7 9
想象下處理斐波那契數列或者迭代流資源,假設處理一個4GB的csv文件,而虛擬服務器只容許使用1GB內存,若是整個加載到內存中,服務器就崩了,而用生成器一次只會爲csv一行分配內存。
<?php function getRows( $file ){ $handle = fopen($file,'rb'); if( $handle === false ){ throw new Exception(); } while(feof($handle) === false){ yield fgetcsv($handle); } fclose($handle); } foreach($getRows('data.csv') as $row){ print_r($row); }
生成器是功能多樣性和簡潔性之間的這種方案。生成器是隻能前進的迭代器,沒法執行快進,後退,查找操做。
參考鳥哥的文章:http://www.laruence.com/2015/05/28/3038.html
是指在建立時封裝周圍狀態的函數。
匿名函數其實就是沒有名稱的函數,特別適合做爲函數或方法的調用。
建立簡單的閉包
$closure = function($name){ return sprintf ('hello %s',$name); } echo $closure("Josh"); //輸出 --> hello Josh
做爲回調
//匿名回調 $numbersPlusOne = array_map(function( $number ){ return $number+1; },[1,2,3]); print_r($numbersPlusOne); //輸出 --> [2,3,4]
//具名回調 function incrementNumber($number){ return $number+1; } $numbersPlusone = array_map('incrementNumber',[1,2,3]); print_r($numbersPlusOne); //輸出 --> [2,3,4]
PHP閉包附加並封裝狀態,手動調用閉包對象的bindTo()方法或者使用use關鍵字,把狀態附加到PHP閉包上。
實例:
<?php function enclosePersion( $name ){ return function($doCommand use $name){ return sprintf('%s,%s',$name,$doCommand); } } //將字符串「sun」封裝到閉包中 $sun = enclosePersion( 'sun' ); //傳入參數,調用閉包 echo $sun('get me sweet tea!'); //輸出 --> "sun,get me sweet tea!"
PHP閉包是對象,與任何其餘PHP對象相似,每一個閉包實例均可以使用$this關鍵字獲取閉包的內部狀態。閉包有__invoke()、bindTo()方法;
<?php class A { function __construct ( $val ) { $this -> val = $val ; } function getClosure () { //returns closure bound to this object and scope return function() { return $this -> val ; }; } } $ob1 = new A ( 1 ); $ob2 = new A ( 2 ); $cl = $ob1 -> getClosure (); echo $cl (), "\n" ; $cl = $cl -> bindTo ( $ob2 ); echo $cl (), "\n" ; ?> 以上例程的輸出相似於: 1 2
從php 5.5.0開始,內置了字節碼緩存功能。
PHP執行過程:
graph LR 解析腳本代碼-->編譯成一系列Zend操做碼 編譯成一系列Zend操做碼-->執行字節碼
字節碼緩存 存儲好預先編譯好的PHP字節碼,PHP解釋器跳過讀取、解析、編譯PHP代碼,直接從內存中讀取預先編譯好的字節碼,而後執行。優勢節省了時間,極大地提高了應用的性能。
腳本執行圖解:
編譯PHP時,明確指定啓用Zend OPcache。
執行./configure 命令時必須包含如下選項:
--enable-opcache
編譯成功會顯示Zend OPcache擴展的文件路徑。也可經過下述命令查找擴展的安裝路徑
php-config --extension-dir
php.ini文件中指定Zend OPcache擴展路徑,如:
zend_extension=/path/to/opcache.so
更新php.ini文件,重啓php進程。
<?php phpinfo()
查看Zend OPcache擴展開啓狀況
[opcache] zend_extension=/usr/local/php5/lib/php/extensions/no-debug-non-zts-20131226/opcache.so ; Zend Optimizer + 的開關, 關閉時代碼再也不優化. opcache.enable=1 ; Determines if Zend OPCache is enabled for the CLI version of PHP opcache.enable_cli=1 ; Zend Optimizer + 共享內存的大小, 總共可以存儲多少預編譯的 PHP 代碼(單位:MB) ;根據內存來定 opcache.memory_consumption=256 ; Zend Optimizer + 暫存池中字符串的佔內存總量.(單位:MB) ; 推薦 8 opcache.interned_strings_buffer=4 ; 最大緩存的文件數目 200 到 100000 之間 ; 推薦 4000~8000 opcache.max_accelerated_files=8000 ; 內存「浪費」達到此值對應的百分比,就會發起一個重啓調度. opcache.max_wasted_percentage=5 ; 開啓這條指令, Zend Optimizer + 會自動將當前工做目錄的名字追加到腳本鍵上, ; 以此消除同名文件間的鍵值命名衝突.關閉這條指令會提高性能, ; 可是會對已存在的應用形成破壞. opcache.use_cwd=0 ; 開啓文件時間戳驗證 opcache.validate_timestamps=1 ; 2s檢查一次文件更新 注意:0是一直檢查不是關閉 ; 推薦 60 opcache.revalidate_freq=0 ; 容許或禁止在 include_path 中進行文件搜索的優化 ;opcache.revalidate_path=0 ; 是否保存文件/函數的註釋 若是apigen、Doctrine、 ZF二、 PHPUnit須要文件註釋 ; 推薦 0 opcache.save_comments=1 ; 是否加載文件/函數的註釋 ;opcache.load_comments=1 ; 打開快速關閉, 打開這個在PHP Request Shutdown的時候會收內存的速度會提升 ; 推薦 1 opcache.fast_shutdown=1 ;容許覆蓋文件存在(file_exists等)的優化特性。 ;opcache.enable_file_override=0 ; 定義啓動多少個優化過程 ;opcache.optimization_level=0xffffffff ; 啓用此Hack能夠暫時性的解決」can’t redeclare class」錯誤. ;opcache.inherited_hack=1 ; 啓用此Hack能夠暫時性的解決」can’t redeclare class」錯誤. ;opcache.dups_fix=0 ; 設置不緩存的黑名單 ; 不緩存指定目錄下cache_開頭的PHP文件. /png/www/example.com/public_html/cache/cache_ ;opcache.blacklist_filename= ; 經過文件大小屏除大文件的緩存.默認狀況下全部的文件都會被緩存. ;opcache.max_file_size=0 ; 每 N 次請求檢查一次緩存校驗.默認值0表示檢查被禁用了. ; 因爲計算校驗值有損性能,這個指令應當牢牢在開發調試的時候開啓. ;opcache.consistency_checks=0 ; 從緩存不被訪問後,等待多久後(單位爲秒)調度重啓 ;opcache.force_restart_timeout=180 ; 錯誤日誌文件名.留空表示使用標準錯誤輸出(stderr). ;opcache.error_log=/tmp/ckl.log ; 將錯誤信息寫入到服務器(Apache等)日誌 ;opcache.log_verbosity_level=1 ; 內存共享的首選後臺.留空則是讓系統選擇. ;opcache.preferred_memory_model= ; 防止共享內存在腳本執行期間被意外寫入, 僅用於內部調試. ;opcache.protect_memory=0
參考下大神的配置
opcache.enable=1 opcache.memory_consumption=256 opcache.interned_strings_buffer=4 opcache.max_accelerated_files=8000 opcache.max_wasted_percentage=5 opcache.use_cwd=1 opcache.validate_timestamps=1 opcache.revalidate_freq=0 opcache.revalidate_path=0 opcache.save_comments=0 opcache.load_comments=0 opcache.force_restart_timeout=3600