Zend Framework编码规范

Zend Framework 中的 Php 编码标准 () - 文件格式

1. 对于只含有 php 代码的文件,我们将在文件结尾处忽略掉 "?>" 。这是为了防止多余的空格或者其它字符影响到代码。

实际上这个问题只有当你不开启压缩或缓存输出时才会出现 

// php.ini - 禁止压缩输出及缓存输出
zlib.output_compression = off
output_buffering = off

// foo.php - 注意这个时候有一些空格或换行符掉在了 "?>" 之后,当然这在页面上是看不到的

<?php
$foo = 'foo';
?>

// index.php - 在包含 foo.php 的同时,实际上我们已经输出了一些空格或换行了
<?php
include 'foo.php';
session_start();
?>


这时我们将看到一个警告 (warning) 说 "... Cannot send session cache limiter - headers already sent ..." 这是因为我们在 session_start() 之前输出了一些看不到的字符。


2. 由 __halt_compiler() 允许的任意的二进制代码的内容,被 Zend Framework 中的 PHP 文件或由它们产生的文件所禁止。

实际上这个规定是为了防止一些极个别的情况发生,例如上例中 :

// foo.php - 我们已经禁用了 "?>"

<?php
// 假如我们想通过 __halt_compiler() 输出某些东西
if (defined('__COMPILER_HALT_OFFSET__')) {
    $fp = fopen(__FILE__, 'r');
    fseek($fp, __COMPILER_HALT_OFFSET__);
    var_dump(stream_get_contents($fp));
}

// 在程序结束时
__halt_compiler();

则在执行 index.php 时我们依然会看到警告,而只要把 __halt_compiler() 注释掉就不会报错了。需要注意的是__halt_compiler() 实际上时语言结构,而非函数或方法。


3. 缩进由四个空格组成,禁止使用制表符 TAB 

这个主要是为了代码美观整齐。因为在不同的编辑器里, TAB 制表符的长度是不一样的,而空格则是一样的。实际上这已经成为编写代码的默认标准之一。 

例如 :


if ($x == 1) {
    $indented_code = 1;
    if ($new_line == 1) {
        $more_indented_code = 1;
    }
}

4. 变量赋值必须保持相等间距和排列。

例如 :

$variable1 = "demo"; 
$var2      = "demo2";

5. 每行代码长度应控制在80个字符以内,最长不超过120个字符。

因为 linux 读入文件一般以80列为单位,就是说如果一行代码超过80个字符,那么系统将为此付出额外操作指令。这个虽然看起来是小问题,但是对于追求完美的程序员来说也是值得注意并遵守的规范。

例如,下面是在 Zend/Navigation.php 中的一段代码 :

6. 每行结尾不允许有多余的空格。

这在很多 IDE 或者编辑器里都是可以设置的,例如在 save 保存操作执行时,顺便去掉多余的空格。

7. 行结束标志遵循 Unix 文本文件的约定,行必需以单个换行符 "/n" (LF) 结束。换行符在文件中表示为10,或16进制的 0x0A 。 不要使用苹果操作系统的回车 "/r" (0x0D) 或 Windows 系统的回车换行组合如 "/r/n" (0x0D,0x0A) 

这个规定没有贬低苹果机或者 Windows 的意思,而事实确实是,LAMP 还是主流,所以遵循其文件约定也是为了在 liunx 系统上表现更好的性能。

 

Zend Framework 中的 Php 编码标准 () - 命名约定


1. 类命名总是对应于其所属文件的目录结构。

这源于 PEAR 命名约定,能让人从类名就能联想到该类的存放位置。

例如 :
Zend_Acl_Role 就代表 Zend/Acl/Role.php 文件。 
  


require_once 'Zend/Acl/Role/Interface.php';
class Zend_Acl_Role implements Zend_Acl_Role_Interface
{
    ......
}

这是规定实际上提供了一种伪命名空间机制,这在 php5.3 和 php6 里面都将得到支持,到时候 Zend Framework可能会有一翻变革。

2. 类名只允许有字母和数字字符,在大部分情况下不鼓励使用数字。下划线只允许做路径分隔符。

这也源自 PEAR 命名约定,只不过 Zend Framework 在其基础上制定了更严格的规定。

例如 :
Zend_Db_Table 是允许的。
Zend_Db_Table2 则是不鼓励的。
Zend-Db-Table 是不允许的。

3. 当你为其他开发人员提供 API 接口的时候,如果他们需要用一个复合的名称来确认这个接口,那么你必须把这个名称用下滑线 (underline) 隔开,而不是使用驼峰的形式。而且最好是以常量 (contant) 的形式。

这个规定可能有点难懂,让我们举个例子吧。例如在实例化 Zend_Db_Adapter_xxx 实例时,我们通常需要将adapter 的名称作为参数传入到 Zend_Db::factory() 并由该工厂返回所需实例。

我们可以实例化 MySQL PDO 驱动 :

$db = Zend_Db::factory('PDO_MYSQL', $config);


也可以实例化 MsSQL PDO 驱动 :

$db = Zend_Db::factory('PDO_MSSQL', $config);

4. 如果类名包含多个单词,每个单词的第一个字母必须大写,连续的大写是不允许的。

例如 :
Zend_PDF 是不允许的。
Zend_Pdf 才是标准写法。


5. 有 Zend 及其合作伙伴开发的 Zend Framework 类的命名必须总是以 "Zend_" 作为开头,并放在 "Zend/" 目录下。

例如 :
Zend_Db 是由 Zend 开发的,它通常以 “Zend/Db.php” 的形式存放。
My_Db 则是用户自己定义或继承自 Zend_Db 的类,所以它不得以 "Zend_" 作为开头,而且通常以 "My/Db.php"的形式存放。


6. 接口类 (interface) 的定义必须遵循类名的定义规范,不同的是必须要以 _Interface 作为结尾。

例如 :
Zend_Controller_Dispatcher_Interface 对应的是 Zend/Controller/Dispatcher/Interface.php



7. 对于文件名,只有字母、数字字符、下划线和短横线 ("-") 可用,空格是绝对不允许的。

例如 :
Zend/Controller/Front.php 是标准写法。
My/Controller/Common-Action_2.php 也是允许的。
My/Controller/Common Action.php 则是禁止的。

8. 包含任何 PHP 代码的任何文件应当以 ".php" 扩展名结尾,视图脚本默认拓展名是 ".phtml",也可以用 ".html"等代替。

例如 :
Zend/Controller/Front.php 是标准 php 文件写法,index.phtml 是默认视图脚本名。

我相信很多人都见过以下的一些 php 的拓展名 :
.php4
.php5
.phpx
.class.php
.include.php
html (开玩笑?)

而在 Zend Framework 中你只会见到一种,那就是 ".php"


9. 函数名只允许由数字或字母组成,下划线是不允许的,首字母要小写,其后每个单词首字母要大写,即所谓的“camelCaps” 规则。

例如 :

filterInput()
getElementById()
widgetFactory()

等都是规范的写法。

而 :

FilterInput3()
getelementbyid()
widget_factory()

等都是不允许的。

10. 函数名越详细越好,应该能够描述清楚该函数的功能。

例如 :

getOne($id) // 描述的不清不楚。
getOneRecordById($id) // 则非常详细而清晰。

11. 对于对象成员的访问,我们必须始终使用 “get” 和 “set” 方法。

例如 :

class Foo
{
    protected $_testObj;

    public function getTestObj()
    {
        return $this->_testObj;
    }

    public function setTestObj($testObj)
    {
        $this->_testObj = $testObj;
    }
}

12. 当我们使用了某些设计模式的时候,我们的方法中应该含有该模式名。

例如 :

abstract class Zend_Cache
{
    // ......

    public static function factory($frontend, $backend,
        $frontendOptions = array(), $backendOptions = array(), 
        $customFrontendNaming = false, $customBackendNaming = false, 
        $autoload = false)
    {
        // ......
    }
}



13. 当类成员函数被声明为 private 或者 protected 时,函数必须以下划线 "_" 为开头,一般情况下的函数不含下划线。

例如 :

class Zend_Foo
{
    protected function _fooBar()
    {
        // ...
    }
}

14. 如果我们需要把一些经常使用的函数或方法定义为全局函数,那么应该把它们以静态 (static) 的形式定义在类中。

例如 :

class Zend_Debug
{
    // ......

    public static function dump($var, $label = null, $echo = true)
    {
        // ......
    }
}

15. 在类中被声明为 static 的函数或变量不应该再被声明为 private 私有,而应该为 protected 或者public ,如果只是不想被子类继承,则应该用 final 声明它们。

例如 :

class Foo
{
    final public static function fooFinally()
    {
    }
}

class Bar extends Foo
{
}

// This is wrong
Bar::fooFinally();

// Use Foo::fooFinally() instead
Foo::fooFinally();



16. 函数或方法的初始中括号应该在函数声明的下一行顶格。

例如 :

function Myfunction($parameter1)
{
}



17. 当函数参数不一定需要被赋值的时候,用 "null" 来代替 "false" 作为函数参数的默认值,除非该参数是boolean 值。

例如,考虑如下代码 :

public function foo($required, $optional = null)
{
    if (isset($optional)) {
        echo 'Echo something only when $optional is set and != null';
    }
}

public function foo($required, $optional = false)
{
    if (isset($optional)) {
        echo 'Always echo something';
    }
}

18. 变量只允许由字母组成,数字或下划线都是不允许的。

例如 :

$foo // 是正确的
$foo_foo // 是错误的
$foo2 // 也是错误的

19. 被声明为 private 或者 protected 的类成员属性必须由下划线 "_" 作为开头,这也是唯一一种允许变量中出现下划线的情况,而声明为 public 的成员属性则在任何时候都不允许含有下划线。

例如 :

class Zend_Foo
{
    private $_barPrivate;
    protected $_barProtected;
    public $barPublic;
}



20. 变量名必须像函数名那样,即首字母要小写,其后每个单词首字母要大写,即所谓的 “camelCaps” 规则。

例如 :

$compatibilityMode
$registryClassName

21. 建议用描述性的变量的命名,变量名越详细越好,以至于像 $i 或 $n 等等都是不鼓励使用的,特别是在超过20行的循环里面。

例如 Zend_Search_Lucene 中的一段代码 :

// read segmentInfos
for ($count = 0; $count < $segments; $count++) {
    $segName = $segmentsFile->readString();
    ......
}

22. 常量 constant 必须仅包括字母,数字和下划线,而且必须全部大写,各个单词之间用下划线分割。

例如 :

"MY_CONSTANT_ONE" // 是允许的
"MYCONSTANTTWO" // 是不允许的
"my_constant_two" // 也是不允许的

23. 常量应该在类中由 const 声明并定义,全局范围内的 define 是不鼓励使用的。

例如 :

class Zend_Acl
{
    const TYPE_ALLOW = 'TYPE_ALLOW';
    const TYPE_DENY  = 'TYPE_DENY';
    ......
}

24. 和 php 文档说明不一样的是,Zend Framework 中的 boolean 值和 null 值都是用小写的。

例如 Zend_Mail 中的一段代码 :

public function setMessageId($id = true)
{
    if ($id === null || $id === false) {
        return $this;
    } elseif ($id === true) {
        $id = $this->createMessageId();
    }
    ......
}

 

Zend Framework 中的 Php 编码标准 () - 编码风格

1. PHP 代码必须以完整的形式来定界,短定界符只能用在视图。

例如 :

<?php
// Php code here
?>
   
// index.phtml
<?= 'hello' ?>



2. 当一个字符串是纯文字组成的时候(即不含有变量),则必须总是以单引号(')或者撇号(`)作为定界符。

例如 : 

$a = 'Example String';
$b = `Excute Something`;

3. 当一个字符串含有撇号(`)的时候,我们允许使用双引号(")来定界字符串,特别是在些 SQL 语句的时候。

例如 :

$sql = "SELECT `id`, `name` from `people` WHERE `name`='Fred' OR `name`='Susan'";

4. 变量替换中的变量只允许用 $+变量名 的形式。

例如 :

$greeting = "Hello $name, welcome back!";   // 允许
$greeting = "Hello {$name}, welcome back!"; // 允许
$greeting = "Hello ${name}, welcome back!"; // 不允许



5. 多个字符串必须用点号 "." 来连接,且字符串与点号间必须用一个空格隔开。

例如 :

$company = 'Zend' . 'Technologies';

6. 当用点号 "." 连接各字符串的时候,我们允许把它分割成多行以增强可读性。在这种情况下,点号 "." 必须与等于号 "=" 对齐。

例如 :

$sql = "SELECT `id`, `name` FROM `people` "
     . "WHERE `name` = 'Susan' "
     . "ORDER BY `name` ASC ";

7. 任何负数都不允许作为数组的索引,数组索引必须以任何非负数作为开头,而且强烈建议以0作为默认开头。

例如 :

$sampleArray = array(-1 => -1, 0 => 0); // 错误
$sampleArray = array(0 => -1, 1 => 0);  // 正确
$sampleArray = array(1 => -1, 2 => 0);  // 正确

8. 当用 array 类型符号来构造数组的时候,必须在每个逗号之后加上一个空格来增强可读性。

例如 :

$sampleArray = array(1, 2, 3, 'Zend', 'Studio');

9. 多行的索引数组同样允许用 array 类型符号来构造,只是我们需要为每行的每个值加上必要的空格来保持其整齐美观。

例如 :

$sampleArray = array(1,        2,  3,  'Zend',
                     'Studio', $a, $b, $c,
                     56.44,    $d, 500);

10. 当使用 array 类型符声明关联数组的时候,我们鼓励把它分成多个行,只是我们必须同时保证每行的键与值的对齐,以保持美观。

例如 :

$sampleArray = array('firstKey'  => 'firstValue',
                     'secondKey' => 'secondValue');

11. 中括号的开始必须在类名的下一行顶格。

例如 :

class foo
{
    // 正确 {} 写法
}
class foo {
    // 错误 {} 写法
}

12. 类定义必须拥有符合 phpDocumentor 标准的注释块。

例如 :

/**
类定义注释
*/
class Zend_Class
{
}

13. 类中的所有代码都必须用4个空格来进行缩进。

例如 :

class Zend_Class
{
    $spaces = '4 spaces';
    if ($spaces == '4 spaces') {
        echo 'is permitted !';
    }
}
class Zend_Class
{
  $spaces = 'less then 4 spaces';
  if ($spaces != '4 spaces') {
    echo 'is not permitted !';
  }
}

14. 每个 php 文件只允许声明一个类。在类文件里面写其它代码是允许的,但并不鼓励这样做。假如真要附加代码的话,必须用空行来分隔。

例如 :

<?php
// 允许但并不鼓励这样做
class Zend_Class
{
    static $foo = 'foo';
}
echo Zend_Class::$foo;

<?php
/**
在同一文件里声明超过两个类是不允许的
*/
class Class_One
{
}
class Class_Two
{
}
?>

15. 任何类变量的声明都必须放在类顶部,先于任何函数的声明。

例如 :

// 正确
class right
{
    public $foo = '先于函数定义';
    public function fun()
    {
    }
}
// 错误
class wrong
{
    public function fun()
    {
    }
    public $foo = '后于函数定义';
}

16. 不允许用 var 符号来声明变量,类成员变量必须以 privateprotected 和 public 来声明。其次,把类成员声明为 public 而直接引用虽然是允许的,但通常更好的方法是使用 get 和 set 方法来访问类成员。

例如 :

class foo
{
    var $unpermitted = '这是不允许的!';
    private $privateVariable = '私有变量';
    protected $protectedVariable = '保护变量';
    public $publicVariable = '公共变量';
    public function setPrivateVariable($value)
    {
        $this->privateVariable = $value;
    }
    public function getPrivateVariable()
    (
        return $this->privateVariable;
    )
}
$foo = new foo();
// 不鼓励使用
echo $foo->publicVariable;
// 鼓励使用
echo $foo->getPrivateVariable();

17. 方法和函数必须总是用 privateprotected 或者 public 来声明其作用域。

例如 : 

class foo
{
    function goo()
    {
        // 不允许的
    }
    private function bar()
    {
        // 正确
    }
    protected function baz()
    {
        // 正确
    }
    public function zoo()
    {
        // 正确
    }
}

18. 按照 php 社区的习惯,静态 static 方法应该声明其作用域。

例如 :

class foo
{
    static function baz()
    {
        // 不允许的
    }
    public static function bar()
    {
        // 正确
    }
}

19. 对于类成员函数和方法,中括号的开始必须位于函数和方法名的下一行顶格。

例如 :

class foo
{
    public function braceIsUnderneath()
    {
        // 正确
    }
    public function braceIsNotUnderneath() {
        // 错误
    }
}

20. 在函数名与参数括号之间不允许出现多余的空格。

例如 :

class foo
{
    public function someSpacesAfterMe  ($a)
    {
        // 错误
    }
    public function noSpacesAfterMe($a)
    {
        // 正确
    }
}

21. 引用只允许定义在函数参数中,实时传递引用是禁止的。

例如 :

function defineRefInMethod(&$a)
{
    $a = 'a';
}
function callTimePassRef($a)
{
    $a = 'a';
}
$b = 'b';
$c = 'c';
// 允许的
defineRefInMethod($b);
echo $b; // 'a'
// 禁止的
callTimePassRef(&$c);
echo $c; // 'a'

22. 函数返回值不可以用括号包住,不然会降低可读性,而且假如以后函数修改为返回引用的话,这将会抛出一个异常。

例如 :

class foo
{
    public $bar = 'bar';
    public function goo()
    {
        return ($this->bar);
    }
    public function & zoo()
    {
        return ($this->bar);
    }
}
$foo = new foo();
// 看起来没问题
echo $foo->goo();
/**
程序会抛出一个 notice 说 :
* "Only variable references should be returned by reference"
*/
echo $foo->zoo();

23. 鼓励尽量使用类型提示,特别是在模块设计中。

例如 :

class Zend_Component
{
    public function foo(SomeInterface $object)
    {}

    public function bar(array $options)
    {}
}

24. 尽量避免同时使用异常处理和类型提示,来检验参数的有效性。

例如 :

class Not_Zend_Class
{
}
class foo
{
    public function bar(Zend_Class $zc)
    {
    }
    public function goo($zc)
    {
        if (!$zc instanceof Zend_Class) {
            throw new Exception('$zc 不是 Zend_Class 的实例');
        }
    }
}
$foo = new foo();
$zc  = new Not_Zend_Class();
/**
* Catchable fatal error 错误显示 :
* "Argument 1 passed to foo::bar() must be an instance of Zend_Class,
* instance of Not_Zend_Class given"
*/
$foo->bar($zc);
/**
错误信息 : '$zc 不是 Zend_Class 的实例'
*/
try {
    $foo->goo($zc);
} catch (Exception $e) {
    echo $e->getMessage();
}

25. 函数参数必须用 逗号+空格 来分隔。

例如 :

// 正确
threeArguments(1, 2, 3);
// 错误
threeArguments(1,2,3);

26. 对于参数为数组的函数,参数中的数组应该分成多行以增强可读性。

例如 :

threeArguments(array(1, 2, 3), 2, 3);
threeArguments(array(1,        2,  3,    'Zend',
                     'Studio', $a, $b,   $c,
                     56.44,    $d, 500), 2,      3);

27. 基于 “if”, "else" 和 "else if" 的条件控制里,我们必须用空格间隔开语句和括号。

例如 :

// 正确
if ($spaceOutSide) {
    // ...
} else if ($spaceOutSide) {
    // ...
} else {
    // ...
}
// 错误
if($noSpaceOutSide){
    // ...
}else if($noSpaceOutSide){
    // ...
}else{
    // ...
}

28. 在条件控制语句的条件括号内,必须用空格将操作符与其它元素隔开。如果遇到很长的逻辑判断,则鼓励用内嵌括号来分割各个逻辑。

例如 :

if (($a != 2) and ($b == 1)) {
    $a = $b;
}

29. 中括号的开始 "{" 必须与条件控制语句位于同一行,结束 "}" 必须总是独占一行且顶格,控制流程内容必须用4个空格进行缩进。

例如 : 

// 正确
if ($braceSameLine) {
    echo '很好 : 4空格缩进';
}
// 错误
if ($braceNotSameLine)
{
  echo '不好 : 2空格缩进';
}

30. 在某些场合,php 允许条件控制语句舍弃中括号 "{}" ,但是根据此编码规范,所有 "if", "else if" 或 "else" 语句都必须使用中括号 "{}" 定界内容。

例如 : 

// 用 "{}" 定界内容是正确的
if ($a != 2) {
    $a = 2;
} else if ($a == 3) {
    $a = 4;
} else {
    $a = 7;
}
// 没有用 "{}" 定界是错误的
if ($a != 2)
    $a = 2;
else if ($a == 3)
    $a = 4;
else
    $a = 7;

31. "elseif" 语句是不允许的,必须使用 "else if" 

例如 : 

if (true) {
    //
} else if {
    // 正确
}
if (true) {
    //
} elseif {
    // 错误
}

32. "switch" 条件控制语句中,必须用空格将待测参数与其它元素分隔开。

例如 : 

switch ($num) {
    // 正确
}
switch($num){
    // 错误
}

33. "switch" 语句的内容必须以4个空格缩进,"case" 条件控制的内容必须再加4个空格进行缩进。

例如 : 

switch ($indentedSpaces) {
  case 2:
    echo "错误";
    break;
    case 4:
        echo "正确";
        break;
    default:
        break;
}

34.在 "switch" 语句中应该总是包括 "default" 控制。

例如 :

switch ($isWithDefault) {
    case false:
        break;
    default:
        echo "有 'default' 控制是正确的";
        break;
}
switch ($isWithDefault) {
    case false:
        echo "没有 'default' 控制是错误的";
        break;
}

35. 有时候我们需要在 "case" 语境中省略掉 "break" 或 "return" ,这个时候我们必须为这些 "case" 语句加上 "// break intentionally omitted" 注释。

例如 : 

switch ($numPeople) {
    case 1: // break intentionally omitted
    case 2:
        break;
    default:
        break;
}

36. 关键词 "global" 是不允许使用的,请用 $GLOBAL[xxx] 替代。

例如 : 
[php]
$a = 'a';
function foo()
{
    // 错误
    global $a;
    $foo = $a;
    // 正确
    $foo = $GLOBALS['a'];
    return $foo;
}
echo foo();
[/php]

 

Zend Framework 中的 Php 编码标准 () - 内嵌文档

1. Docblocks start always with "/*" or "/**". The use of "#" is not allowed. The "//" is only allowed for comments within functions.

For example :

/**
* Class docblock
*/
class foo
{
    /* Variable docblock */
    public $foo;

    /**
     * Function docblock
     */
    public function __construct()
    {
        // Commentted hy '//' only allowed within function
        $this->foo = 'foo';
        # Commentted by '#' is not allowed within function
        $this->foo = 'bar';
    }
}



2. A docblock must contain a short description and minimum one parameter. Optionally a long description and multiple parameters can be added.

For example : 

/**
* One short description and one parameter at least
*
* @param
*/

/**
* Long description and multiple parameters below
*
* One empty line to seperate the
* SHORT_DESCRIPTION,
* LONG_DESCRIPTION,
* PARAMETERS
*
* @param
* @todo
*/



3. All docblock parts which are not keywords have to be under each other with the same indenting.

For example : 

/**
* Right
*
* @component All descriptive parts
* @uses      have the same indenting
*/

/**
* Wrong
*
* @component All descriptive parts
* @uses don't have the same indenting
*/



4. Also when describing parameters the keywords, parameters, and description have to have the same indenting to be under each other.

For example : 

/**
* Right, all descriptions are indented
*
* @param string  $value      Description of this value
* @param integer $othervalue Another description
*/

/**
* Wrong, not indenting
*
* @param string $value Description of this value
* @param integer $othervalue Another description
*/

5. Each file which is delivered with the Zend Framework must have the following header block : 

[php]
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category    Zend
* @package     __PACKAGENAME__
* @subpackage  __SUBPACKAGENAME__
* @copyright   Copyright (c) 2005-__ENDDATE__ Zend Technologies USA Inc. (http://www.zend.com)
* @license     http://framework.zend.com/license/new-bsd     New BSD License
* @version     $Id: $
* @depreciated Since 0.0.1
*/
[/php]

This format can be used in any project, for example : 

<?php
/**
* Project name
*
* LICENSE
*
* License information
* in multiple lines (maybe)
*
* @category    Category name
* @package     Package of this file
* @subpackage  Subpackage which include this file
* @copyright   Copyright information
* @license     License info for short
* @version     $ Id and version description $
* @depreciated Since xxx
*/



6. When other filestypes are used like *.SH, *.BAT, *.JS and so on, the header block must also be contained as header comment. Only when a filetype does not support comments like *.CSS the header block can be omited.

For example :
// zf.bat

REM Zend Framework
REM
REM LICENSE
REM
REM This source file is subject to the new BSD license that is bundled
REM with this package in the file LICENSE.txt.
REM It is also available through the world-wide-web at this URL:
REM http://framework.zend.com/license/new-bsd
REM If you did not receive a copy of the license and are unable to
REM obtain it through the world-wide-web, please send an email
REM to license@zend.com so we can send you a copy immediately.
REM
REM Zend
REM Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
REM http://framework.zend.com/license/new-bsd     New BSD License

// zf.sh

#############################################################################
# Zend Framework
#
# LICENSE
#
# This source file is subject to the new BSD license that is bundled
# with this package in the file LICENSE.txt.
# It is also available through the world-wide-web at this URL:
http://framework.zend.com/license/new-bsd
# If you did not receive a copy of the license and are unable to
# obtain it through the world-wide-web, please send an email
# to license@zend.com so we can send you a copy immediately.
#
# Zend
# Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
http://framework.zend.com/license/new-bsd     New BSD License
#############################################################################

// *.js
The same with php files.


7. The @package clause has to be the component which this file is part of it, there must exist exact one @package clause per header.

For example : 

/**
* ...
*
* @package    Zend_Controller
* @subpackage ...
* @copyright  ...
* @license    ...
*/
abstract class Zend_Controller_Router_Route_Abstract implements Zend_Controller_Router_Route_Interface
{
    // ...
}


Another example : 

/**
* ...
*
* @package    Zend_Db
* @subpackage ...
* @copyright  ...
* @license    ...
*/
class Zend_Db_Adapter_Mysqli extends Zend_Db_Adapter_Abstract
{
    // ...
}



8. The @subpackage clause has to be a logical separation within this component. Logical separations occur when there are several directories which seperate parts of the same component. Only files which are in the main directory of the framework which is "Zend" can omit the subpackage. There must exist maximum one @subpackage clause per header.

First example : 

/**
* @category   ...
* @package    ...
* @subpackage Adapter
* @copyright  ...
* @license    ...
*/
class Zend_Db_Adapter_Mysqli extends Zend_Db_Adapter_Abstract
{
    // ...
}


Second example : 

/**
* @category   ...
* @package    ...
* @subpackage Table
* @copyright  ...
* @license    ...
*/
class Zend_Db_Table_Select extends Zend_Db_Select
{
    // ...
}


Third example for no subpackage : 

/**
* @category   Zend
* @package    Zend_Auth
* @copyright  ...
* @license    ...
*/
class Zend_Auth
{
    // ...
}



9. The @copyright clause has to include the actual year of the release of the framework.

For example : 

/**
* @category   ...
* @package    ...
* @copyright  Copyright (c) 2005-2008 Zend ...
* @license    ...
*/
class Zend_Acl
{
    // ...
}

10. If this file contains a depreciated class it must have the optional @depreciated clause.

For example : 

<?php
/**
* ...
*
* @depreciated Since 1.1.1
*/
class depreciateMe
{
}

11. All classes/files which are required must contain a @see clause.

For example : 

/**
* @see Zend_Controller_Dispatcher_Interface
*/
require_once 'Zend/Controller/Dispatcher/Interface.php';

12. A class or interface in Zend Framework must have a class header which clauses must be added in the below seen order :

[php]
/**
* Description of the class
*
* More descriptive text which
* is allowed to span multiple lines
*
* @category    Zend
* @package     __PACKAGE__
* @subpackage  __SUBPACKAGE__
* @uses        __USES__
* @see         __SEE__
* @since       __SINCE__
* @copyright   Copyright (c) 2005-__ENDDATE__ Zend Technologies USA Inc. (http://www.zend.com)
* @license     http://framework.zend.com/license/new-bsd     New BSD License
* @depreciated Since 0.0.1
*/
class Zend_Controller_Dispatcher extends Zend_Controller_Dispatcher_Class implements Zend_Controller_Dispatcher_Interface
[/php]

13. The @uses clause in header has to contain the extended or implemented classname. When multiple classes or interfaces are used, you must include a @uses clause for every class or interface. When no class is extended or interface is implemented then the @uses clause must be ommitted.

For example : 

/**
* ...
*
* @uses       ArrayAccess
* @uses       Iterator
* @uses       Countable
* @package    ...
* @copyright  ...
* @license    ...
*/
class Zend_Dojo_Data implements ArrayAccess,Iterator,Countable
{
    // ...
}

14. The @see clause in header is optional and can be added to link to another component within the framework. You can add multiple clauses.

For example : 

/**
* ...
*
* @see        Zend_Parent
* @see        Zend_Interface
* @package    ...
* @copyright  ...
* @license    ...
*/
class Zend_Class extends Zend_Parent implements Zend_Interface
{
    // ...
}

15. The @since clause can be added optionally to include the version since which this class is available. It must include the complete version number of the framework. Only one since clause is allowed to be added.

For example : 

/**
* ...
*
* @category   ...
* @package    ...
* @copyright  ...
* @license    ...
* @since      Class available since Release 0.6.0
*
* @todo       ...
*/
class Zend_Console_Getopt
{
    // ...
}



16. Each function must have a function header.

For example : 

class Zend_Foo
{
    /**
     * Full text description of this function.
     * It described all possible things
     * but should not extend the line length of 100 characters.
     *
     * @param  boolean $value Value for checking
     * @since  Version 1.2.3
     * @see    Zend_Anything
     * @throws Zend_Exception When value is false
     * @return array
     */
    public function bar($value)
    {
        require_once('Zend/Anything.php');
        if ($value) {
            return array('foo' => $value);
        } else {
            throw new Zend_Exception('Throw me !');
        }
    }
}

17. All parameters of the function must be available. The types allowed are listed here :

(a) boolean
(b) integer
(c) string
(d) float
(e) array
(f) false
(g) true
(h) null
(i) Zend_Xxx (must be an existing class of the framework)

18. If more than one type could be used then the possible types have to be seperated with "|" like show above.

For example : 

/**
* @param array|null $config configurations
*/

19. If a parameter can be omitted the description must prepend a (optional) to the description.

For example : 

/**
* @param array|null $config (optional) My optional value
*/

20. If the function can throw an exception the @throws clause must be declared. Multiple exception types must be seperated with “|”. Also a description must be added why the exception is thrown.

For example : 

class Zend_XmlRpc_Server extends Zend_Server_Abstract
{
    /**
     * Handle an xmlrpc call (actual work)
     *
     * @param  Zend_XmlRpc_Request $request
     * @return Zend_XmlRpc_Response
     * @throws Zend_XmlRpcServer_Exception|Exception
     * Zend_XmlRpcServer_Exceptions are thrown for internal errors; otherwise,
     * any other exception may be thrown by the callback
     */
    protected function _handle(Zend_XmlRpc_Request $request)
    {
        // ...
    }
}

21. A @return clause must always be defined. Only for class constructor and destructor the @return clause must be ommitted. If multiple types can be returned the types must be seperated with "|". An description can be appended, but is not necessary.

For example : 

class Zend_Form implements Iterator, Countable, Zend_Validate_Interface
{
    /**
     * Overloading: access to elements, form groups, and display groups
     *
     * @param  string $name
     * @return Zend_Form_Element|Zend_Form|null
     */
    public function __get($name)
    {
        // ...
    }
}

22. If the class itself is returned (fluid interface) then the description ”Provides a fluent interface“ must be added.

For example : 

class Zend_Auth
{
    /**
     * Sets the persistent storage handler
     *
     * @param  Zend_Auth_Storage_Interface $storage
     * @return Zend_Auth Provides a fluent interface
     */
    public function setStorage(Zend_Auth_Storage_Interface $storage)
    {
        $this->_storage = $storage;
        return $this;
    }
}



23. If the function does not return any value then the return value must be set to "void".

For example : 

class Zend_Application
{
    /**
     * Run the application
     *
     * @return void
     */
    public function run()
    {
        $this->getBootstrap()->run();
    }
}

24. Keep in mind that the "void" and "null" are not the same. Null means that a empty variable is returned. But void means that nothing is returned. This is a small but important difference. Therefor when return is even not called, void has to be declared in the function docblock.

For example :

class Zend_Class
{
    /**
     * @return void
     */
    public function returnTheVoid()
    {
        // Return nothing
    }
    /**
     * @return null
     */
    public function returnTheNull()
    {
        return null;
    }
}

 

Zend Framework 中的 Php 编码标准 () - 错误与异常


1. Zend Framework 的代码应该不存在 E_STRICT 兼容问题。在开启错误报告 error_reporting 级别为 E_ALL | E_STRICT 时,Zend Framework 的代码不应该抛出任何警告(E_WARNING, E_USER_WARNING),任何通知(E_NOTICE, E_USER_NOTICE)以及任何兼容问题(E_STRICT)。

这就是说,Zend Framework 尽量避免代码写法上的错误。而如果真的发生程序中断,也只能是逻辑错误。

2. Zend Framework 不应该存在 Php 错误,如果我们不得不遇到错误的话,请用异常来处理。Zend Framework中有专门的异常类来为用户提供友好的异常处理。

例如 : 

class Zend_Exception extends Exception
{
}

class Zend_Db_Exception extends Zend_Exception
{
}

class Zend_Db
{
    public static function factory($adapter, $config = array())
    {
        // ...
        if (!is_array($config)) {
            /**
             * @see Zend_Db_Exception
             */
            require_once 'Zend/Db/Exception.php';
            throw new Zend_Db_Exception('Adapter parameters must be in'
                                      . 'an array or a Zend_Config object');
        }
    }
}

3. 在框架模块内的异常统一用 new 关键字构造是公认的良好习惯。

例如 : 

require_once 'Zend_Component_SpecificException.php';
class Zend_Component
{
    public function foo($condition)
    {
        if ($condition) {
            throw new Zend_Component_SpecificException(
                '一些友好的信息');
        }
    }
}

4. 异常必须延迟加载。

例如 : 

// 正确
if ($condition) {
    require_once 'Zend_Component_SpecificException.php';
    throw new Zend_Component_SpecificException(
        '一些友好信息');
} else {
    // ...
}

// 错误
require_once 'Zend_Component_SpecificException.php';
if ($condition) {
    throw new Zend_Component_SpecificException(
        '一些友好信息');
} else {
    // ...
}

5. 通俗地讲,如果用户希望 Zend Framework 模块做出一些超出其能力范围的工作时,那么抛出异常则是明智而正确的选择。相反,假如该模块能够处理用户的需求,但用户却给出各种意想不到的输入,这个时候,模块就不应该抛出异常,而应该正常运行下去。

例如 : 

if ($canNotPerformThisAction) {
    require_once 'Zend/Exception.php';
    throw new Zend_Exception('不能执行此动作 !');
}

$foo = 'bar';
if ($foo == 'foo') {
    echo '对的';
} else {
    // 没必要抛出异常
}

6. 避免抛出 Exception 基类异常,而应该尽量使用派生异常类,这可以让人清楚知道问题所在。

例如 : 

class Zend_Db
{
    public static function factory($adapter, $config = array())
    {
        if (!is_array($config)) {
            throw new Exception('我们根本不知问题发生在哪儿。');
        }
        if (!is_array($config)) {
            require_once 'Zend/Db/Exception.php';
            throw new Zend_Db_Exception("我们都知道问题出在 Zend_Db 这儿。");
        }
    }
}

7. 尽量避免去捕捉 Exception 基类异常。如果在 try 语句里面可能抛出多种异常的话,那么我们应该为各种异常准备各自独立的 catch 块,而不是仅用一个 catch 块去捕捉 Exception 基类异常。

例如 : 

// index.php
try {
    $app->run();
} catch (Zend_Db_Exception $e) {
    die('数据库异常 !');
} catch (Zend_Acl_Exception $e) {
    die('权限分配异常 !');
} catch (Zend_Auth_Exception $e) {
    die('身份认证异常 !');
} catch (Zend_Exception $e) {
    // 所有其它异常
}

8. 我们通常需要在类中通过拓展多个异常类来区分各种不同的情况。例如,我们需要创建两个异常类来区分 "参数错误和 "用户缺乏权限两种情况。

例如 : 

class Zend_Db_Exception extends Zend_Exception
{
    // 数据库异常基类
}

class Zend_Db_Select_Exception extends Zend_Db_Exception
{
    // 用于处理 select 类异常
}

class Zend_Db_Table_Exception extends Zend_Db_Exception
{
    // 用于处理数据库表的异常
}

9. 不要把所有诊断信息都放在异常的 message 里,我们可以在任何需要的时候创建自己的异常类的成员和方法,来为 catch 语句提供帮助。我们需要做的就是在 constructor 构建异常类时,传入正确的参数信息。

例如 : 

class Zend_Exception extends Exception
{
}

class My_Exception extends Zend_Exception
{
    private $_importantDiagnostic;
    public function setImportantDiagnostic($value)
    {
        $this->_importantDiagnostic = $value;
    }
    public function getImportantDiagnostic()
    {
        return $this->_importantDiagnostic;
    }
    public function __construct($message = null, $code = 0, $value)
    {
        parent::__construct($message, $code);
        $this->setImportantDiagnostic($value);
    }
}

try {
    if ($isMyFault) {
        throw new My_Exception('没有信息', 0, '信息在这儿');
    }
} catch (My_Exception $e) {
    echo $e->getImportantDiagnostic();
}

10. 在错误发生的时候,程序不应该保持沉默,甚至对异常置之不理。而是应该要么修正它,要么抛出新的异常来代替它。

例如 : 

try {
} catch (My_Exception $e) {
    tryToCorrectIt($e);
} catch (My_Exception $e) {
    throw new My_Exception($e->getMessage(), '110');
} catch (My_Exception $e) {
    // 不作为是愚蠢的行为!
}

11. 我们应该为我们程序的不同层面准备不同的异常处理。例如,我们不应该把数据逻辑层的错误(即俗称SQLException)搬到业务逻辑层。

例如 : 

class My_Dao_User_Exception extends Zend_Db_Table_Exception
{
    // 数据层 User 异常类
}

class My_Dao_User extends Zend_Db_Table_Abstract
{
    // 数据层 User 对象
}

class My_Bis_User_Exception extends Zend_Exception
{
    // 业务层 User 异常类
}

/**
业务层 User 对象
*/
class My_Bis_User
{
    private $_daoUser = null;

    public function setDaoUser($user)
    {
        $this->_daoUser = $user;
    }

    public function getDaoUser()
    {
        return $this->_daoUser;
    }

    public function throwSomething()
    {
        try {
            if ($wrong) {
                throw new My_Dao_User_Exception('你不应该把数据层的异常搬到这里!');
            } else if ($right) {
                throw new My_Bis_User_Exception('这才是正确的。');
            }
        } catch (Zend_Exception $e) {
            // ...
        }
    }
}

12. 不要把异常处理机制当成控制流程,或者仅仅是返回某些值。

例如 : 

function itIsWrong()
{
    try {
        // 做些小动作
    } catch (Exception_One $e) {
        doSomething($e);
    } catch (Exception_Two $e) {
        doSomething($e);
    } catch (Exception_Three $e) {
        return true;
    }
}

function isRight()
{
    try {
        // 做些小动作
    } catch (Exception_One $e) {
        correctIt($e);
    } catch (Exception_Two $e) {
        correctIt($e);
    } catch (Exception_Three $e) {
        // 从不 return;
        throw new Exception('我们抛出它,而不是返回什么东西!');
    }
}

13. 在用 catch 语句块处理异常的时候,我们应该首先释放多余的内存资源,如数据库连接,网络资源连接等。Php 并不提供类似 finally 之类的语句来进行垃圾处理。

例如 : 

try {
    $db = getDbConnection();
    throw new Exception('发生了错误。');
} catch (Exception $e) {
    unset($db);
    handleExceptionAndGoOn($e);
}

14. 当然,其它语言的关于异常处理的规范也是可以借鉴的。当中有很多东西都是相通而不存在语言界限的。

 

PHP 注释文档标记

文档标记的使用范围是指该标记可以用来修饰的关键字,或其他文档标记。
所有的文档标记都是在每一行的 后面以@开头。如果在一段话的中间出来@的标记,这个标记将会被当做普通内容而被忽略掉。
@access
使用范围:class,function,var,define,module
该标记用于指明关键字的存取权限:privatepublicproteced
@author
指明作者
@copyright
使用范围:classfunctionvardefinemoduleuse
指明版权信息
@deprecated
使用范围:classfunctionvardefinemoduleconstentglobalinclude
指明不用或者废弃的关键字
@example
该标记用于解析一段文件内容,并将他们高亮显示。Phpdoc会试图从该标记给的文件路径中读取文件内容
@const
使用范围:define
用来指明phpdefine的常量
@final
使用范围:class,function,var
指明关键字是一个最终的类、方法、属性,禁止派生、修改。
@filesource
example类似,只不过该标记将直接读取当前解析的php文件的内容并显示。
@global
指明在此函数中引用的全局变量
@ingore
用于在文档中忽略指定的关键字
@license
相当于html标签中的,首先是URL,接着是要显示的内容
例如[url=http://bbs.phpchina.com/”http://www.baidu.com”]百度[/url]
可以写作 @license http://www.baidu.com 百度
@link
类似于license
但还可以通过link指到文档中的任何一个关键字
@name
为关键字指定一个别名。
@package
使用范围:页面级别的-> definefunctioninclude
类级别的->classvarmethods
用于逻辑上将一个或几个关键字分到一组。
@abstrcut
说明当前类是一个抽象类
@param
指明一个函数的参数
@return
指明一个方法或函数的返回指
@static
指明关建字是静态的。
@var
指明变量类型
@version
指明版本信息
@todo
指明应该改进或没有实现的地方
@throws
指明此函数可能抛出的错误异常,极其发生的情况
上面提到过,普通的文档标记标记必须在每行的开头以@标记,除此之外,还有一种标记叫做inline tag,{@}表示,具体包括以下几种:
{@link}
用法同@link
{@source}
显示一段函数或方法的内容

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值