\<Vendor Name>\(<Namespace>\)*<Class Name>
\Doctrine\Common\IsolatedClassLoader => /path/to/project/lib/vendor/Doctrine/Common/IsolatedClassLoader.php \Symfony\Core\Request => /path/to/project/lib/vendor/Symfony/Core/Request.php \Zend\Acl => /path/to/project/lib/vendor/Zend/Acl.php \Zend\Mail\Message => /path/to/project/lib/vendor/Zend/Mail/Message.php
源文件必須只使用php
源文件中php代碼的編碼格式必須只使用不帶字節順序標記(BOM)的UTF-8。html
一個源文件建議只用來作聲明(類(class),函數(function),常量(constant)等)或者只用來作一些引發反作用的操做(例如:輸出信息,修改.ini配置等),但不建議同時作這兩件事。git
命名空間(namespace)和類(class) 必須遵照PSR-0標準。github
類名(class name) 必須使用駱駝式(StudlyCaps)寫法 (譯者注:駝峯式(cameCase)的一種變,後文將直接用StudlyCaps表示)。web
類(class)中的常量必須只由大寫字母和下劃線(_)組成。數組
方法名(method name) 必須使用駝峯式(cameCase)寫法(譯者注:後文將直接用camelCase表示)。markdown
PHP代碼必須只使用長標籤()或者短輸出式標籤();而不可以使用其餘標籤。閉包
PHP代碼的編碼格式必須只使用不帶字節順序標記(BOM)的UTF-8。框架
一個源文件建議只用來作聲明(類(class),函數(function),常量(constant)等)或者只用來作一些引發反作用的操做(例如:輸出信息,修改.ini配置等),但不建議同時作這兩件事。ide
短語反作用(side effects)的意思是 在包含文件時 所執行的邏輯與所聲明的類(class),函數(function),常量(constant)等沒有直接的關係。
反作用(side effects)包含但不侷限於:產生輸出,顯式地使用require或include,鏈接外部服務,修改ini配置,觸發錯誤或異常,修改全局或者靜態變量,讀取或修改文件等等
下面是一個既包含聲明又有反作用的示例文件;即應避免的例子:
<?php // 反作用:修改了ini配置 ini_set('error_reporting', E_ALL); // 反作用:載入了文件 include "file.php"; // 反作用:產生了輸出 echo "<html>\n"; // 聲明 function foo() { // 函數體 }
下面是一個僅包含聲明的示例文件;即應提倡的例子:
<?php // 聲明 function foo() { // 函數體 } // 條件式聲明不算作是反作用 if (! function_exists('bar')) { function bar() { // 函數體 } }
命名空間(namespace)和類(class)必須遵照 PSR-0.
這意味着一個源文件中只能有一個類(class),而且每一個類(class)至少要有一級空間名(namespace):即一個頂級的組織名(vendor name)。
類名(class name) 必須使用StudlyCaps寫法。
PHP5.3以後的代碼必須使用正式的命名空間(namespace) 例子:
<?php // PHP 5.3 及以後: namespace Vendor\Model; class Foo { }
術語類(class)指全部的類(class),接口(interface)和特性(trait)
類常量必須只由大寫字母和下劃線(_)組成。 例子:
<?php namespace Vendor\Model; class Foo { const VERSION = '1.0'; const DATE_APPROVED = '2012-06-01'; }
本指南中故意不對$StulyCaps,$camelCase或者$unser_score中的某一種風格做特別推薦,徹底由讀者依據我的喜愛決定屬性名的命名風格。
可是無論你如何定義屬性名,建議在一個合理的範圍內保持一致。這個範圍多是組織(vendor)級別的,包(package)級別的,類(class)級別的,或者方法(method)級別的。
方法名則必須使用camelCase()風格來聲明。
代碼必須遵照 PSR-1。
代碼必須使用4個空格來進行縮進,而不是用製表符。
一行代碼的長度不建議有硬限制;軟限制必須爲120個字符,建議每行代碼80個字符或者更少。
在命名空間(namespace)的聲明下面必須有一行空行,而且在導入(use)的聲明下面也必須有一行空行。
類(class)的左花括號必須放到其聲明下面自成一行,右花括號則必須放到類主體下面自成一行。
方法(method)的左花括號必須放到其聲明下面自成一行,右花括號則必須放到方法主體的下一行。
全部的屬性(property)和方法(method) 必須有可見性聲明;抽象(abstract)和終結(final)聲明必須在可見性聲明以前;而靜態(static)聲明必須在可見性聲明以後。
在控制結構關鍵字的後面必須有一個空格;而方法(method)和函數(function)的關鍵字的後面不可有空格。
控制結構的左花括號必須跟其放在同一行,右花括號必須放在該控制結構代碼主體的下一行。
控制結構的左括號以後不可有空格,右括號以前也不可有空格。
<?php namespace Vendor\Package; use FooInterface; use BarClass as Bar; use OtherVendor\OtherPackage\BazClass; class Foo extends Bar implements FooInterface { public function sampleFunction($a, $b = null) { if ($a === $b) { bar(); } elseif ($a > $b) { $foo->bar($arg1); } else { BazClass::bar($arg2, $arg3); } } final public static function bar() { // 方法主體 } }
代碼必須遵照 PSR-1 中的全部規則。
全部的PHP源文件必須使用Unix LF(換行)做爲行結束符。
全部PHP源文件必須以一個空行結束。
純PHP代碼源文件的關閉標籤?> 必須省略。
行長度不可有硬限制。
行長度的軟限制必須是120個字符;對於軟限制,代碼風格檢查器必須警告但不可報錯。
一行代碼的長度不建議超過80個字符;較長的行建議拆分紅多個不超過80個字符的子行。
在非空行後面不可有空格。
空行能夠用來加強可讀性和區分相關代碼塊。
一行不可多於一個語句。
代碼必須使用4個空格,且不可以使用製表符來做爲縮進。
PHP關鍵字(keywords)必須使用小寫字母。
PHP常量true, false和null 必須使用小寫字母。
命名空間(namespace)的聲明後面必須有一行空行。
全部的導入(use)聲明必須放在命名空間(namespace)聲明的下面。
一句聲明中,必須只有一個導入(use)關鍵字。
在導入(use)聲明代碼塊後面必須有一行空行。
示例:
<?php namespace Vendor\Package; use FooClass; use BarClass as Bar; use OtherVendor\OtherPackage\BazClass; // ... 其它PHP代碼 ...
術語「類」指全部的類(class),接口(interface)和特性(trait)。
一個類的擴展(extend)和實現(implement)關鍵詞必須和類名(class name)在同一行。
類(class)的左花括號必須放在下面自成一行;右花括號必須放在類(class)主體的後面自成一行。
<?php namespace Vendor\Package; use FooClass; use BarClass as Bar; use OtherVendor\OtherPackage\BazClass; class ClassName extends ParentClass implements \ArrayAccess, \Countable { // 常量、屬性、方法 }
實現(implement)列表能夠被拆分爲多個縮進了一次的子行。若是要拆成多個子行,列表的第一項必需要放在下一行,而且每行必須只有一個接口(interface)。
<?php namespace Vendor\Package; use FooClass; use BarClass as Bar; use OtherVendor\OtherPackage\BazClass; class ClassName extends ParentClass implements \ArrayAccess, \Countable, \Serializable { // 常量、屬性、方法 }
全部的屬性(property)都必須聲明其可見性。
變量(var)關鍵字不可用來聲明一個屬性(property)。
一條語句不可聲明多個屬性(property)。
屬性名(property name) 不推薦用單個下劃線做爲前綴來代表其保護(protected)或私有(private)的可見性。
一個屬性(property)聲明看起來應該像下面這樣。
<?php namespace Vendor\Package; class ClassName { public $foo = null; }
全部的方法(method)都必須聲明其可見性。
方法名(method name) 不推薦用單個下劃線做爲前綴來代表其保護(protected)或私有(private)的可見性。
方法名(method name)在其聲明後面不可有空格跟隨。其左花括號必須放在下面自成一行,且右花括號必須放在方法主體的下面自成一行。左括號後面不可有空格,且右括號前面也不可有空格。
一個方法(method)聲明看來應該像下面這樣。 注意括號,逗號,空格和花括號的位置:
<?php namespace Vendor\Package; class ClassName { public function fooBarBaz($arg1, &$arg2, $arg3 = []) { // 方法主體部分 } }
在參數列表中,逗號以前不可有空格,而逗號以後則必需要有一個空格。
方法(method)中有默認值的參數必須放在參數列表的最後面。
<?php namespace Vendor\Package; class ClassName { public function foo($arg1, &$arg2, $arg3 = []) { // 方法主體部分 } }
參數列表能夠被拆分爲多個縮進了一次的子行。若是要拆分紅多個子行,參數列表的第一項必須放在下一行,而且每行必須只有一個參數。
當參數列表被拆分紅多個子行,右括號和左花括號之間必須又一個空格而且自成一行。
<?php namespace Vendor\Package; class ClassName { public function aVeryLongMethodName( ClassTypeHint $arg1, &$arg2, array $arg3 = [] ) { // 方法主體部分 } }
當用到�抽象(abstract)和終結(final)來作類聲明時,它們必須放在可見性聲明的前面。
而當用到靜態(static)來作類聲明時,則必須放在可見性聲明的後面。
<?php namespace Vendor\Package; abstract class ClassName { protected static $foo; abstract protected function zim(); final public static function bar() { // 方法主體部分 } }
調用一個方法或函數時,在方法名或者函數名和左括號之間不可有空格,左括號以後不可有空格,右括號以前也不可有空格。參數列表中,逗號以前不可有空格,逗號以後則必須有一個空格。
<?php bar(); $foo->bar($arg1); Foo::bar($arg2, $arg3);
參數列表能夠被拆分紅多個縮進了一次的子行。若是拆分紅子行,列表中的第一項必須放在下一行,而且每一行必須只能有一個參數。
<?php $foo->bar( $longArgument, $longerArgument, $muchLongerArgument );
下面是對於控制結構代碼風格的歸納:
每一個控制結構的代碼主體必須被括在花括號裏。這樣但是使代碼看上去更加標準化,而且加入新代碼的時候還能夠所以而減小引入錯誤的可能性。
下面是一個if條件控制結構的示例,注意其中括號,空格和花括號的位置。同時注意else和elseif要和前一個條件控制結構的右花括號在同一行。
<?php if ($expr1) { // if body } elseif ($expr2) { // elseif body } else { // else body; }
推薦用elseif來替代else if,以保持全部的條件控制關鍵字看起來像是一個單詞。
下面是一個switch條件控制結構的示例,注意其中括號,空格和花括號的位置。case語句必需要縮進一級,而break關鍵字(或其餘停止關鍵字)必須和case結構的代碼主體在同一個縮進層級。若是一個有主體代碼的case結構故意的繼續向下執行則必需要有一個相似於// no break的註釋。
<?php switch ($expr) { case 0: echo 'First case, with a break'; break; case 1: echo 'Second case, which falls through'; // no break case 2: case 3: case 4: echo 'Third case, return instead of break'; return; default: echo 'Default case'; break; }
下面是一個while循環控制結構的示例,注意其中括號,空格和花括號的位置。
<?php while ($expr) { // structure body }
下面是一個do while循環控制結構的示例,注意其中括號,空格和花括號的位置。
<?php do { // structure body; } while ($expr);
下面是一個for循環控制結構的示例,注意其中括號,空格和花括號的位置。
<?php for ($i = 0; $i < 10; $i++) { // for body }
下面是一個foreach循環控制結構的示例,注意其中括號,空格和花括號的位置。
<?php foreach ($iterable as $key => $value) { // foreach body }
下面是一個try catch異常處理控制結構的示例,注意其中括號,空格和花括號的位置。
<?php try { // try body } catch (FirstExceptionType $e) { // catch body } catch (OtherExceptionType $e) { // catch body }
聲明閉包時所用的function關鍵字以後必需要有一個空格,而use關鍵字的先後都要有一個空格。
閉包的左花括號必須跟其在同一行,而右花括號必須在閉包主體的下一行。
閉包的參數列表和變量列表的左括號後面不可有空格,右括號的前面也不可有空格。
閉包的參數列表和變量列表中逗號前面不可有空格,而逗號後面則必須有空格。
閉包的參數列表中帶默認值的參數必須放在參數列表的結尾部分。
下面是一個閉包的示例。注意括號,空格和花括號的位置。
<?php $closureWithArgs = function ($arg1, $arg2) { // body }; $closureWithArgsAndVars = function ($arg1, $arg2) use ($var1, $var2) { // body };
參數列表和變量列表能夠被拆分紅多個縮進了一級的子行。若是要拆分紅多個子行,列表中的第一項必須放在下一行,而且每一行必須只放一個參數或變量。
當列表(不論是參數仍是變量)最終被拆分紅多個子行,右括號和左花括號之間必需要有一個空格而且自成一行。
下面是一個參數列表和變量列表被拆分紅多個子行的示例。
<?php $longArgs_noVars = function ( $longArgument, $longerArgument, $muchLongerArgument ) { // body }; $noArgs_longVars = function () use ( $longVar1, $longerVar2, $muchLongerVar3 ) { // body }; $longArgs_longVars = function ( $longArgument, $longerArgument, $muchLongerArgument ) use ( $longVar1, $longerVar2, $muchLongerVar3 ) { // body }; $longArgs_shortVars = function ( $longArgument, $longerArgument, $muchLongerArgument ) use ($var1) { // body }; $shortArgs_longVars = function ($arg) use ( $longVar1, $longerVar2, $muchLongerVar3 ) { // body };
把閉包做爲一個參數在函數或者方法中調用時,依然要遵照上述規則。
<?php $foo->bar( $arg1, function ($arg2) use ($var1) { // body }, $arg3 );
本文檔描述了日誌類庫的通用接口。
主要目標是讓類庫得到一個Psr\Log\LoggerInterface對象並能經過簡單通用的方式來寫日誌。有自定義需求的框架和CMS能夠根據狀況擴展這個接口,但推薦保持和該文檔的兼容性,以確保應用中使用到的第三方庫能將日誌集中寫到應用日誌裏。
RFC 2119中的必須(MUST),不可(MUST NOT),建議(SHOULD),不建議(SHOULD NOT),能夠/可能(MAY)等關鍵詞將在本節用來作一些解釋性的描述。
關鍵詞實現者在這個文檔被解釋爲:在日誌相關的庫或框架實現LoggerInterface接口的開發人員。用這些實現者開發出來的類庫的人都被稱做用戶。
LoggerInterface暴露八個接口用來記錄八個等級(debug, info, notice, warning, error, critical, alert, emergency)的日誌。
第九個方法是log,接受日誌等級做爲第一個參數。用一個日誌等級常量來調用這個方法必須和直接調用指定等級方法的結果一致。用一個本規範中未定義且不爲具體實現所知的日誌等級來調用該方法必須拋出一個Psr\Log\InvalidArgumentException。不推薦使用自定義的日誌等級,除非你很是肯定當前類庫對其有所支持。
每一個方法都接受一個字符串,或者一個有__toString方法的對象做爲message參數。實現者 能夠對傳入的對象有特殊的處理。若是沒有,實現者 必須將它轉換成字符串。
message參數中可能包含一些能夠被context參數的數值所替換的佔位符。
佔位符名字必須和context數組類型參數的鍵名對應。
佔位符名字必須使用一對花括號來做爲分隔符。在佔位符和分隔符之間不能有任何空格。
佔位符名字應該只能由A-Z,a-z,0-9,下劃線_和句號.組成。其它的字符做爲之後佔位符規範的保留字。
實現者 可使用佔位符來實現不一樣的轉義和翻譯日誌成文。由於用戶並不知道上下文數據會是什麼,因此不推薦提早轉義佔位符。
下面提供一個佔位符替換的例子,僅做爲參考:
<?php /** * Interpolates context values into the message placeholders. */ function interpolate($message, array $context = array()) { // build a replacement array with braces around the context keys $replace = array(); foreach ($context as $key => $val) { $replace['{' . $key . '}'] = $val; } // interpolate replacement values into the message and return return strtr($message, $replace); } // a message with brace-delimited placeholder names $message = "User {username} created"; // a context array of placeholder names => replacement values $context = array('username' => 'bolivar'); // echoes "Username bolivar created" echo interpolate($message, $context);
每一個方法接受一個數組做爲context參數,用來存儲不適合在字符串中填充的信息。數組能夠包括任何東西。實現者 必須確保他們儘量包容的對context參數進行處理。一個context參數的給定值不可致使拋出異常,也不可產生任何PHP錯誤,警告或者提醒。
若是在context參數中傳入了一個異常對象,它必須以exception做爲鍵名。記錄異常軌跡是通用的模式,而且能夠在日誌系統支持的狀況下從異常中提取出整個調用棧。實現者在將exception當作異常對象來使用以前必須去驗證它是否是一個異常對象,由於它可能包含着任何東西。
Psr\Log\AbstractLogger類可讓你經過繼承它並實現通用的log方法來方便的實現LoggerInterface接口。而其餘八個方法將會把消息和上下文轉發給log方法。
相似的,使用Psr\Log\LoggerTrait只須要你實現通用的log方法。注意特性是不能用來實現接口的,因此你依然須要在你的類中implement LoggerInterface。
Psr\Log\NullLogger是和接口一塊兒提供的。它在沒有可用的日誌記錄器時,能夠爲使用日誌接口的用戶們提供一個後備的「黑洞」。可是,當context參數的構建很是耗時的時候,直接判斷是否須要記錄日誌多是個更好的選擇。
Psr\Log\LoggerAwareInterface只有一個setLogger(LoggerInterface $logger)方法,它能夠在框架中用來隨意設置一個日誌記錄器。
Psr\Log\LoggerAwareTrait特性能夠被用來在各個類中輕鬆實現相同的接口。經過它能夠訪問到$this->logger。
Psr\Log\LogLevel類擁有八個日誌等級的常量。
psr/log中提供了上文描述過的接口和類,以及相關的異常類,還有一組用來驗證你的實現的單元測試。
<?php namespace Psr\Log; /** * Describes a logger instance * * The message MUST be a string or object implementing __toString(). * * The message MAY contain placeholders in the form: {foo} where foo * will be replaced by the context data in key "foo". * * The context array can contain arbitrary data, the only assumption that * can be made by implementors is that if an Exception instance is given * to produce a stack trace, it MUST be in a key named "exception". * * See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md * for the full interface specification. */ interface LoggerInterface { /** * System is unusable. * * @param string $message * @param array $context * @return null */ public function emergency($message, array $context = array()); /** * Action must be taken immediately. * * Example: Entire website down, database unavailable, etc. This should * trigger the SMS alerts and wake you up. * * @param string $message * @param array $context * @return null */ public function alert($message, array $context = array()); /** * Critical conditions. * * Example: Application component unavailable, unexpected exception. * * @param string $message * @param array $context * @return null */ public function critical($message, array $context = array()); /** * Runtime errors that do not require immediate action but should typically * be logged and monitored. * * @param string $message * @param array $context * @return null */ public function error($message, array $context = array()); /** * Exceptional occurrences that are not errors. * * Example: Use of deprecated APIs, poor use of an API, undesirable things * that are not necessarily wrong. * * @param string $message * @param array $context * @return null */ public function warning($message, array $context = array()); /** * Normal but significant events. * * @param string $message * @param array $context * @return null */ public function notice($message, array $context = array()); /** * Interesting events. * * Example: User logs in, SQL logs. * * @param string $message * @param array $context * @return null */ public function info($message, array $context = array()); /** * Detailed debug information. * * @param string $message * @param array $context * @return null */ public function debug($message, array $context = array()); /** * Logs with an arbitrary level. * * @param mixed $level * @param string $message * @param array $context * @return null */ public function log($level, $message, array $context = array()); }
<?php namespace Psr\Log; /** * Describes a logger-aware instance */ interface LoggerAwareInterface { /** * Sets a logger instance on the object * * @param LoggerInterface $logger * @return null */ public function setLogger(LoggerInterface $logger); }
<?php namespace Psr\Log; /** * Describes log levels */ class LogLevel { const EMERGENCY = 'emergency'; const ALERT = 'alert'; const CRITICAL = 'critical'; const ERROR = 'error'; const WARNING = 'warning'; const NOTICE = 'notice'; const INFO = 'info'; const DEBUG = 'debug'; }
這個 PSR 描述的是經過文件路徑自動載入類的指南;它做爲對 PSR-0 的補充;根據這個 指導如何規範存放文件來自動載入;
術語「類」是一個泛稱;它包含類,接口,traits 以及其餘相似的結構;
徹底限定類名應該相似以下範例:
<NamespaceName>(<SubNamespaceNames>)*<ClassName>
當從徹底限定類名載入文件時:
自動載入器的實現不可拋出任何異常,不可引起任何等級的錯誤;也不該返回值;
以下表格展現的是與徹底限定類名、命名空間前綴和基礎目錄相對應的文件路徑:
|徹底限定類名|命名空間前綴|基礎目錄|實際的文件路徑|
|:----:|:----:|:----:|:----:| |\Acme\Log\Writer\FileWriter|Acme\Log\Writer|./acme-log-writer/lib/|./acme-log-writer/lib/FileWriter.php|
|\Aura\Web\Response\Status|Aura\Web|/path/to/aura-web/src/|/path/to/aura-web/src/Response/Status.php| |\Symfony\Core\Request|Symfony\Core|./vendor/Symfony/Core/|./vendor/Symfony/Core/Request.php| |\Zend\Acl|Zend|/usr/includes/Zend/|/usr/includes/Zend/Acl.php|
例子中的自動載入器很是適應這個指南,請參照 示例文件。因爲可能隨時變動,實例不能做爲指南的一部分。