├── PSR-0-cn.md ├── PSR-1-basic-coding-standard-cn.md ├── PSR-2-coding-style-guide-cn.md ├── PSR-2-coding-style-guide-meta-cn.md ├── PSR-3-logger-interface-cn.md ├── PSR-4-autoloader-cn.md ├── PSR-4-autoloader-examples.md ├── PSR-4-autoloader-meta.md └── README.md /PSR-0-cn.md: -------------------------------------------------------------------------------- 1 | 自动加载规范 2 | ==================== 3 | 4 | > **此规范已被弃用** - 本规范已于2014年10月21日被标记为弃用,目前最新的替代规范为 [PSR-4] 。 5 | 6 | 本文是为`自动加载器(autoloader)`实现通用自动加载,所需要遵循的编码规范。 7 | 8 | 规范说明 9 | --------- 10 | 11 | * 一个标准的 命名空间(namespace) 与 类(class) 名称的定义必须符合以下结构: 12 | `\\(\)*`; 13 | * 其中`Vendor Name`为每个命名空间都必须要有的一个顶级命名空间名; 14 | * 需要的话,每个命名空间下可以拥有多个子命名空间; 15 | * 当根据完整的命名空间名从文件系统中载入类文件时,每个命名空间之间的分隔符都会被转换成文件夹路径分隔符; 16 | * 类名称中的每个 `_` 字符也会被转换成文件夹路径分隔符,而命名空间中的 `_` 字符则是无特殊含义的。 17 | * 当从文件系统中载入标准的命名空间或类时,都将添加 `.php` 为目标文件后缀; 18 | * `组织名称(Vendor Name)`、`命名空间(Namespace)` 以及 `类的名称(Class Name)` 可由任意大小写字母组成。 19 | 20 | 范例 21 | -------- 22 | 23 | * `\Doctrine\Common\IsolatedClassLoader` => `/path/to/project/lib/vendor/Doctrine/Common/IsolatedClassLoader.php` 24 | * `\Symfony\Core\Request` => `/path/to/project/lib/vendor/Symfony/Core/Request.php` 25 | * `\Zend\Acl` => `/path/to/project/lib/vendor/Zend/Acl.php` 26 | * `\Zend\Mail\Message` => `/path/to/project/lib/vendor/Zend/Mail/Message.php` 27 | 28 | 命名空间以及类名称中的下划线 29 | ----------------------------------------- 30 | 31 | * `\namespace\package\Class_Name` => `/path/to/project/lib/vendor/namespace/package/Class/Name.php` 32 | * `\namespace\package_name\Class_Name` => `/path/to/project/lib/vendor/namespace/package_name/Class/Name.php` 33 | 34 | 35 | 以上是使用通用自动加载必须遵循的最低规范标准, 可通过以下的示例函数 SplClassLoader 载入 PHP 5.3 的类文件,来验证你所写的命名空间以及类是否符合以上规范。 36 | 37 | 实例 38 | ---------------------- 39 | 40 | 以下示例函数为本规范的一个简单实现。 41 | 42 | ```php 43 | ` 长标签 或 `` 短输出标签; 40 | **一定不可**使用其它自定义标签。 41 | 42 | ### 2.2. 字符编码 43 | 44 | PHP代码**必须**且只可使用`不带BOM的UTF-8`编码。 45 | 46 | ### 2.3. 从属效应(副作用) 47 | 48 | 一份PHP文件中**应该**要不就只定义新的声明,如类、函数或常量等不产生从属效应的操作,要不就只有会产生从属效应的逻辑操作,但**不该**同时具有两者。 49 | 50 | “从属效应”(side effects)一词的意思是,仅仅通过包含文件,不直接声明类、 51 | 函数和常量等,而执行的逻辑操作。 52 | 53 | “从属效应”包含却不仅限于:生成输出、直接的 `require` 或 `include`、连接外部服务、修改 ini 配置、抛出错误或异常、修改全局或静态变量、读或写文件等。 54 | 55 | 以下是一个反例,一份包含声明以及产生从属效应的代码: 56 | 57 | ```php 58 | \n"; 67 | 68 | // 声明函数 69 | function foo() 70 | { 71 | // 函数主体部分 72 | } 73 | ``` 74 | 75 | 下面是一个范例,一份只包含声明不产生从属效应的代码: 76 | 77 | ```php 78 | $b) { 63 | $foo->bar($arg1); 64 | } else { 65 | BazClass::bar($arg2, $arg3); 66 | } 67 | } 68 | 69 | final public static function bar() 70 | { 71 | // method body 72 | } 73 | } 74 | ``` 75 | 76 | 2. 通则 77 | ---------- 78 | 79 | ### 2.1 基本编码准则 80 | 81 | 代码**必须**符合 [PSR-1][] 中的所有规范。 82 | 83 | ### 2.2 文件 84 | 85 | 所有PHP文件**必须**使用`Unix LF (linefeed)`作为行的结束符。 86 | 87 | 所有PHP文件**必须**以一个空白行作为结束。 88 | 89 | 纯PHP代码文件**必须**省略最后的 `?>` 结束标签。 90 | 91 | ### 2.3. 行 92 | 93 | 行的长度**一定不能**有硬性的约束。 94 | 95 | 软性的长度约束**一定**要限制在120个字符以内,若超过此长度,带代码规范检查的编辑器**一定**要发出警告,不过**一定不可**发出错误提示。 96 | 97 | 每行**不应该**多于80个字符,大于80字符的行**应该**折成多行。 98 | 99 | 非空行后**一定不能**有多余的空格符。 100 | 101 | 空行**可以**使得阅读代码更加方便以及有助于代码的分块。 102 | 103 | 每行**一定不能**存在多于一条语句。 104 | 105 | ### 2.4. 缩进 106 | 107 | 代码**必须**使用4个空格符的缩进,**一定不能**用 tab键 。 108 | 109 | > 备注: 使用空格而不是tab键缩进的好处在于, 110 | > 避免在比较代码差异、打补丁、重阅代码以及注释时产生混淆。 111 | > 并且,使用空格缩进,让对齐变得更方便。 112 | 113 | ### 2.5. 关键字 以及 True/False/Null 114 | 115 | PHP所有 [关键字][]**必须**全部小写。 116 | 117 | 常量 `true` 、`false` 和 `null` 也**必须**全部小写。 118 | 119 | [关键字]: http://php.net/manual/en/reserved.keywords.php 120 | 121 | 122 | 123 | 3. namespace 以及 use 声明 124 | --------------------------------- 125 | 126 | `namespace` 声明后 必须 插入一个空白行。 127 | 128 | 所有 `use` 必须 在 `namespace` 后声明。 129 | 130 | 每条 `use` 声明语句 必须 只有一个 `use` 关键词。 131 | 132 | `use` 声明语句块后 必须 要有一个空白行。 133 | 134 | 例如: 135 | 136 | ```php 137 | bar($arg1); 306 | Foo::bar($arg2, $arg3); 307 | ``` 308 | 309 | 参数**可以**分列成多行,此时包括第一个参数在内的每个参数都**必须**单独成行。 310 | 311 | ```php 312 | bar( 314 | $longArgument, 315 | $longerArgument, 316 | $muchLongerArgument 317 | ); 318 | ``` 319 | 320 | 5. 控制结构 321 | --------------------- 322 | 323 | 控制结构的基本规范如下: 324 | 325 | - 控制结构关键词后**必须**有一个空格。 326 | - 左括号 `(` 后**一定不能**有空格。 327 | - 右括号 `)` 前也**一定不**能有空格。 328 | - 右括号 `)` 与开始花括号 `{` 间**一定**有一个空格。 329 | - 结构体主体**一定**要有一次缩进。 330 | - 结束花括号 `}` **一定**在结构体主体后单独成行。 331 | 332 | 每个结构体的主体都**必须**被包含在成对的花括号之中, 333 | 这能让结构体更加结构话,以及减少加入新行时,出错的可能性。 334 | 335 | 336 | ### 5.1. `if` 、 `elseif` 和 `else` 337 | 338 | 标准的 `if` 结构如下代码所示,留意 括号、空格以及花括号的位置, 339 | 注意 `else` 和 `elseif` 都与前面的结束花括号在同一行。 340 | 341 | ```php 342 | $value) { 420 | // foreach body 421 | } 422 | ``` 423 | 424 | ### 5.6. `try`, `catch` 425 | 426 | 标准的 `try catch` 语句如下所示,注意其 括号、空格以及花括号的位置。 427 | 428 | ```php 429 | bar( 523 | $arg1, 524 | function ($arg2) use ($var1) { 525 | // body 526 | }, 527 | $arg3 528 | ); 529 | ``` 530 | 531 | 532 | 7. 总结 533 | -------------- 534 | 以上规范难免有疏忽,其中包括但不仅限于: 535 | 536 | - 全局变量和常量的定义 537 | 538 | - 函数的定义 539 | 540 | - 操作符和赋值 541 | 542 | - 行内对齐 543 | 544 | - 注释和文档描述块 545 | 546 | - 类名的前缀及后缀 547 | 548 | - 最佳实践 549 | 550 | 本规范之后的修订与扩展将弥补以上不足。 551 | 552 | 553 | 附录 A. 问卷调查 554 | ------------------ 555 | 556 | 为了编写本规范,小组制定了调查问卷,用来统计各成员项目的共同规范。 557 | 以下是此问卷调查的数据,在此供查阅。 558 | 559 | ### A.1. 问卷数据 560 | 561 | url,http://www.horde.org/apps/horde/docs/CODING_STANDARDS,http://pear.php.net/manual/en/standards.php,http://solarphp.com/manual/appendix-standards.style,http://framework.zend.com/manual/en/coding-standard.html,http://symfony.com/doc/2.0/contributing/code/standards.html,http://www.ppi.io/docs/coding-standards.html,https://github.com/ezsystems/ezp-next/wiki/codingstandards,http://book.cakephp.org/2.0/en/contributing/cakephp-coding-conventions.html,https://github.com/UnionOfRAD/lithium/wiki/Spec%3A-Coding,http://drupal.org/coding-standards,http://code.google.com/p/sabredav/,http://area51.phpbb.com/docs/31x/coding-guidelines.html,https://docs.google.com/a/zikula.org/document/edit?authkey=CPCU0Us&hgd=1&id=1fcqb93Sn-hR9c0mkN6m_tyWnmEvoswKBtSc0tKkZmJA,http://www.chisimba.com,n/a,https://github.com/Respect/project-info/blob/master/coding-standards-sample.php,n/a,Object Calisthenics for PHP,http://doc.nette.org/en/coding-standard,http://flow3.typo3.org,https://github.com/propelorm/Propel2/wiki/Coding-Standards,http://developer.joomla.org/coding-standards.html 562 | voting,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,no,no,no,?,yes,no,yes 563 | indent_type,4,4,4,4,4,tab,4,tab,tab,2,4,tab,4,4,4,4,4,4,tab,tab,4,tab 564 | line_length_limit_soft,75,75,75,75,no,85,120,120,80,80,80,no,100,80,80,?,?,120,80,120,no,150 565 | line_length_limit_hard,85,85,85,85,no,no,no,no,100,?,no,no,no,100,100,?,120,120,no,no,no,no 566 | class_names,studly,studly,studly,studly,studly,studly,studly,studly,studly,studly,studly,lower_under,studly,lower,studly,studly,studly,studly,?,studly,studly,studly 567 | class_brace_line,next,next,next,next,next,same,next,same,same,same,same,next,next,next,next,next,next,next,next,same,next,next 568 | constant_names,upper,upper,upper,upper,upper,upper,upper,upper,upper,upper,upper,upper,upper,upper,upper,upper,upper,upper,upper,upper,upper,upper 569 | true_false_null,lower,lower,lower,lower,lower,lower,lower,lower,lower,upper,lower,lower,lower,upper,lower,lower,lower,lower,lower,upper,lower,lower 570 | method_names,camel,camel,camel,camel,camel,camel,camel,camel,camel,camel,camel,lower_under,camel,camel,camel,camel,camel,camel,camel,camel,camel,camel 571 | method_brace_line,next,next,next,next,next,same,next,same,same,same,same,next,next,same,next,next,next,next,next,same,next,next 572 | control_brace_line,same,same,same,same,same,same,next,same,same,same,same,next,same,same,next,same,same,same,same,same,same,next 573 | control_space_after,yes,yes,yes,yes,yes,no,yes,yes,yes,yes,no,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes 574 | always_use_control_braces,yes,yes,yes,yes,yes,yes,no,yes,yes,yes,no,yes,yes,yes,yes,no,yes,yes,yes,yes,yes,yes 575 | else_elseif_line,same,same,same,same,same,same,next,same,same,next,same,next,same,next,next,same,same,same,same,same,same,next 576 | case_break_indent_from_switch,0/1,0/1,0/1,1/2,1/2,1/2,1/2,1/1,1/1,1/2,1/2,1/1,1/2,1/2,1/2,1/2,1/2,1/2,0/1,1/1,1/2,1/2 577 | function_space_after,no,no,no,no,no,no,no,no,no,no,no,no,no,no,no,no,no,no,no,no,no,no 578 | closing_php_tag_required,no,no,no,no,no,no,no,no,yes,no,no,no,no,yes,no,no,no,no,no,yes,no,no 579 | line_endings,LF,LF,LF,LF,LF,LF,LF,LF,?,LF,?,LF,LF,LF,LF,?,,LF,?,LF,LF,LF 580 | static_or_visibility_first,static,?,static,either,either,either,visibility,visibility,visibility,either,static,either,?,visibility,?,?,either,either,visibility,visibility,static,? 581 | control_space_parens,no,no,no,no,no,no,yes,no,no,no,no,no,no,yes,?,no,no,no,no,no,no,no 582 | blank_line_after_php,no,no,no,no,yes,no,no,no,no,yes,yes,no,no,yes,?,yes,yes,no,yes,no,yes,no 583 | class_method_control_brace,next/next/same,next/next/same,next/next/same,next/next/same,next/next/same,same/same/same,next/next/next,same/same/same,same/same/same,same/same/same,same/same/same,next/next/next,next/next/same,next/same/same,next/next/next,next/next/same,next/next/same,next/next/same,next/next/same,same/same/same,next/next/same,next/next/next 584 | 585 | ### A.2. 问卷说明 586 | 587 | `indent_type`: 588 | 缩进类型. `tab` = "使用 tab 键一次", `2` or `4` = "空格的数量" 589 | 590 | `line_length_limit_soft`: 591 | 每行字符数量的“软”限制. `?` = 不可辩或无作答, `no` 表示无限制. 592 | 593 | `line_length_limit_hard`: 594 | 每行字符数量的“硬”限制. `?` = 不可辩或无作答, `no` 表示无限制. 595 | 596 | `class_names`: 597 | 类名称的命名. `lower` = 只允许小写字母, `lower_under` = 下滑线分隔的小写字母, `studly` = StudlyCase 的驼峰风格. 598 | 599 | `class_brace_line`: 600 | 类的开始花括号是与 class 关键字在同一行或是在其的下一行? 601 | 602 | `constant_names`: 603 | 类的常量如何命名? `upper` = 下划线分隔的大写字母. 604 | 605 | `true_false_null`: 606 | 关键字 `true`、`false` 以及 `null` 是全部小写 `lower` 还是全部大写 `upper`? 607 | 608 | `method_names`: 609 | 方法名称如何命名? `camel` = `camelCase`, `lower_under` = 下划线分隔的小写字母. 610 | 611 | `method_brace_line`: 612 | 方法的开始花括号是与方法名在同一行还是在其的下一行? 613 | 614 | `control_brace_line`: 615 | 控制结构的开始花括号是与声明在同一行还是在其的下一行? 616 | 617 | `control_space_after`: 618 | 控制结构关键词后是否有空格? 619 | 620 | `always_use_control_braces`: 621 | 控制结构体是否都要被包含在花括号内? 622 | 623 | `else_elseif_line`: 624 | `else` 或 `elseif` 与前面的结束花括号在同一行还是在其的下一行? 625 | 626 | `case_break_indent_from_switch`: 627 | `switch` 语句中的 `case` 和 `break` 需要相对 `switch` 缩进多少次? 628 | 629 | `function_space_after`: 630 | 函数调用语句中,函数名称与变量列表的左括号间是否有空格? 631 | 632 | `closing_php_tag_required`: 633 | 纯 PHP 代码的文件,是否需要 `?>` 结束标签? 634 | 635 | `line_endings`: 636 | 选择哪种类型的行结束符? 637 | 638 | `static_or_visibility_first`: 639 | 声明一个静态方法时,`static` 是写访问修饰符前还是后? 640 | 641 | `control_space_parens`: 642 | 控制结构里,左括号后以及右括号前是否有空格?`yes` = `if ( $expr )`, `no` = `if ($expr)`. 643 | 644 | `blank_line_after_php`: 645 | PHP 开始标签后,是否需要一个空行? 646 | 647 | `class_method_control_brace`: 648 | 开始花括号在类、方法和控制结构的位置统计。 649 | 650 | ### A.3. 问卷统计结果 651 | 652 | indent_type: 653 | tab: 7 654 | 2: 1 655 | 4: 14 656 | line_length_limit_soft: 657 | ?: 2 658 | no: 3 659 | 75: 4 660 | 80: 6 661 | 85: 1 662 | 100: 1 663 | 120: 4 664 | 150: 1 665 | line_length_limit_hard: 666 | ?: 2 667 | no: 11 668 | 85: 4 669 | 100: 3 670 | 120: 2 671 | class_names: 672 | ?: 1 673 | lower: 1 674 | lower_under: 1 675 | studly: 19 676 | class_brace_line: 677 | next: 16 678 | same: 6 679 | constant_names: 680 | upper: 22 681 | true_false_null: 682 | lower: 19 683 | upper: 3 684 | method_names: 685 | camel: 21 686 | lower_under: 1 687 | method_brace_line: 688 | next: 15 689 | same: 7 690 | control_brace_line: 691 | next: 4 692 | same: 18 693 | control_space_after: 694 | no: 2 695 | yes: 20 696 | always_use_control_braces: 697 | no: 3 698 | yes: 19 699 | else_elseif_line: 700 | next: 6 701 | same: 16 702 | case_break_indent_from_switch: 703 | 0/1: 4 704 | 1/1: 4 705 | 1/2: 14 706 | function_space_after: 707 | no: 22 708 | closing_php_tag_required: 709 | no: 19 710 | yes: 3 711 | line_endings: 712 | ?: 5 713 | LF: 17 714 | static_or_visibility_first: 715 | ?: 5 716 | either: 7 717 | static: 4 718 | visibility: 6 719 | control_space_parens: 720 | ?: 1 721 | no: 19 722 | yes: 2 723 | blank_line_after_php: 724 | ?: 1 725 | no: 13 726 | yes: 8 727 | class_method_control_brace: 728 | next/next/next: 4 729 | next/next/same: 11 730 | next/same/same: 1 731 | same/same/same: 6 732 | -------------------------------------------------------------------------------- /PSR-2-coding-style-guide-meta-cn.md: -------------------------------------------------------------------------------- 1 | PSR-2 补充文档 2 | =================== 3 | 4 | 1. 摘要 5 | ---------- 6 | 7 | 本规范希望通过制定一系列规范化PHP代码的规则,以减少在浏览不同作者的代码时,因代码风格的不同而造成不便。 8 | 9 | 当多名程序员在多个项目中合作时,就需要一个共同的编码规范, 10 | 而本文中的风格规范源自于多个不同项目代码风格的共同特性, 11 | 因此,本规范的价值在于我们都遵循这个编码风格,而不是在于它本身。 12 | 13 | 14 | 2. 投票 15 | -------- 16 | 17 | - **投票点:** [ML](https://groups.google.com/d/msg/php-fig/c-QVvnZdMQ0/TdDMdzKFpdIJ) 18 | 19 | 20 | 3. 勘误 21 | --------- 22 | 23 | ### 3.1 - 多行参数 (09/08/2013) 24 | 25 | 使用一个或多个跨行的参数(如数组和匿名函数)并不需要触发 4.6 节中关于参数列表的单行规定, 26 | 因此,在参数表中的数组和匿名函数是可以单独分列成多行的。 27 | 28 | 以下的例子是符合 PSR-2 规范的: 29 | 30 | ```php 31 | get('/hello/{name}', function ($name) use ($app) { 37 | return 'Hello '.$app->escape($name); 38 | }); 39 | ``` 40 | 41 | ### 3.2 - 多行参数 (10/17/2013) 42 | 43 | 当需要扩展多个接口时,`extends` 的相关规范与 4.1 节中 `implements` 的规范一致。 44 | 45 | -------------------------------------------------------------------------------- /PSR-3-logger-interface-cn.md: -------------------------------------------------------------------------------- 1 | 日志接口规范 2 | ================ 3 | 4 | 本文制定了日志类库的通用接口规范。 5 | 6 | 本规范的主要目的,是为了让日志类库以简单通用的方式,通过接收一个 `Psr\Log\LoggerInterface` 对象,来记录日志信息。 7 | 框架以及CMS内容管理系统如有需要,**可以**对此接口进行扩展,但需遵循本规范, 8 | 这才能保证在使用第三方的类库文件时,日志接口仍能正常对接。 9 | 10 | 关键词 “必须”("MUST")、“一定不可/一定不能”("MUST NOT")、“需要”("REQUIRED")、 11 | “将会”("SHALL")、“不会”("SHALL NOT")、“应该”("SHOULD")、“不该”("SHOULD NOT")、 12 | “推荐”("RECOMMENDED")、“可以”("MAY")和”可选“("OPTIONAL")的详细描述可参见 [RFC 2119][] 。 13 | 14 | 本文中的 `实现者` 指的是实现了 `LoggerInterface` 接口的类库或者框架,反过来讲,他们就是 `LoggerInterface` 的 `使用者`。 15 | 16 | [RFC 2119]: http://tools.ietf.org/html/rfc2119 17 | 18 | 1. 规范说明 19 | ----------------- 20 | 21 | ### 1.1 基本规范 22 | 23 | - `LoggerInterface` 接口对外定义了八个方法,分别用来记录 [RFC 5424][] 中定义的八个等级的日志:debug、 info、 notice、 warning、 error、 critical、 alert 以及 emergency 。 24 | 25 | - 第九个方法 —— `log`,其第一个参数为记录的等级。可使用一个预先定义的等级常量作为参数来调用此方法,**必须**与直接调用以上八个方法具有相同的效果。如果传入的等级常量参数没有预先定义,则**必须**抛出 `Psr\Log\InvalidArgumentException` 类型的异常。在不确定的情况下,使用者**不该**使用未支持的等级常量来调用此方法。 26 | 27 | [RFC 5424]: http://tools.ietf.org/html/rfc5424 28 | 29 | ### 1.2 记录信息 30 | 31 | - 以上每个方法都接受一个字符串类型或者是有 `__toString()` 方法的对象作为记录信息参数,这样,实现者就能把它当成字符串来处理,否则实现者**必须**自己把它转换成字符串。 32 | 33 | - 记录信息参数**可以**携带占位符,实现者**可以**根据上下文将其它替换成相应的值。 34 | 35 | 其中占位符**必须**与上下文数组中的键名保持一致。 36 | 37 | 占位符的名称**必须**由一个左花括号 `{` 以及一个右括号 `}` 包含。但花括号与名称之间**一定不能**有空格符。 38 | 39 | 占位符的名称**应该**只由 `A-Z`、 `a-z`,`0-9`、下划线 `_`、以及英文的句号 `.`组成,其它字符作为将来占位符规范的保留。 40 | 41 | 实现者**可以**通过对占位符采用不同的转义和转换策略,来生成最终的日志。 42 | 而使用者在不知道上下文的前提下,**不该**提前转义占位符。 43 | 44 | 以下是一个占位符使用的例子: 45 | 46 | ```php 47 | /** 48 | * 用上下文信息替换记录信息中的占位符 49 | */ 50 | function interpolate($message, array $context = array()) 51 | { 52 | // 构建一个花括号包含的键名的替换数组 53 | $replace = array(); 54 | foreach ($context as $key => $val) { 55 | $replace['{' . $key . '}'] = $val; 56 | } 57 | 58 | // 替换记录信息中的占位符,最后返回修改后的记录信息。 59 | return strtr($message, $replace); 60 | } 61 | 62 | // 含有带花括号占位符的记录信息。 63 | $message = "User {username} created"; 64 | 65 | // 带有替换信息的上下文数组,键名为占位符名称,键值为替换值。 66 | $context = array('username' => 'bolivar'); 67 | 68 | // 输出 "Username bolivar created" 69 | echo interpolate($message, $context); 70 | ``` 71 | 72 | ### 1.3 上下文 73 | 74 | - 每个记录函数都接受一个上下文数组参数,用来装载字符串类型无法表示的信息。它**可以**装载任何信息,所以实现者**必须**确保能正确处理其装载的信息,对于其装载的数据,**一定不能** 抛出异常,或产生PHP出错、警告或提醒信息(error、warning、notice)。 75 | 76 | - 如需通过上下文参数传入了一个 `Exception` 对象, **必须**以 `'exception'` 作为键名。 77 | 记录异常信息是很普遍的,所以如果它能够在记录类库的底层实现,就能够让实现者从异常信息中抽丝剥茧。 78 | 当然,实现者在使用它时,**必须**确保键名为 `'exception'` 的键值是否真的是一个 `Exception`,毕竟它**可以**装载任何信息。 79 | 80 | ### 1.4 助手类和接口 81 | 82 | - `Psr\Log\AbstractLogger` 类使得只需继承它和实现其中的 `log` 方法,就能够很轻易地实现 `LoggerInterface` 接口,而另外八个方法就能够把记录信息和上下文信息传给它。 83 | 84 | - 同样地,使用 `Psr\Log\LoggerTrait` 也只需实现其中的 `log` 方法。不过,需要特别注意的是,在traits可复用代码块还不能实现接口前,还需要 `implement LoggerInterface`。 85 | 86 | - 在没有可用的日志记录器时, `Psr\Log\NullLogger` 接口**可以**为使用者提供一个备用的日志“黑洞”。不过,当上下文的构建非常消耗资源时,带条件检查的日志记录或许是更好的办法。 87 | 88 | - `Psr\Log\LoggerAwareInterface` 接口仅包括一个 89 | `setLogger(LoggerInterface $logger)` 方法,框架可以使用它实现自动连接任意的日志记录实例。 90 | 91 | - `Psr\Log\LoggerAwareTrait` trait可复用代码块可以在任何的类里面使用,只需通过它提供的 `$this->logger`,就可以轻松地实现等同的接口。 92 | 93 | - `Psr\Log\LogLevel` 类装载了八个记录等级常量。 94 | 95 | 2. 包 96 | ---------- 97 | 98 | 上述的接口、类和相关的异常类,以及一系列的实现检测文件,都包含在 [psr/log](https://packagist.org/packages/psr/log) 文件包中。 99 | 100 | 3. `Psr\Log\LoggerInterface` 101 | ---------------------------- 102 | 103 | ```php 104 | (\<子命名空间>)*\<类名> 22 | 23 | 1. 完整的类名**必须**要有一个顶级命名空间,被称为 "vendor namespace"; 24 | 25 | 2. 完整的类名**可以**有一个或多个子命名空间; 26 | 27 | 3. 完整的类名**必须**有一个最终的类名; 28 | 29 | 4. 完整的类名中任意一部分中的下滑线都是没有特殊含义的; 30 | 31 | 5. 完整的类名**可以**由任意大小写字母组成; 32 | 33 | 6. 所有类名都**必须**是大小写敏感的。 34 | 35 | 3. 当根据完整的类名载入相应的文件…… 36 | 37 | 1. 完整的类名中,去掉最前面的命名空间分隔符,前面连续的一个或多个命名空间和子命名空间,作为“命名空间前缀”,其必须与至少一个“文件基目录”相对应; 38 | 39 | 2. 紧接命名空间前缀后的子命名空间**必须**与相应的”文件基目录“相匹配,其中的命名空间分隔符将作为目录分隔符。 40 | 41 | 3. 末尾的类名**必须**与对应的以 `.php` 为后缀的文件同名。 42 | 43 | 4. 自动加载器(autoloader)的实现**一定不能**抛出异常、**一定不能**触发任一级别的错误信息以及**不应该**有返回值。 44 | 45 | 46 | ## 3. 例子 47 | 48 | 下表展示了符合规范完整类名、命名空间前缀和文件基目录所对应的文件路径。 49 | 50 | | 完整类名 | 命名空间前缀 | 文件基目录 | 文件路径 51 | | ----------------------------- |--------------------|--------------------------|------------------------------------------- 52 | | \Acme\Log\Writer\File_Writer | Acme\Log\Writer | ./acme-log-writer/lib/ | ./acme-log-writer/lib/File_Writer.php 53 | | \Aura\Web\Response\Status | Aura\Web | /path/to/aura-web/src/ | /path/to/aura-web/src/Response/Status.php 54 | | \Symfony\Core\Request | Symfony\Core | ./vendor/Symfony/Core/ | ./vendor/Symfony/Core/Request.php 55 | | \Zend\Acl | Zend | /usr/includes/Zend/ | /usr/includes/Zend/Acl.php 56 | 57 | 关于本规范的实现,可参阅 [相关实例][] 58 | 注意:实例并**不**属于规范的一部分,且随时**会**有所变动。 59 | 60 | [自动载入]: http://php.net/autoload 61 | [PSR-0]: https://github.com/PizzaLiu/PHP-FIG/blob/master/PSR-0-cn.md 62 | [相关实例]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader-examples.md 63 | -------------------------------------------------------------------------------- /PSR-4-autoloader-examples.md: -------------------------------------------------------------------------------- 1 | PSR-4 相关示例 2 | ================================ 3 | 4 | 以下是 PSR-4 规范的相关示例代码: 5 | 6 | 闭包的实现示例 7 | --------------- 8 | 9 | ```php 10 | register(); 88 | * 89 | * // register the base directories for the namespace prefix 90 | * $loader->addNamespace('Foo\Bar', '/path/to/packages/foo-bar/src'); 91 | * $loader->addNamespace('Foo\Bar', '/path/to/packages/foo-bar/tests'); 92 | * 93 | * The following line would cause the autoloader to attempt to load the 94 | * \Foo\Bar\Qux\Quux class from /path/to/packages/foo-bar/src/Qux/Quux.php: 95 | * 96 | * prefixes[$prefix]) === false) { 144 | $this->prefixes[$prefix] = array(); 145 | } 146 | 147 | // 将命名空间前缀与文件基目录对插入保存数组 148 | if ($prepend) { 149 | array_unshift($this->prefixes[$prefix], $base_dir); 150 | } else { 151 | array_push($this->prefixes[$prefix], $base_dir); 152 | } 153 | } 154 | 155 | /** 156 | * 由类名载入相应类文件 157 | * 158 | * @param string $class 完整的类名 159 | * @return mixed 成功载入则返回载入的文件名,否则返回布尔 false 160 | */ 161 | public function loadClass($class) 162 | { 163 | // 当前命名空间前缀 164 | $prefix = $class; 165 | 166 | // work backwards through the namespace names of the fully-qualified 167 | // class name to find a mapped file name 168 | while (false !== $pos = strrpos($prefix, '\\')) { 169 | 170 | // retain the trailing namespace separator in the prefix 171 | $prefix = substr($class, 0, $pos + 1); 172 | 173 | // the rest is the relative class name 174 | $relative_class = substr($class, $pos + 1); 175 | 176 | // try to load a mapped file for the prefix and relative class 177 | $mapped_file = $this->loadMappedFile($prefix, $relative_class); 178 | if ($mapped_file) { 179 | return $mapped_file; 180 | } 181 | 182 | // remove the trailing namespace separator for the next iteration 183 | // of strrpos() 184 | $prefix = rtrim($prefix, '\\'); 185 | } 186 | 187 | // 找不到相应文件 188 | return false; 189 | } 190 | 191 | /** 192 | * Load the mapped file for a namespace prefix and relative class. 193 | * 194 | * @param string $prefix The namespace prefix. 195 | * @param string $relative_class The relative class name. 196 | * @return mixed Boolean false if no mapped file can be loaded, or the 197 | * name of the mapped file that was loaded. 198 | */ 199 | protected function loadMappedFile($prefix, $relative_class) 200 | { 201 | // are there any base directories for this namespace prefix? 202 | if (isset($this->prefixes[$prefix]) === false) { 203 | return false; 204 | } 205 | 206 | // look through base directories for this namespace prefix 207 | foreach ($this->prefixes[$prefix] as $base_dir) { 208 | 209 | // replace the namespace prefix with the base directory, 210 | // replace namespace separators with directory separators 211 | // in the relative class name, append with .php 212 | $file = $base_dir 213 | . str_replace('\\', DIRECTORY_SEPARATOR, $relative_class) 214 | . '.php'; 215 | $file = $base_dir 216 | . str_replace('\\', '/', $relative_class) 217 | . '.php'; 218 | 219 | // 当文件存在时,在入之 220 | if ($this->requireFile($file)) { 221 | // 完成载入 222 | return $file; 223 | } 224 | } 225 | 226 | // 找不到相应文件 227 | return false; 228 | } 229 | 230 | /** 231 | * 当文件存在,则从文件系统载入之 232 | * 233 | * @param string $file 需要载入的文件 234 | * @return bool 当文件存在则为 True,否则为 false 235 | */ 236 | protected function requireFile($file) 237 | { 238 | if (file_exists($file)) { 239 | require $file; 240 | return true; 241 | } 242 | return false; 243 | } 244 | } 245 | ``` 246 | 247 | ### 单元测试 248 | 249 | 以下是上面代码单元测试的一种实现: 250 | 251 | ```php 252 | files = $files; 262 | } 263 | 264 | protected function requireFile($file) 265 | { 266 | return in_array($file, $this->files); 267 | } 268 | } 269 | 270 | class Psr4AutoloaderClassTest extends \PHPUnit_Framework_TestCase 271 | { 272 | protected $loader; 273 | 274 | protected function setUp() 275 | { 276 | $this->loader = new MockPsr4AutoloaderClass; 277 | 278 | $this->loader->setFiles(array( 279 | '/vendor/foo.bar/src/ClassName.php', 280 | '/vendor/foo.bar/src/DoomClassName.php', 281 | '/vendor/foo.bar/tests/ClassNameTest.php', 282 | '/vendor/foo.bardoom/src/ClassName.php', 283 | '/vendor/foo.bar.baz.dib/src/ClassName.php', 284 | '/vendor/foo.bar.baz.dib.zim.gir/src/ClassName.php', 285 | )); 286 | 287 | $this->loader->addNamespace( 288 | 'Foo\Bar', 289 | '/vendor/foo.bar/src' 290 | ); 291 | 292 | $this->loader->addNamespace( 293 | 'Foo\Bar', 294 | '/vendor/foo.bar/tests' 295 | ); 296 | 297 | $this->loader->addNamespace( 298 | 'Foo\BarDoom', 299 | '/vendor/foo.bardoom/src' 300 | ); 301 | 302 | $this->loader->addNamespace( 303 | 'Foo\Bar\Baz\Dib', 304 | '/vendor/foo.bar.baz.dib/src' 305 | ); 306 | 307 | $this->loader->addNamespace( 308 | 'Foo\Bar\Baz\Dib\Zim\Gir', 309 | '/vendor/foo.bar.baz.dib.zim.gir/src' 310 | ); 311 | } 312 | 313 | public function testExistingFile() 314 | { 315 | $actual = $this->loader->loadClass('Foo\Bar\ClassName'); 316 | $expect = '/vendor/foo.bar/src/ClassName.php'; 317 | $this->assertSame($expect, $actual); 318 | 319 | $actual = $this->loader->loadClass('Foo\Bar\ClassNameTest'); 320 | $expect = '/vendor/foo.bar/tests/ClassNameTest.php'; 321 | $this->assertSame($expect, $actual); 322 | } 323 | 324 | public function testMissingFile() 325 | { 326 | $actual = $this->loader->loadClass('No_Vendor\No_Package\NoClass'); 327 | $this->assertFalse($actual); 328 | } 329 | 330 | public function testDeepFile() 331 | { 332 | $actual = $this->loader->loadClass('Foo\Bar\Baz\Dib\Zim\Gir\ClassName'); 333 | $expect = '/vendor/foo.bar.baz.dib.zim.gir/src/ClassName.php'; 334 | $this->assertSame($expect, $actual); 335 | } 336 | 337 | public function testConfusion() 338 | { 339 | $actual = $this->loader->loadClass('Foo\Bar\DoomClassName'); 340 | $expect = '/vendor/foo.bar/src/DoomClassName.php'; 341 | $this->assertSame($expect, $actual); 342 | 343 | $actual = $this->loader->loadClass('Foo\BarDoom\ClassName'); 344 | $expect = '/vendor/foo.bardoom/src/ClassName.php'; 345 | $this->assertSame($expect, $actual); 346 | } 347 | } 348 | -------------------------------------------------------------------------------- /PSR-4-autoloader-meta.md: -------------------------------------------------------------------------------- 1 | PSR-4 附加文档 2 | =================== 3 | 4 | 1. 摘要 5 | ---------- 6 | 7 | 本文档的目的是制定一个可互操作的PHP加载器的规范, 8 | 令其可以将命名空间与文件路径相对应,且可以与其他 SPL 注册加载器共存。 9 | 这是一个 PSR-0 的补充文档,而不是替代。 10 | 11 | 2. 为什么要制定此文档? 12 | -------------- 13 | 14 | ### PSR-0 的历史 15 | 16 | The PSR-0 class naming and autoloading standard rose out of the broad 17 | acceptance of the Horde/PEAR convention under the constraints of PHP 5.2 and 18 | previous. With that convention, the tendency was to put all PHP source classes 19 | in a single main directory, using underscores in the class name to indicate 20 | pseudo-namespaces, like so: 21 | 22 | /path/to/src/ 23 | VendorFoo/ 24 | Bar/ 25 | Baz.php # VendorFoo_Bar_Baz 26 | VendorDib/ 27 | Zim/ 28 | Gir.php # Vendor_Dib_Zim_Gir 29 | 30 | With the release of PHP 5.3 and the availability of namespaces proper, PSR-0 31 | was introduced to allow both the old Horde/PEAR underscore mode *and* the use 32 | of the new namespace notation. Underscores were still allowed in the class 33 | name to ease transition from the older namespace naming to the newer naming, 34 | and thereby to encourage wider adoption. 35 | 36 | /path/to/src/ 37 | VendorFoo/ 38 | Bar/ 39 | Baz.php # VendorFoo_Bar_Baz 40 | VendorDib/ 41 | Zim/ 42 | Gir.php # VendorDib_Zim_Gir 43 | Irk_Operation/ 44 | Impending_Doom/ 45 | V1.php 46 | V2.php # Irk_Operation\Impending_Doom\V2 47 | 48 | This structure is informed very much by the fact that the PEAR installer moved 49 | source files from PEAR packages into a single central directory. 50 | 51 | ### Along Comes Composer 52 | 53 | With Composer, package sources are no longer copied to a single global 54 | location. They are used from their installed location and are not moved 55 | around. This means that with Composer there is no "single main directory" for 56 | PHP sources as with PEAR. Instead, there are multiple directories; each 57 | package is in a separate directory for each project. 58 | 59 | To meet the requirements of PSR-0, this leads to Composer packages looking 60 | like this: 61 | 62 | vendor/ 63 | vendor_name/ 64 | package_name/ 65 | src/ 66 | Vendor_Name/ 67 | Package_Name/ 68 | ClassName.php # Vendor_Name\Package_Name\ClassName 69 | tests/ 70 | Vendor_Name/ 71 | Package_Name/ 72 | ClassNameTest.php # Vendor_Name\Package_Name\ClassNameTest 73 | 74 | The "src" and "tests" directories have to include vendor and package directory 75 | names. This is an artifact of PSR-0 compliance. 76 | 77 | Many find this structure to be deeper and more-repetitive than necessary. This 78 | proposal suggests that an additional or superseding PSR would be useful so 79 | that we can have packages that look more like the following: 80 | 81 | vendor/ 82 | vendor_name/ 83 | package_name/ 84 | src/ 85 | ClassName.php # Vendor_Name\Package_Name\ClassName 86 | tests/ 87 | ClassNameTest.php # Vendor_Name\Package_Name\ClassNameTest 88 | 89 | This would require an implementation of what was initially called 90 | "package-oriented autoloading" (as vs the traditional "direct class-to-file 91 | autoloading"). 92 | 93 | ### 基于包的自动载入 94 | 95 | It's difficult to implement package-oriented autoloading via an extension or 96 | amendment to PSR-0, because PSR-0 does not allow for an intercessory path 97 | between any portions of the class name. This means the implementation of a 98 | package-oriented autoloader would be more complicated than PSR-0. However, it 99 | would allow for cleaner packages. 100 | 101 | Initially, the following rules were suggested: 102 | 103 | 1. Implementors MUST use at least two namespace levels: a vendor name, and 104 | package name within that vendor. (This top-level two-name combination is 105 | hereinafter referred to as the vendor-package name or the vendor-package 106 | namespace.) 107 | 108 | 2. Implementors MUST allow a path infix between the vendor-package namespace 109 | and the remainder of the fully qualified class name. 110 | 111 | 3. The vendor-package namespace MAY map to any directory. The remaining 112 | portion of the fully-qualified class name MUST map the namespace names to 113 | identically-named directories, and MUST map the class name to an 114 | identically-named file ending in .php. 115 | 116 | Note that this means the end of underscore-as-directory-separator in the class 117 | name. One might think underscores should be honored as they are under 118 | PSR-0, but seeing as their presence in that document is in reference to 119 | transitioning away from PHP 5.2 and previous pseudo-namespacing, it is 120 | acceptable to remove them here as well. 121 | 122 | 123 | 3. Scope 124 | -------- 125 | 126 | ### 3.1 Goals 127 | 128 | - Retain the PSR-0 rule that implementors MUST use at least two namespace 129 | levels: a vendor name, and package name within that vendor. 130 | 131 | - Allow a path infix between the vendor-package namespace and the remainder of 132 | the fully qualified class name. 133 | 134 | - Allow the vendor-package namespace MAY map to any directory, perhaps 135 | multiple directories. 136 | 137 | - End the honoring of underscores in class names as directory separators 138 | 139 | ### 3.2 Non-Goals 140 | 141 | - Provide a general transformation algorithm for non-class resources 142 | 143 | 144 | 4. Approaches 145 | ------------- 146 | 147 | ### 4.1 Chosen Approach 148 | 149 | This approach retains key characteristics of PSR-0 while eliminating the 150 | deeper directory structures it requires. In addition, it specifies certain 151 | additional rules that make implementations explicitly more interoperable. 152 | 153 | Although not related to directory mapping, the final draft also specifies how 154 | autoloaders should handle errors. Specifically, it forbids throwing exceptions 155 | or raising errors. The reason is two-fold. 156 | 157 | 1. Autoloaders in PHP are explicitly designed to be stackable so that if one 158 | autoloader cannot load a class another has a chance to do so. Having an autoloader 159 | trigger a breaking error condition violates that compatibility. 160 | 161 | 2. `class_exists()` and `interface_exists()` allow "not found, even after trying to 162 | autoload" as a legitimate, normal use case. An autoloader that throws exceptions 163 | renders `class_exists()` unusable, which is entirely unacceptable from an interoperability 164 | standpoint. Autoloaders that wish to provide additional debugging information 165 | in a class-not-found case should do so via logging instead, either to a PSR-3 166 | compatible logger or otherwise. 167 | 168 | Pros: 169 | 170 | - Shallower directory structures 171 | 172 | - More flexible file locations 173 | 174 | - Stops underscore in class name from being honored as directory separator 175 | 176 | - Makes implementations more explicitly interoperable 177 | 178 | Cons: 179 | 180 | - It is no longer possible, as under PSR-0, to merely examine a class name to 181 | determine where it is in the file system (the "class-to-file" convention 182 | inherited from Horde/PEAR). 183 | 184 | 185 | ### 4.2 Alternative: Stay With PSR-0 Only 186 | 187 | Staying with PSR-0 only, although reasonable, does leave us with relatively 188 | deeper directory structures. 189 | 190 | Pros: 191 | 192 | - No need to change anyone's habits or implementations 193 | 194 | Cons: 195 | 196 | - Leaves us with deeper directory structures 197 | 198 | - Leaves us with underscores in the class name being honored as directory 199 | separators 200 | 201 | 202 | ### 4.3 Alternative: Split Up Autoloading And Transformation 203 | 204 | Beau Simensen and others suggested that the transformation algorithm might be 205 | split out from the autoloading proposal, so that the transformation rules 206 | could be referenced by other proposals. After doing the work to separate them, 207 | followed by a poll and some discussion, the combined version (i.e., 208 | transformation rules embedded in the autoloader proposal) was revealed as the 209 | preference. 210 | 211 | Pros: 212 | 213 | - Transformation rules could be referenced separately by other proposal 214 | 215 | Cons: 216 | 217 | - Not in line with the wishes of poll respondents and some collaborators 218 | 219 | ### 4.4 Alternative: Use More Imperative And Narrative Language 220 | 221 | After the second vote was pulled by a Sponsor after hearing from multiple +1 222 | voters that they supported the idea but did not agree with (or understand) the 223 | wording of the proposal, there was a period during which the voted-on proposal 224 | was expanded with greater narrative and somewhat more imperative language. This 225 | approach was decried by a vocal minority of participants. After some time, Beau 226 | Simensen started an experimental revision with an eye to PSR-0; the Editor and 227 | Sponsors favored this more terse approach and shepherded the version now under 228 | consideration, written by Paul M. Jones and contributed to by many. 229 | 230 | ### Compatability Note with PHP 5.3.2 and below 231 | 232 | PHP versions before 5.3.3 do not strip the leading namespace separator, so 233 | the responsibility to look out for this falls on the implementation. Failing 234 | to strip the leading namespace seperator could lead to unexpected behavior. 235 | 236 | 237 | 5. 相关人员 238 | --------- 239 | 240 | ### 5.1 编辑 241 | 242 | - Paul M. Jones, Solar/Aura 243 | 244 | ### 5.2 发起人 245 | 246 | - Phil Sturgeon, PyroCMS (Coordinator) 247 | - Larry Garfield, Drupal 248 | 249 | ### 5.3 贡献者 250 | 251 | - Andreas Hennings 252 | - Bernhard Schussek 253 | - Beau Simensen 254 | - Donald Gilbert 255 | - Mike van Riel 256 | - Paul Dragoonis 257 | - 其余人员不一一细数 258 | 259 | 260 | 6. 投票 261 | -------- 262 | 263 | - **投票入口:** 264 | 265 | - **接纳的投票:** 266 | 267 | - 第一轮: , 268 | presented prior to new workflow; aborted due to accidental proposal modification 269 | 270 | - 第二轮: , 271 | cancelled at the discretion of the sponsor 272 | 273 | - 第三轮: 待定 274 | 275 | 276 | 7. 相关链接 277 | ----------------- 278 | 279 | - [Autoloader, round 4](https://groups.google.com/forum/#!topicsearchin/php-fig/autoload/php-fig/lpmJcmkNYjM) 280 | - [POLL: Autoloader: Split or Combined?](https://groups.google.com/forum/#!topicsearchin/php-fig/autoload/php-fig/fGwA6XHlYhI) 281 | - [PSR-X autoloader spec: Loopholes, ambiguities](https://groups.google.com/forum/#!topicsearchin/php-fig/autoload/php-fig/kUbzJAbHxmg) 282 | - [Autoloader: Combine Proposals?](https://groups.google.com/forum/#!topicsearchin/php-fig/autoload/php-fig/422dFBGs1Yc) 283 | - [Package-Oriented Autoloader, Round 2](https://groups.google.com/forum/#!topicsearchin/php-fig/autoload/php-fig/Y4xc71Q3YEQ) 284 | - [Autoloader: looking again at namespace](https://groups.google.com/forum/#!topicsearchin/php-fig/autoload/php-fig/bnoiTxE8L28) 285 | - [DISCUSSION: Package-Oriented Autoloader - vote against](https://groups.google.com/forum/#!topicsearchin/php-fig/autoload/php-fig/SJTL1ec46II) 286 | - [VOTE: Package-Oriented Autoloader](https://groups.google.com/forum/#!topicsearchin/php-fig/autoload/php-fig/Ua46E344_Ls) 287 | - [Proposal: Package-Oriented Autoloader](https://groups.google.com/forum/#!topicsearchin/php-fig/autoload/php-fig/qT7mEy0RIuI) 288 | - [Towards a Package Oriented Autoloader](https://groups.google.com/forum/#!searchin/php-fig/package$20oriented$20autoloader/php-fig/JdR-g8ZxKa8/jJr80ard-ekJ) 289 | - [List of Alternative PSR-4 Proposals](https://groups.google.com/forum/#!topic/php-fig/oXr-2TU1lQY) 290 | - [Summary of [post-Acceptance Vote pull] PSR-4 discussions](https://groups.google.com/forum/#!searchin/php-fig/psr-4$20summary/php-fig/bSTwUX58NhE/YPcFgBjwvpEJ) 291 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | PHP编码规范(中文版)导读 2 | ==================================== 3 | 本文档是PHP互操作性框架制定小组([PHP-FIG][] :PHP Framework Interoperability Group)制定的PHP编码规范([PSR][]:Proposing a Standards Recommendation)中译版。 4 | 5 | 翻译过程中参照了 [莫希爾(Mosil)手札][] 的繁体中文版,以及 [Corrie Zhao][] 组织翻译的简体中文版, 6 | 译文中为了让语句通顺,便于理解,没有对原文逐字翻译,个别语句与原文原意可能略有偏差,希望告知指正。 7 | 8 | 目前官方已制定的规范包括以下六份文件: 9 | 10 | - [PSR-0](https://github.com/PizzaLiu/PHP-FIG/blob/master/PSR-0-cn.md) (已弃用) 11 | - [PSR-1](https://github.com/PizzaLiu/PHP-FIG/blob/master/PSR-1-basic-coding-standard-cn.md) 12 | - [PSR-2](https://github.com/PizzaLiu/PHP-FIG/blob/master/PSR-2-coding-style-guide-cn.md) 13 | - [PSR-2补充](https://github.com/PizzaLiu/PHP-FIG/blob/master/PSR-2-coding-style-guide-meta-cn.md) 14 | - [PSR-3](https://github.com/PizzaLiu/PHP-FIG/blob/master/PSR-3-logger-interface-cn.md) 15 | - [PSR-4](https://github.com/PizzaLiu/PHP-FIG/blob/master/PSR-4-autoloader-cn.md) 16 | 17 | 18 | 19 | - 2014/04/25 添加`PSR-2补充`文件以及修改之前版本中的翻译不当与错误。 20 | - 2014/07/31 添加`PSR-4`。 21 | 22 | [PHP-FIG]: https://github.com/php-fig/ 23 | [PSR]: https://github.com/php-fig/fig-standards 24 | [莫希爾(Mosil)手札]: https://github.com/mosil/fig-standards 25 | [Corrie Zhao]: https://github.com/hfcorriez/fig-standards 26 | 27 | 28 | 以下是原版的导读: 29 | 30 | --------------- 31 | 32 | PHP互操作性框架制定小组 33 | ==================================== 34 | 35 | 组建本小组的目的是,通过在各项目的代表之间讨论他们共同的编码规范,以制定一个协作标准。本规范的主要面向对象是本小组的各个组成成员,当然,同时也欢迎关注本规范的其它PHP社区采用本规范。 36 | 37 | 38 | 提交规范建议 39 | ------------------------------------ 40 | 41 | 可以通过以下方式给本规范提交建议: 42 | 43 | - fork [PSR代码库][],创建并检出一个分支,在 `proposed/` 下添加 规范建议,然后 push 分支到 Github,最后给我们发送一个 pull request;又或者 44 | 45 | - 在 Github 下新建一个讨论 ticket;又或者 46 | 47 | - 在 [邮件列表][] 中提交建议。 48 | 49 | [邮件列表]: http://groups.google.com/group/php-fig/ 50 | [PSR代码库]: https://github.com/php-fig/fig-standards 51 | 52 | 成为投票成员 53 | --------------------- 54 | 55 | 注意,你 **不需要** 成为投票成员才能在 [邮件列表][] 中发表言论。 56 | 57 | 想要成为投票成员,你必须发送一封邮件到 [邮件列表][] 中。 58 | 59 | - 邮件主题格式如下: `Membership Request: {你的名字} ({参与的项目名称})` 60 | 61 | - 邮件内容应包括你的名字、你参与的项目名称、项目的地址以及其它相关信息。 62 | 63 | 目前的成员会对你的加入请求进行投票。 64 | 65 | 请不要在一份申请中提交多个加入请求,每份申请只能提交一份请求。 66 | 67 | 68 | 目前的成员及其代表项目列表 69 | -------------- 70 | 71 | 1. Nate Abele: Lithium 72 | 73 | 1. Nils Adermann: phpBB 74 | 75 | 1. Brett Bieber: PEAR, PEAR2 76 | 77 | 1. Guilherme Blanco: Doctrine, Doctrine2, et al. 78 | 79 | 1. Jordi Boggiano: Composer, Packagist 80 | 81 | 1. Pádraic Brady: Zend Framework 82 | 83 | 1. Karma Dordrak: Zikula 84 | 85 | 1. Paul Dragoonis: PPI, PPI2 86 | 87 | 1. William Durand: Propel, Propel 2 88 | 89 | 1. Don Gilbert: Joomla 90 | 91 | 1. Cal Evans: the community at large 92 | 93 | 1. Larry Garfield: Drupal 94 | 95 | 1. Ivan Habunek: Apache log4php 96 | 97 | 1. Paul M. Jones: Solar Framework, Aura Project 98 | 99 | 1. Karsten Dambekalns: TYPO3 Flow, TYPO3 Neos 100 | 101 | 1. Larry Masters: CakePHP, CakePHP 2 102 | 103 | 1. John Mertic: SugarCRM 104 | 105 | 1. Taylor Otwell: Laravel 106 | 107 | 1. Ryan Parman: Amazon Web Services SDK 108 | 109 | 1. Evert Pot: SabreDAV 110 | 111 | 1. Fabien Potencier: Symfony, Symfony2 112 | 113 | 1. Mike van Riel: phpDocumentor 114 | 115 | 1. Andre Romcke: eZ Publish 116 | 117 | 1. Phil Sturgeon: PyroCMS 118 | 119 | 1. Lukas Smith: Jackalope 120 | 121 | 1. Kris Wallsmith: Assetic, Buzz 122 | 123 | 1. David Zülke: Agavi --------------------------------------------------------------------------------