一、目标
统一代码风格、命名规范,增强代码可读性和可维护性,供日常开发工作中时参考,以提高团队协作的开发效率。
二、编程规约
PHP代码规范[PSR-12]
特别注意:
1、业务代码内对
常量、变量(分页值、版本号、向下参数等)、魔法值、布尔类型开关等 统一走配置文件,配置文件对应各环境的 /common/enums.php 文件内(按业务功能对应目录进行区分)。
2、新增加配置做好对应的注视说明
2.1 总则
2.1.1 基本编码标准
代码必须遵循 [PSR-1] 中列出的所有规则。
PSR-1 中的术语 ‘StudlyCaps’ 必须解释为 PascalCase (帕斯卡命名法:大驼峰式命名法),其中每个单词的第一个字母大写,包括第一个字母。
2.1.2 文件
所有 PHP 文件 只能 使用 Unix LF (换行符) 结尾。
所有的 PHP 文件都 必须 以非空行结尾,以一个 LF 结尾。
在仅包含 PHP 代码的文件中,必须省略结尾的 ?> 标记。
PHP 源文件 必须 是不带 BOM 的 UTF-8 编码的文件。
BOM(Byte Order Mark),字节顺序标记,出现在文本文件头部,Unicode 编码标准中用于标识文件是采用哪种格式的编码。
2.1.3 代码行
行长度不得有硬限制。
行长度的软限制必须为 120 个字符。
行的长度不应超过 80 个字符;超过该长度的行应拆分为多个后续行,每个行的长度不应超过 80 个字符。
行尾不能有尾随空格。
可以添加空行以提高可读性并指示相关的代码块,除非明确禁止。
每行不能有多个语句。
2.1.4 缩进
代码 必须 为每个缩进级别使用 4 个空格的缩进,并且 不能 使用缩进标签。
2.1.5 关键词和类型
PHP 的所有关键字和类型 [1]、[2] 都必须使用小写。
PHP 未来版本中新加的所有关键字和类型也都必须使用小写。
类型关键字必须使用缩写。使用 bool 而不是 boolean,使用 int 而不是 integer 等等。
// 关键字
__halt_compiler()、abstract、and、array()、as、break、callable、case、catch、class、clone、const、continue、declare、default、die()、do、echo、else、elseif、empty()、enddeclare、endfor、endforeach、endif、endswitch、endwhile、eval()、exit()、extends、final、finally、fn (as of PHP 7.4)、for、foreach、function、global、goto、if、implements、include、include_once、instanceof、insteadof、interface、isset()、list()、match (as of PHP 8.0)、namespace、new、or、print、private、protected、public、readonly (as of PHP 8.1.0)*、require、require_once、return、static、switch、throw、trait、try、unset()、use、var、while、xor、yield
// 保留字
int、float、bool、string、true、false、null、void (as of PHP 7.1)、iterable (as of PHP 7.1)、object (as of PHP 7.2)、mixed (as of PHP 8.0)、never (as of PHP 8.1)
enum、resource、numeric
2.2 声明、命名空间以及导入
一个 PHP 文件的头部可能会包含多个块。如果包含多个块,则每个块都必须用空白行和其他块分隔,并且块内不能包含空白行。所有的块都必须按照下面的顺序排列,如果不存在该块则忽略。
- PHP 文件开始标签: <?php
- 文件级文档块。
- 一个或多个声明语句。
- 命名空间声明语句。
- 一个或多个基于类的 use 声明语句。
- 一个或多个基于方法的 use 声明语句。
- 一个或多个基于常量的 use 声明语句。
- 其余代码。
当文件包含 HTML 和 PHP 的混合代码时,可以使用上面列出的任何部分。如果是这种情况的话,即时代码的其他部分包含有 PHP 结束符,然后再包含 HTML 和 PHP 代码,声明、命名空间和导入语句块也必须放在文件的顶部。
什么时候开始 <?php 标签位于文件的第一行,它必须位于自己的行,没有其他语句,除非它是一个包含 PHP 之外的标记的文件打开和关闭标记。
import 语句不能以前导反斜杠开头,因为它们必须始终完全合格。
以下示例演示了所有块的完整列表:
<?php
/**
* This file contains an example of coding styles.
*/
declare(strict_types=1);
namespace Vendor\Package;
use Vendor\Package\{ClassA as A, ClassB, ClassC as C};
use Vendor\Package\SomeNamespace\ClassD as D;
use Vendor\Package\AnotherNamespace\ClassE as E;
use function Vendor\Package\{functionA, functionB, functionC};
use function Another\Vendor\functionD;
use const Vendor\Package\{CONSTANT_A, CONSTANT_B, CONSTANT_C};
use const Another\Vendor\CONSTANT_D;
/**
* FooBar is an example class.
*/
class FooBar
{
// ... 其他php代码 ...
}
深度不能超过两层的复合名称空间,因此以下展示了允许的最大复合深度。
<?php
use Vendor\Package\SomeNamespace\{
SubnamespaceOne\ClassA,
SubnamespaceOne\ClassB,
SubnamespaceTwo\ClassY,
ClassZ,
};
并且不允许以下内容:
<?php
use Vendor\Package\SomeNamespace\{
SubnamespaceOne\AnotherNamespace\ClassA,
SubnamespaceOne\ClassB,
ClassZ,
};
当希望在 PHP 外部包含标记的文件中声明严格类型时打开和关闭标签,声明 必须 写在文件的第一行并且包含在一个开始的 PHP 标签,以及严格的类型声明和结束标签。
例如:
<?php declare(strict_types=1) ?>
<html>
<body>
<?php
// ... 其他 PHP 代码 ...
?>
</body>
</html>
声明语句 不能 包含空格,并且 必须 完全是 declare(strict_types=1) (带有可选的分号终止符)。
允许使用块声明语句,并且 必须 按照以下的格式设置。注意的位置括号和间距:
declare(ticks=1) {
// 一些代码
}
2.3 类,属性,和方法
这里的『类』指的是所有类,接口,以及 trait 。
任何注释和语句 不得 跟在其右花括号后的同一行。
当实例化一个类时,后面的圆括号 必须 写出来,即使没有参数传进其构造函数。
new Foo();
2.4 继承和实现
关键字 继承 和 实现 必须 在类名的同一行声明。
类的左花括号 必须 另起一行;右花括号 必须 跟在类主体的下一行。
类的左花括号 必须 独自成行,且 不得 在其上一行或下一行存在空行。
右花括号 必须 独自成行,且 不得 在其上一行存在空行。
<?php
namespace Vendor\Package;
use FooClass;
use BarClass as Bar;
use OtherVendor\OtherPackage\BazClass;
class ClassName extends ParentClass implements \ArrayAccess, \Countable
{
// 常量,属性,方法
}
如果有接口, 实现 接口和 继承父类 可以 分为多行,前者每行需缩进一次。当这么做时,第一个接口 必须 写在下一行,且每行 必须 只能写一个接口。
<?php
namespace Vendor\Package;
use FooClass;
use BarClass as Bar;
use OtherVendor\OtherPackage\BazClass;
class ClassName extends ParentClass implements
\ArrayAccess,
\Countable,
\Serializable
{
// 常量,属性,方法
}
2.4.2 使用 trait
在类里面用于实现 trait 的关键字 use必须 在左花括号的下一行声明。
<?php
namespace Vendor\Package;
use Vendor\Package\FirstTrait;
class ClassName
{
use FirstTrait;
}
每个导入类的 trait必须 每行一个包含声明,且每个包含声明 必须 有其 use 导入语句。
<?php
namespace Vendor\Package;
use Vendor\Package\FirstTrait;
use Vendor\Package\SecondTrait;
use Vendor\Package\ThirdTrait;
class ClassName
{
use FirstTrait;
use SecondTrait;
use ThirdTrait;
}
在类文件中,如果在使用’useTrait’之后没有其他内容了 ,类名右大括号必须另起一行。
<?php
namespace Vendor\Package;
use Vendor\Package\FirstTrait;
class ClassName
{
use FirstTrait;
}
如有其他内容,两者之间需空一行。
<?php
namespace Vendor\Package;
use Vendor\Package\FirstTrait;
class ClassName
{
use FirstTrait;
private $property;
}
当使用’ insteadof ‘和’ as ‘运算符时,它们必须如图所示使用,注意缩进、间距和另起一行。
<?php
class Talker
{
use A, B, C {
B::smallTalk insteadof A;
A::bigTalk insteadof C;
C::mediumTalk as FooBar;
}
}
2.4.3 属性和常量
所有属性 必须 声明可见性。
如果你的项目 PHP 最小版本支持常量可见性( PHP 7.1 或以上),所有常量 必须 声明可见性。
关键字 var不得 用于声明属性。
每条声明语句 不得 声明多于一个属性。
属性名 不得 用单个下划线开头表明其受保护的或私有的可见性。也就是说,一个下划线开头显然是没有意义的。
类型声明和属性名之间 必须 有一个空格。
一个属性声明看上去如下所示:
<?php
namespace Vendor\Package;
class ClassName
{
public $foo = null;
public static int $bar = 0;
}
2.4.4 方法和函数
所有的方法 必须 事先声明类型。
方法命名 一定不可 用单个下划线来区分是 protected 或 private 类型。也就是说,不要用一个没有意义的下划线开头。
方法和函数名称中,方法命名后面 一定不可 使用空格。方法开始的花括号 必须 写在方法声明后自成一行, 结束花括号也 必须 写在方法后面自成一行。开始左括号后和结束右括号前,都 一定不可 有空格符。
一个方法的声明应该如下所示。注意括号,逗号,空格和花括号的位置:
<?php
namespace Vendor\Package;
class ClassName
{
public function fooBarBaz($arg1, &$arg2, $arg3 = [])
{
// 方法主体
}
}
一个函数的声明应该如下所示。注意括号,逗号,空格和花括号的位置:
<?php
function fooBarBaz($arg1, &$arg2, $arg3 = [])
{
// 函数主体
}
2.4.5 方法和函数参数
在参数列表中, 不得 在每个逗号前存在空格,且 必须 在每个逗号后有一个空格。
方法和函数中带有默认值的参数 必须 放在参数列表的最后。
<?php
namespace Vendor\Package;
class ClassName
{
public function foo(int $arg1, &$arg2, $arg3 = [])
{
// 方法主体
}
}
参数列表 可以 分为多行,每行参数缩进一次。当这么做时,第一个参数 必须 放在下一行,且每行 必须 只能有一个参数。
当参数列表分成多行时,右圆括号和左花括号 必须 放在同一行且单独成行,两者之间存在一个空格。
<?php
namespace Vendor\Package;
class ClassName
{
public function aVeryLongMethodName(
ClassTypeHint $arg1,
&$arg2,
array $arg3 = []
) {
// 方法主体
}
}
当你定义一个返回值类型声明时,冒号后面的类型声明 必须 用空格符隔开。冒号和声明 必须 在同一行,且跟参数列表后的结束括号之间没有空格。
<?php
declare(strict_types=1);
namespace Vendor\Package;
class ReturnTypeVariations
{
public function functionName(int $arg1, $arg2): string
{
return 'foo';
}
public function anotherFunction(
string $foo,
string $bar,
int $baz
): string {
return 'foo';
}
}
在可空类型声明中,问号和类型声明之间 不能 有空格。
<?php
declare(strict_types=1);
namespace Vendor\Package;
class ReturnTypeVariations
{
public function functionName(?string $arg1, ?int &$arg2): ?string
{
return 'foo';
}
}
当在参数之前使用引用运算符 & 时,引用运算符之后 不能 有空格,例如上面的示例。
可变参数声明的三个点和参数名称之间 不能 有空格:
public function process(string $algorithm, ...$parts)
{
// 函数体
}
当同时使用引用运算符和可变参数运算符时,它们之间 不能 有任何空格:
public function process(string $algorithm, &...$parts)
{
// 函数体
}
2.4.6 abstract, final, and static
如果是 abstract and final ,那么申明的时候 必须 是可见性声明。
如果是 static ,声明 必须 位于可见性声明之后。
<?php
namespace Vendor\Package;
abstract class ClassName
{
protected static $foo;
abstract protected function zim();
final public static function bar()
{
// 请求体
}
}
2.4.7 方法和函数的调用
当我们在进行方法或者函数调用的时候,方法名或函数名与左括号之间 不能 出现空格,在右括号之后也 不能 出现空格,并且在右括号之前也 不能 有空格。在参数列表中,每个逗号前面不能有空格,每个逗号后面 必须 有一个空格。
<?php
bar();
$foo->bar($arg1);
Foo::bar($arg2, $arg3);
参数列表可以分为多行,每行后面缩进一次。这样做时,列表中的第一项必须位于下一行,并且每一行必须只有一个参数。跨多个行拆分单个参数 (就像匿名函数或者数组那样) 并不构成拆分参数列表本身。
<?php
$foo->bar(
$longArgument,
$longerArgument,
$muchLongerArgument
);
<?php
somefunction($foo, $bar, [
// ...
], $baz);
$app->get('/hello/{name}', function ($name) use ($app) {
return 'Hello ' . $app->escape($name);
});
2.5 流程控制
如下是主要的流程控制风格规则:
- 流程控制关键词之后 必须 要有一个空格
- 左括号后面 不能 有空格
- 右括号前面 不能 有空格
- 右括号与左大括号之间 必须 要有一个空格
- 流程主体 必须 要缩进一次
- 流程主体 必须 在左大括号之后另起一行
- 右大括号 必须 在流程主体之后另起一行
每个流程控制主体 必须 以封闭的括号结束。这将标准化流程结构,同时减少由于流程中添加新的内容而引入错误的可能性。
2.5.1 if, elseif, else
if 结构如下。注意括号,空格,和大括号的位置;else 和 elseif 都在同一行,和右大括号一样在主体的前面。
<?php
if ($expr1) {
// if body
} elseif ($expr2) {
// elseif body
} else {
// else body;
}
应该 使用关键词 elseif 替换 else if,这样所有的控制关键词看起来都像单个词。
括号中的表达式 可能 会被分开为多行,每一行至少缩进一次。如果这样做,第一个条件 必须 在新的一行。右括号和左大括号 必须 在同一行,而且中间有一个空格。条件中间的布尔控制符 必须 在每一行的开头或者结尾,而不是混在一起。
<?php
if (
$expr1
&& $expr2
) {
// if body
} elseif (
$expr3
&& $expr4
) {
// elseif body
}
2.5.2 switch, case
switch 结构如下。注意括号,空格和大括号的位置。case必须 缩进一次从 switch 开始, break 关键词 (或者其他终止关键词) 必须 缩进和 case 主体保持一致。必须 要有一个像 // no break 这样的注释在不为空且不需要中断的 case 主体之中。
<?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
switch (
$expr1
&& $expr2
) {
// structure body
}
2.5.3 while, do while
while 结构如下。注意括号,空格和大括号的位置。
<?php
while ($expr) {
// structure body
}
括号中的表达式 可能 会被分开多行,每一行至少要缩进一次。如果这样做,第一个条件 必须 在新的一行。右括号和左大括号 必须 在同一行,而且中间有一个空格。条件中间的布尔控制符 必须 在每一行的开头或者结尾,而不是混在一起。
<?php
while (
$expr1
&& $expr2
) {
// structure body
}
同样的, do while 申明如下。注意括号,空格和大括号的位置。
<?php
do {
// structure body;
} while ($expr);
括号中的表达式 可能 会被分开多行,每一行至少要缩进一次。如果这样做,第一个条件 必须 在新的一行。条件中间的布尔控制符 必须 在每一行的开头或者结尾,而不是混在一起。
<?php
do {
// structure body;
} while (
$expr1
&& $expr2
);
2.5.4 for
for 申明如下。注意括号,空格和大括号的位置。
<?php
for ($i = 0; $i < 10; $i++) {
// for body
}
括号中的表达式 可能 会被分开多行,每一行至少要缩进一次。如果这样做,第一个条件 必须 在新的一行。右括号和左大括号 必须 在同一行,而且中间有一个空格。
<?php
for (
$i = 0;
$i < 10;
$i++
) {
// for body
}
2.5.5 foreach
foreach 语句的写法如下所示。请注意它的圆括号、空格和花括号。
<?php
foreach ($iterable as $key => $value) {
// 迭代主体
}
2.5.6 try , catch , finally
一个 try-catch-finally 模块包含下面这些内容。请注意它的圆括号、空格和花括号。
<?php
try {
// try 主体
} catch (FirstThrowableType $e) {
// 捕获异常主体
} catch (OtherThrowableType | AnotherThrowableType $e) {
// 捕获异常主体
} finally {
// finally 主体
}
2.6 运算符
运算符的样式规则按元数分组(其接受的操作数个数)。
当运算符周围允许出现空格时, 可以 出于可读性目的打多个空格。
所有这里没描述的运算符暂不作限定。
2.6.1. 一元运算符
递增 / 递减运算符和操作数之间 不得 有任何空格。
$i++;
++$j;
类型转换运算符的圆括号内部 不得 有任何空格:
$intValue = (int) $input;
2.6.2. 二元运算符
所有二进制 算术,比较,赋值,按位,逻辑、字符串和类型运算符 必须 在前后跟至少一个空格:
if ($a === $b) {
$foo = $bar ?? $a ?? $b;
} elseif ($a > $b) {
$foo = $a + $b * $c;
}
2.6.3. 三元运算符
条件运算符,也称为三元运算符,必须 在 ? 和 : 这两个字符之间:
$variable = $foo ? 'foo' : 'bar';
如果省略条件运算符的中间操作数,运算符 必须 遵循与其他二进制比较运算符相同的样式规则:
$variable = $foo ?: 'bar';
2.7 闭包(Closures)
闭包声明时 必须 在 function 关键字后留有 1 个空格,并且在 use 关键字前后各留有 1 个空格。
左花括号必须跟随前文写在同一行,右花括号 必须 在函数体后换行放置。
不能 在参数和变量的左括号后和右括号前放置空格。
不能 在参数和变量的逗号前放置空格,但必须在逗号后放置 1 个空格。
闭包参数如果有默认值,该参数 必须 放在参数列表末尾。
如果声明了返回类型,它必须遵循普通函数和方法相同的规则;如果使用 use 关键字,冒号 必须 在 use 右括号后且冒号前后不能有空格。
闭包的声明方式如下,留意括号,逗号,空格和花括号:
<?php
$closureWithArgs = function ($arg1, $arg2) {
// 函数体
};
$closureWithArgsAndVars = function ($arg1, $arg2) use ($var1, $var2) {
// 函数体
};
$closureWithArgsVarsAndReturn = function ($arg1, $arg2) use ($var1, $var2): bool {
// 函数体
};
参数和变量可以分多行放置,每个后续行缩进一次。执行此操作时,列表中的第一项 必须 放在下一行,并且每行只能有一个参数或变量。
结束多行列表(或者参数,变量)的时候,右括号和左大括号 必须 要放在一行,而且中间有一个空格。
下面是有和没有多行参数列表与变量列表的闭包示例。
<?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
);
2.8 匿名类
匿名类 必须 遵循上面章节中和闭包一样的方针和准则。
<?php
$instance = new class {};
只要 implements 接口列表不换行,左花括号 可以 和关键字 class 在同一行。如果接口列表换行,花括号 必须 放在最后一个接口的下一行。
<?php
// 花括号在同一行
$instance = new class extends \Foo implements \HandleableInterface {
// 类内容
};
// 花括号在下一行
$instance = new class extends \Foo implements
\ArrayAccess,
\Countable,
\Serializable
{
// 类内容
};
2.9 其他
2.9.1 类的命名必须遵循首字母大写
首字母大写,否则YII2框架的url,会出现 -
2.9.2 方法参数注释
/**
* 管理后台获取优惠券发送记录。
*
* @author luka 2018-02-23
* @modify 2019-02-25 修复了 SQL 性能问题。
* @contact 2022-03-31 提供给{官网APP}做{列表}功能
*
* @param int $couponId 优惠券ID。
* @param string $username 用户名。
* @param string $mobilephone 用户手机号。
* @param int $page 当前分页页码。
* @param int $count 每页显示条数。
* @param array $data 请求参数。
*
* ------------------- eg:start ---------------------
* $data = [
* 'username' => '用户账号,没有时传空字符串',
* 'age' => '用户年龄,没有时传0',
* ];
* ------------------- eg:end -----------------------
*
* @return array
*/
public static function getBackendSendHistory($couponId = -1, $username, $mobilephone, $page, $count, $data) {
}
可以看出,有以下几个注释特点:
1)方法说明。
2)创建方法的同事编号以及时间。
3)修改方法的同事编号以及时间与修改的内容。
4)参数注释:类型、名称、参数说明。参数与其他注释之间要有空行。
5)参数示例:如果参数当中有复杂的参数。可以在参数下方给出示例以增强说明。
6)返回值。需要给出返回的类型。
7) APP、API层的接口,需在注释中,写清楚这个接口是提供给谁用的,跟谁对接的,完成什么功能;
Yii前必须加斜线 \Yii
所有session的使用配置不能用默认的名字
'session' => array(
'keyPrefix' => '',
'class' => 'yii\redis\Session',
'timeout' => 36000,
'name' => 'cms',
'redis' => [
'class' => 'yii\redis\Connection',
'cluster'=>['10.1.2.10:6379','10.1.2.11:6380','10.1.2.12:6379','10.1.2.13:6380','10.1.2.14 :6380','10.1.2.15 :6379'],
'port' => REDIS_PORT,
'database' => 0,
'password' =>'EgJh6wq',
'isCluster' => 1
],
'cookieParams' => [
'lifetime' => 36000,
],
'isCluster' => 1
),
Redis Key的规则
- 以业务名:数据库名/ES索引名为前缀(防⽌key冲突),⽤冒号分隔,⽐如 业务名:表名/ES索引名:自定义
- key在保证语义的前提下,控制 key的⻓度,最好不要超过100字节;
- 不要包含特殊字符 如:空格 、 换⾏ 、 单双引号 以及 其他转义字符;
性能相关
- 禁止在循环中连接数据库、ES,如果实在需要使用,需要评估风险;
- 上传、下载以及生成文件要考虑内存占用大小和性能(CMS后台、推广xml文件的生成等等);
- 业务数据和基础数据不要放在一张数据库表里,以免网经同步基础数据的时候影响到业务数据;
- ES做关键词搜索,必须控制搜索词的长度,最多30个字符;
- ES搜索,must not搜索词要控制在200个词以内;
- ES搜索,目标查询量不能超过1000条,查询结果需要指定具体字段;
- Mysql数据库,select查询量不能超过1000条,不允许使用select *,需要指定具体字段;
- Mysql数据库做删除操作,建议使用逻辑删除,不用物理删除,迫不得已一定要用物理删除的,一次不允许超过2000条;
- mysql查询,必须用explain分析下,根据结果创建必要索引;
- redis单个key中的value,string 类型控制在 200KB 以内, hash 、 list 、 set 、 zset 元素个数不要超过 5000 ;
- 谨慎使用 redis 队列,超过5000请使用别的方式来实现功能,例如:MQ、Kafka;
- redis中bigkey的删除,⾮字符串的 bigkey ,不要使⽤ del 删除,使⽤ hscan 、 sscan 、 zscan ⽅式渐进 式删除,同时要注意防⽌ bigkey 过期时间⾃动删除问题 (例如⼀个200万的 zset 设置1⼩时过期,会触发 del 操作,造成阻塞) ;
- redis的key,必须设置缓存时间,不能永久保存数据;
- 代码上防止缓存穿透、缓存雪崩,做好备选容错方案;
- 脚本循环要加 sleep(1) 或者 usleep(10000) ,防止循环过于频繁空转;
- while(1), while(true)建议要修改成foreach循环,不可避免的,要设置跳出规则,不能陷入死循环。
日志收集
1、日志记录总则
- 日志中不要记录无用信息,防止无用日志淹没重要信息
- 要明确不同日志的用途,对日志内容进行分类
- 日志信息要准确全面,努力做到仅凭日志就可以定位问题
- 日志格式要统一规范
- 日志要不断优化、完善
2、日志级别
遵循 RFC 5424[2],将日志级别分为以下 8 种等级:
各级日志等级信息记录内容如下:
Emergency
- 导致系统不可用的事故,属于最严重的日志级别,因此该日志级别必须慎用
- 通常情况下,一个进程的声明周期中应该只记录一次 Emergency 级别的日志
Alert
- 必须马上处理的问题,紧急程度低于 Emergency
- Alert 错误发生时,已经影响了用户的正常访问
- 与 Emergency 的区别是,Alert 状态下系统依旧是可用的。例如:DB / Cache 无法连接。
Critical
紧急情况,程序组件不可用,需要立刻进行修复。例如:用户注册逻辑模块不能发送邮件。
Error
- 运行时出现的错误,不必要立即进行修复
- 错误不影响整个逻辑的运行,但需要记录并做检测。
Warning
- 可能影响系统功能,需要提醒的重要事件
- 该日志标识系统可能出现问题,也可能没有(比如网络波动)。对于那些目前还不是错误,然而不及时处理也会变为错误的情况,也可以记为 Warning 日志。例如一个存储系统的磁盘使用量超过阀值,或者系统中某个用户的存储配额快用完等等
- 对于 Warining 级别的日志,虽然不需要马上处理,但也需要及时查看并处理
Notice
- 不影响正常功能,但需要注意的消息
- 执行过程中较 Infomational 级别更为重要的信息。
Infomational
- 用于记录系统正常运行情况下的一般信息,强调应用程序的运行过程。例如:某个子模块的初始化、某个请求的成功执行等
- 通过查看 Infomational 级别的日志,可以很快对系统中出现的 0~5 级别的错误进行定位
Debug
帮助开发、测试、运维人员对系统进行诊断的信息。
代码对应
代码中 | 规范等级 | 备注 |
error | Emergency Alert Critical | 立即需要处理的 |
warning | Error Warning | 定期处理 |
info | Notice Infomational | 定位问题 |
trace | Debug | 诊断信息 |
3、日志分类
日志从功能来说,可分为诊断日志、统计日志、审计日志。
诊断日志
- 请求入口和出口
- 外部服务调用和返回
- 资源消耗操作: 打开文件等
- 容错行为:譬如云硬盘的副本修复操作
- 程序异常:譬如数据库无法连接
- 后台操作:清理程序
- 启动、关闭、配置加载
- 抛出异常时,不记录日志
统计日志
- 用户访问统计
- 计费日志(如记录用户使用的网络资源或磁盘占用,格式较为严格,便于统计)
审计日志
- 管理操作
4、日志其它
后台操作必须记log;
$this->addLog([
'type'=>1,
'userid'=>$_SESSION['userId'],
'username'=>$_SESSION['username'],'data'=>"",
'title'=>'新增-友情链接-'.json_encode($param)
]);
type 1为增2为改3为删4导出
data 数据主键ID,新增时为0
title 存操作的明细,哪个模块,什么操作,和具体参数
调接口,必须记runtime日志,记录入参,记结果,记接口地址;
\Yii::error({接口地址},{类型});
\Yii::error({接口参数},{类型});
$res = Http::request({接口地址},......);
\Yii::error({接口返回值},{类型});
mysql数据库的报错,代码里的异常,需要记录runtime日志;
try {
}
catch(\Exception $ex){
\Yii::error($ex->getFile().$ex->getMessage().$ex->getLine());
}
其它
- 内网 api 层不能调用 外网 api 层接口;
- 内网 api 层不能 通过 CURL 调用内网自己 api 层接口;
- 全局公共方法 位置 /common/helps ,单应用使用的方法位置 /应用/helps
- git merge 后面的分支不能是 test;
- 所有APP、API层接口,必须提供YAPI接口文档,并在接口备注中,标明接口对接人;
- 所有参数建议有默认值,没有的话使用之前必须要判断一下;
- 调用外围系统,对外围系统的url配置,必须写在配置文件中;
- 官网各系统中,调用api层,要用IP绑定host的方式,不能直接写域名;
- 判断条件 常量 在 左侧 如 200 == $data['status'];