PHP社区百花齐放,拥有大量的函数库、框架和组件。PHP开发者通常会在自己的项目中使用若干个外部库,因而PHP代码遵循或尽量接近同一个代码风格就非常重要,可以让开发者方便地把多个代码库集成在自己的项目中。
框架互操作组(即PHP标准组)发布了一系列代码风格推荐标准,即PSR-0,PSR-1,PSR-2和PSR-3。 不要让这些名称所混淆,这些推荐仅是一些被其它项目所遵循的规则,如Drupal, Zend, Symfony, CakePHP, phpBB, AWS SDK, FuelPHP, Lithium等,你可以把这些规则用在自己的项目中,或者继续使用你自己的风格。
通常情况下,你的PHP代码应该遵循其中一项或多项标准,从而其他开发者可以方便地阅读和使用你的代码。这些标准都是在前一个标准 上附加新的规则,所以使用PSR-1就同时要求遵循PSR-0,但可以不遵循PSR-2。
可以使用PHP_CodeSniffer来检查代码是否符合这些标准,文本编辑器插件Sublime Text 2还能提供实时检查。如果不符合规范,可以使用Fabien Potencier提供的工具PHP Coding Standards Fixer自动修复,不用自己手工修复。
PSR完整地址为:https://github.com/php-fig/fig-standards
PSR-0主要是对namespace和class命名规范进行约束,这个规范主要作用是使得autoloader函数能够根据完整的类名从硬盘中自动加载指定的类文件,其中涉及到的“强制”要求有以下几点:
如果符合了上述要求,那么autoload代码就如下:
<?php function autoload($className) { $className = ltrim($className, '\\'); $fileName = ''; $namespace = ''; if ($lastNsPos = strrpos($className, '\\')) { $namespace = substr($className, 0, $lastNsPos); $className = substr($className, $lastNsPos + 1); $fileName = str_replace('\\', DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR; } $fileName .= str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php'; require $fileName; }
\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 \namespace\package\Class_Name => /path/to/project/lib/vendor/namespace/package/Class/Name.php \namespace\package_name\Class_Name => /path/to/project/lib/vendor/namespace/package_name/Class/Name.php
原文中的 "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" 等关键字含义请参与RFC 2119文档。并且本文中不会对这些关键字进行翻译。
<?php namespace Vendor\Package; use FooClass; use BarClass as Bar; use OtherVendor\OtherPackage\BazClass; // ... additional PHP code ...
<?php namespace Vendor\Package; use FooClass; use BarClass as Bar; use OtherVendor\OtherPackage\BazClass; class ClassName extends ParentClass implements \ArrayAccess, \Countable, \Serializable { // constants, properties, methods }
<?php namespace Vendor\Package; class ClassName { public function foo($arg1, &$arg2, $arg3 = []) { // method body } public function aVeryLongMethodName( ClassTypeHint $arg1, &$arg2, array $arg3 = [] ) { // method body } }
<?php bar(); $foo->bar($arg1); Foo::bar($arg2, $arg3); $foo->bar( $longArgument, $longerArgument, $muchLongerArgument );
<?php if ($expr1) { // if body } elseif ($expr2) { // elseif body } else { // else body; }
<?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; }
<?php while ($expr) { // structure body } do { // structure body; } while ($expr);
<?php for ($i = 0; $i < 10; $i++) { // for body }
foreach ($iterable as $key => $value) { // foreach body }
<?php try { // try body } catch (FirstExceptionType $e) { // catch body } catch (OtherExceptionType $e) { // catch body }
<?php $closureWithArgs = function ($arg1, $arg2) { // body }; $closureWithArgsAndVars = function ($arg1, $arg2) use ($var1, $var2) { // body }; $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 };