shipfi

add php rules

...@@ -50,9 +50,7 @@ windows的cms工具,可以使用ConEmu或者cmder工具 ...@@ -50,9 +50,7 @@ windows的cms工具,可以使用ConEmu或者cmder工具
50 50
51 开发工具下载: 51 开发工具下载:
52 52
53 -phpstorm : [下载链接](https://www.jetbrains.com/phpstorm/download/#section=windows) 53 +phpstorm : [下载链接](https://www.jetbrains.com/phpstorm/download/#section=windows) 注:phpstorm64位版本依赖于JRE
54 -
55 -? 注:phpstorm64位版本依赖于JRE
56 54
57 phpstorm的注册激活 : [参考](http://idea.lanyus.com/) 55 phpstorm的注册激活 : [参考](http://idea.lanyus.com/)
58 56
...@@ -66,6 +64,8 @@ Conemu下载 [下载链接](http://conemu.github.io/en/Downloads.html) ...@@ -66,6 +64,8 @@ Conemu下载 [下载链接](http://conemu.github.io/en/Downloads.html)
66 64
67 65
68 66
67 +
68 +
69 ### 5. 关于PHP默认编码规范 69 ### 5. 关于PHP默认编码规范
70 70
71 * [5.1 PHP语言编码规范 v1.0](php_rule.md) 71 * [5.1 PHP语言编码规范 v1.0](php_rule.md)
...@@ -73,21 +73,27 @@ Conemu下载 [下载链接](http://conemu.github.io/en/Downloads.html) ...@@ -73,21 +73,27 @@ Conemu下载 [下载链接](http://conemu.github.io/en/Downloads.html)
73 73
74 74
75 75
76 +
77 +
76 ### 6. 数据库规范 78 ### 6. 数据库规范
77 79
78 * 6.1 [数据库规范](database.md) 80 * 6.1 [数据库规范](database.md)
79 81
80 82
81 83
84 +
85 +
82 ### 7. GIT代码管理规范 86 ### 7. GIT代码管理规范
83 87
84 * 7.1 [GIT Flow规范](git_flow.md) 88 * 7.1 [GIT Flow规范](git_flow.md)
85 89
86 90
87 91
92 +
93 +
88 ### 8. 项目开发流程规范 94 ### 8. 项目开发流程规范
89 95
90 -* 8.1 [产品设计规范]() 96 +* 8.1 [文档规范]()
91 * 8.2 [项目开发规范]() 97 * 8.2 [项目开发规范]()
92 * 8.3 [测试规范]() 98 * 8.3 [测试规范]()
93 * 8.4 [生产部署规范]() 99 * 8.4 [生产部署规范]()
......
1 +### PHP自定义类示例(Weixin消息解析类)
2 +
3 +
4 +
5 +```php
6 +/**
7 + * Created by Qingger.
8 + * User: jsspf
9 + * Date: 2017/3/24
10 + * Time: 10:50
11 + */
12 +
13 +namespace App\Service;
14 +
15 +use App\Exception\TPException;
16 +use App\Library\VarDefines\GlobalErrCode;
17 +
18 +/**
19 + * 微信公众号消息的接收与回复
20 + * @desc : 消息加解密指引参考 https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419318611&lang=zh_CN
21 + * Class WXMPEventMessageParser
22 + * @package App\Services\WeixinFunc
23 + */
24 +class WeixinMPEventMessageParser extends WeixinBaseFuncService
25 +{
26 +
27 + /**
28 + * @var object
29 + * 接收消息的消息体结构 (text | image | voice | video | shortvideo | location | link)
30 + */
31 + private $_messageReceiveBody = null;
32 +
33 + /**
34 + * @var string
35 + * 接收消息的发送方帐号
36 + */
37 + private $_messageReceiveFrom = null;
38 +
39 + /**
40 + * @var string
41 + * 接收消息的接收方帐号
42 + */
43 + private $_messageReceiveTo = null;
44 +
45 + /**
46 + * @var string
47 + * 接收消息的消息体类型 (text | image | voice | video | shortvideo | location | link)
48 + */
49 + private $_messageReceiveType = null;
50 +
51 +
52 + /**
53 + * @var string
54 + * 接收消息时,Request请求中的nonce信息
55 + */
56 + private $_messageNonce = '';
57 +
58 + /**
59 + * @var WXBizMsgCrypt
60 + * 微信消息体加解密对象
61 + */
62 + private $_wxBizMsgCrypt = null;
63 +
64 + /**
65 + * @var array
66 + * 公众号消息回复的模板
67 + */
68 + private $_replyMessageTemplate = [
69 + // 文本消息的回复模板
70 + 'text' => "<xml>
71 + <ToUserName><![CDATA[%s]]></ToUserName>
72 + <FromUserName><![CDATA[%s]]></FromUserName>
73 + <CreateTime>%s</CreateTime>
74 + <MsgType><![CDATA[text]]></MsgType>
75 + <Content><![CDATA[%s]]></Content>
76 + </xml>",
77 +
78 + // 图片消息的回复模板
79 + 'image' => "<xml>
80 + <ToUserName><![CDATA[%s]]></ToUserName>
81 + <FromUserName><![CDATA[%s]]></FromUserName>
82 + <CreateTime>%s</CreateTime>
83 + <MsgType><![CDATA[image]]></MsgType>
84 + <Image><MediaId><![CDATA[%s]]></MediaId></Image>
85 + </xml>",
86 + ];
87 +
88 +
89 + public function __construct($tpSuiteName,$messageNonce='')
90 + {
91 + parent::__construct();
92 + $this->_messageNonce = $messageNonce;
93 + $this->_wxBizMsgCrypt = new WXBizMsgCrypt(
94 + $this->getWxTpConfigParser()->getConfigToken($tpSuiteName),
95 + $this->getWxTpConfigParser()->getConfigEncodingAesKey($tpSuiteName),
96 + $this->getWxTpConfigParser()->getConfigId($tpSuiteName)
97 + );
98 + }
99 +
100 + /**
101 + * 对消息体进行微信的加密
102 + * @param $replyMsgStr
103 + * @return string
104 + */
105 + private function _encryptMessage($replyMsgStr) {
106 + $replyMessageEncrypt = '';
107 + $this->_wxBizMsgCrypt->encryptMsg($replyMsgStr,time(),$this->_messageNonce,$replyMessageEncrypt);
108 + return $replyMessageEncrypt;
109 + }
110 +
111 + /**
112 + * 生成文本消息的回复结构
113 + * @param $content
114 + * @return string
115 + */
116 + public function textMessageReply($content) {
117 + $replyMessageType = 'text';
118 + $replyMsgStr = sprintf($this->_replyMessageTemplate[$replyMessageType],
119 + $this->_messageReceiveFrom,
120 + $this->_messageReceiveTo,
121 + time(),
122 + $content);
123 + return $this->_encryptMessage($replyMsgStr);
124 + }
125 +
126 + /**
127 + * 生成图片消息的回复
128 + * @param $imageMediaId
129 + * @return string
130 + */
131 + public function imageMessageReply($imageMediaId) {
132 + $replyMessageType = 'image';
133 + $replyMsgStr = sprintf($this->_replyMessageTemplate[$replyMessageType],
134 + $this->_messageReceiveFrom,
135 + $this->_messageReceiveTo,
136 + time(),
137 + $imageMediaId);
138 + return $this->_encryptMessage($replyMsgStr);
139 + }
140 +
141 + /**
142 + * Todo : 需要实现,使用XML对象操作字符串模板
143 + * 生成音乐消息的回复
144 + * @param array $musicInfo
145 + * [
146 + * 'title' : 标题 / 可选
147 + * 'description' : 描述 / 可选
148 + * 'musicURL' : 音乐链接 / 可选
149 + * 'hqMusicUrl' : 高质量音乐链接,WIFI环境优先使用该链接播放音乐 / 可选
150 + * 'ThumbMediaId' : 缩略图的媒体id,通过素材管理接口上传多媒体文件,得到的id / 可选
151 + * ]
152 + * @throws TPException
153 + * @return string
154 + */
155 + public function musicMessageReply(array $musicInfo) {
156 + throw new TPException('Music Message Reply Not Support',GlobalErrCode::ERR_FUNCTION_NOT_IMPLEMENT);
157 + }
158 +
159 + /**
160 + * 解析Weixin Message消息,并根据相应的消息,进行回复
161 + * @desc 具体解密参考:https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419318479&lang=zh_CN
162 + * @param $messageEventObj
163 + * @param Closure $doEvent
164 + * @return mixed
165 + * @throws TPException
166 + */
167 + public function parseEvent($messageEventObj,Closure $doEvent) {
168 + if(isset($messageEventObj->MsgType)) {
169 + $this->_messageReceiveBody = $messageEventObj;
170 + $this->_messageReceiveFrom = isset($messageEventObj->FromUserName)?$messageEventObj->FromUserName:null;
171 + $this->_messageReceiveTo = isset($messageEventObj->ToUserName)?$messageEventObj->ToUserName:null;
172 + $this->_messageReceiveType = $messageEventObj->MsgType;
173 +
174 + $messageReply = $doEvent($messageEventObj);
175 +
176 + return $messageReply;
177 + } else {
178 + throw new TPException('MP Message Body Parse Error',GlobalErrCode::ERR_WEIXIN_MESSAGE_INFO_ERROR);
179 + }
180 +
181 +
182 +}
183 +```
184 +
1 +## PHP语言规范
2 +
3 +本规则适用于使用PHP语言编写应用的人员。一经定义,PHP编写时统一遵循此规范
4 +
5 +本规范包括PHP编写时命名、缩进、文件结构、注释等一系列定义。
6 +
7 +
8 +
9 +**目标 :公司PHP编码形成统一风格,编码人员能够互相理解对方编写之意图。**
10 +
11 +
12 +
13 +### 1. 代码规范
14 +
15 + ##### 1.1 文件夹命名
16 +
17 +* 如果有框架定义,则文件夹命名统一按照框架制定的规则,如果框架不定义,则统一使用小写字母。
18 +
19 + > 以Lumen为例,项目下的第一级目录全部以小写字母命名。除app文件夹外,其它目录也是全部使用小写字母命名。 app目录下文件夹统一使用首字符大写命名。
20 +
21 +
22 +
23 +---
24 +
25 +
26 +
27 +##### 1.2 文件及命名
28 +
29 +* 类文件,命名与类名称保持一致,**必须**统一使用**大驼峰**形式。
30 +
31 + ```php
32 + // CacheManger.php
33 +
34 + class CacheManger {
35 + //...
36 + }
37 + ```
38 +
39 +
40 +* 配置文件,**必须**统一使用字母小写形式命名
41 +
42 + ```php
43 + // config/jwt.php
44 +
45 + return [
46 + //...
47 + ]
48 + ```
49 +
50 +* 普通工具脚本,**必须**统一使用小驼峰命名
51 +
52 + ```php
53 + // tools/uploadImage.php
54 +
55 + $i=1;
56 + dosth();
57 + ```
58 +
59 +* 只含有php代码的文件,结尾处忽略掉 "?>", 以防止多余的空格或者其它字符影响到代码。
60 +
61 +* 文件的编码**必须**为UTF-8字符集
62 +
63 +* 文件换行**必须**以Unix换行\n为准,**不允许**出现\r\n换行。 注:通过git可配置
64 +
65 +* 如果是接口类,则文件以I开头,如 IAuthedUser。 如果是抽象类,则以Abs开头,如AbsAppClient
66 +
67 +* 接口类和抽象类的实现,必须在文件命名中强调其继承哪个接口或抽象.
68 +
69 + ```php
70 + // 命名的准确
71 +
72 + interface IAuthedUser {}
73 + abstract AbsAppClient {}
74 +
75 + class WeixinAuthedUser implements IAutheduser { }
76 + class MessageAppClient extends AbsAppClient {}
77 + ```
78 +
79 +
80 +
81 +---
82 +
83 +
84 +
85 +##### 1.3 变量命名
86 +
87 +* 全局变量命名使用大驼峰,前缀加上_,所有单词首字母大写。
88 +
89 +* 常量统一使用大写,中间分隔使用_
90 +
91 +* 私有变量命名小驼峰,前缀加上_
92 +
93 +* 变量命名确认以英文名词为主。
94 +
95 +* 变量如果是类的对象,**必须**使用注释,使用@var定义对象所属的类
96 +
97 +* **必须**注意单复数,变量如果是数组列表,则以s/es/List为结尾
98 +
99 +* 变量定义示例
100 +
101 + ```php
102 + // 全局变量
103 + $_System_Config = config('myconfig');
104 + $_Root_Path = '/';
105 +
106 + // 常量
107 + define('CURRENT_SCRIPT','index_php');
108 + const TRANSCATION_TYPE = 'income';
109 +
110 + // 私有变量(protected不在此列)
111 + private $_orderCnt = 0;
112 + protected $_salaryAmount = 0;
113 +
114 + /**
115 + * 我的订单列表
116 + * @var array
117 + */
118 + private $myOrderList = [];
119 +
120 + /**
121 + * 客户连接对象
122 + * @var ClientConnection|null
123 + */
124 + private $peerConnection = null;
125 + ```
126 +
127 +
128 +
129 +---
130 +
131 +
132 +
133 +##### 1.4 类、方法、对象命名
134 +
135 +* 类统一使用大驼峰形式命名,与文件名必须保持一致。
136 +* 自编写的类一般遵循名词或名词短语来进行命名。
137 +* 框架中的一些类的命名参考 ()
138 +* 类的动作方法 ,一般使用【动词+名词】方式进行命名,例如 sendMessage / getAttr / setAttr / postLogin等
139 +* 类的属性和变量字段,使用小写字母或者小写驼峰方式命名
140 +* 类的private字段和方法,**必须**使用带_前缀的方式命名
141 +* 常量值,统一使用大写。
142 +* [PHP自定义类示例参考](Samples/my_class_sample.md)
143 +
144 +
145 +
146 +---
147 +
148 +
149 +
150 +##### 1.5 缩进和注释
151 +
152 +* 缩进采用4空格进行缩进,禁止使用TAB制表符。
153 +
154 +* 所有的类、函数、方法定义都需要进行注释。
155 +
156 +* 一般php注释遵循phpdocumentor规范, [phpdocumentor](https://phpdoc.org/docs/latest/references/phpdoc/index.html)
157 +
158 +* 如果是API的接口,则提供PHP APIDOC的相关注释 [APIDOC](https://github.com/calinrada/php-apidoc)
159 +
160 +* 注释
161 +
162 + ```php
163 + // ------- 文件的注释 -------
164 + /**
165 + * Created by Qingger.
166 + * User: shipfi
167 + * Date: 2016/9/22
168 + * Time: 15:49
169 + */
170 +
171 + // ------- 类的注释 -------
172 + /**
173 + * 所有应用Controller的基类,提供了一般性请求/应答的共通实现
174 + * @desc 如有必要,通过desc描述详细的类的功能
175 + * Class BasicController
176 + * @package App\Http\Controllers
177 + */
178 + class BasicController extends Controller
179 + {
180 + // ------- 变量的注释,如果变量为 Array/Object类型,一定要使用@var说明其类型定义 -------
181 +
182 + /**
183 + * 缓存管理对象
184 + * @var AppCacheManager|null
185 + */
186 + protected $appCacheManager = null;
187 +
188 + const MY_RET = GlobalErrCode::ERR_SUCCESS;
189 +
190 + /**
191 + * @param Request $request
192 + * @param AppCacheManager $appCacheManager
193 + */
194 + public function __construct(Request $request,AppCacheManager $appCacheManager){
195 + $this->requestHandler = $request;
196 + $this->appCacheManager = $appCacheManager;
197 + DB::connection()->enableQueryLog();
198 + }
199 +
200 + // ------- 方法的注释,参数如果为Array/Object类型,则一定需要指明 -------
201 +
202 + /**
203 + * 记录Debug日志信息
204 + * @desc : 参考----
205 + * @param $message
206 + * @param array $moreInfo
207 + */
208 + protected function debugLogIt($message,array $moreInfo=[]) {
209 + Log::debug($message,$moreInfo);
210 + }
211 +
212 + }
213 + ```
214 +
215 +
216 +
217 +---
218 +
219 +
220 +
221 +##### 1.6 代码和语句
222 +
223 +* 两元运算符,前后使用空格
224 +
225 + ```php
226 + $ret = $age>18 ? 'adult' : 'children';
227 + ```
228 +
229 +* 变量赋值必须保持相等间距和排列
230 +
231 + ```php
232 + $newQyAgents = array_values(array_rename_keys($qyAgents,[
233 + 'agent_id' => 'agentId',
234 + 'agent_name' => 'agentName',
235 + 'agent_round_logo_url' => 'agentRoundLogo',
236 + 'agent_square_logo_url' => 'agentSquareLogo',
237 + 'agent_app_id' => 'appId'
238 + ]));
239 +
240 + if($corpMangerIns) {
241 + $ret['corpUserManger']['corpUserId'] = $corpMangerIns->getMyUserId();
242 + $ret['corpUserManger']['corpUserEmail'] = $corpMangerIns->getMyUserEmail();
243 + $ret['corpUserManger']['corpUserMobile'] = $corpMangerIns->getMyUserMobile();
244 + }
245 + ```
246 +
247 +* 每行代码长度应控制在80个字符以内,最长不超过120个字符, 如超过则另起一行
248 +
249 + ```php
250 + $qyAuthAppGrpIns = (new QyAuthAppGrp())->getInstanceBySuiteNameCorpId(
251 + $suiteName,
252 + $this->requestHandler->input('corpId')
253 + );
254 + ```
255 +
256 +* 每行结尾不允许有多余空格
257 +
258 +* 在类中(尤其是在Model),对于每个属性的访问, 统一使用get/set方法
259 +
260 + ```php
261 + class MPAuthAppGrp extends BaseModel
262 + {
263 + public function getMyCallBackUrl() { return isset($this->grp_callback_url) ? $this->grp_callback_url : null; }
264 + public function getMyGroupAppId() { return isset($this->grp_app_id) ? $this->grp_app_id : null; }
265 + public function getMyWXAppId() { return isset($this->auth_wx_app_id) ? $this->auth_wx_app_id : null; }
266 + public function getMyWXAppName() { return isset($this->auth_wx_app_name) ? $this->auth_wx_app_name : null; }
267 + public function getMyGrpCode() { return isset($this->grp_code) ? $this->grp_code : null; }
268 + public function getMyOpenAppId() { return isset($this->opentp_appid) ? $this->opentp_appid : null; }
269 + public function getMyOpenAppName() { return isset($this->opentp_name) ? $this->opentp_name : null; }
270 + }
271 + ```
272 +
273 +* 语句流程
274 +
275 + ```php
276 + /** if / else 语句规范 **/
277 + if($age>1 && $age<10) {
278 + echo '1';
279 + } else if($age>30 && $age<=60) {
280 + echo '2';
281 + } else {
282 + echo '3';
283 + }
284 +
285 + /* switch语句规范 */
286 + switch($status) {
287 + // 严禁使用魔数,如 case 10:
288 + case OrderStatus::NO_PAY_STATUS:
289 + echo '1';
290 + break;
291 + case OrderStatus::HAS_PAY_STATUS:
292 + echo '2';
293 + break;
294 + default:
295 + break;
296 + }
297 +
298 + /* while语句 */
299 + while($condition) {
300 + // do sth
301 + }
302 +
303 + /* foreach语句 */
304 + foreach($a)
305 + ```
306 +
307 +* 使用 array 类型符声明关联数组的时候,我们鼓励把它分成多个行,只是我们必须同时保证每行的键与值的对齐,以保持美观。
308 +
309 +* 类中的所有代码都必须用四个空格来进行缩进。
310 +
311 +* 每个 php 文件只允许声明一个类。
312 +
313 +* 任何类变量的声明都**必须**放在类顶部,先于任何函数的声明。
314 +
315 +* 类中的方法必须总是用 private,protected 或者 public 来声明其作用域。
316 +
317 +* 对于方法的变量参数,如果参数确定为对象或数据,则**必须**在参数中给出变量提示:
318 +
319 + ```php
320 + public function foo(AbsContract $obj, array options) {
321 + // do sth
322 + }
323 + ```
324 +
325 +* 代码做到复用,对于相同听代码逻辑,严禁出现在两个函数或者两个文件内,如果逻辑相同,使用重构提取共用性。
326 +
327 +* 一个函数的逻辑实现**严禁**超过一屏(非常特殊或者逻辑简单可理解的除外)。如果业务复杂,使用多个函数实现。
328 +
329 +* 一个函数中**不能**出现以下复杂的if/else逻辑判断, 简单规则,每个函数只允许一个if/elseif/else嵌套层。
330 +
331 + ```php
332 + if($condition1) {
333 + if($condition2) {
334 + // do sth
335 + } else if ($condition3) {
336 + // do sth
337 + } else {
338 + if($condiont4) { // do sth.. }
339 + // do sth
340 + }
341 + } else {
342 + // do sth
343 + }
344 + ```
345 +
346 +
347 +
348 +---
349 +
350 +
351 +
352 +##### 1.7 变量的定义和使用
353 +
354 +* 代码中,类的变量必须做到先定义后使用.
355 +
356 +* 变量使用时,尤其是数组变量,一定要判断其是否被设置
357 +
358 + ```php
359 + $sItem = isset($items['key']) ? $item['key'] : null;
360 + ```
361 +
362 +* 在定义和使用变量时一定要明确其类型
363 +
364 + ```php
365 + // 模型变量定义
366 + $objectModel = new ObjectModel();
367 + $objectInstance = $objectModel->find(1);
368 +
369 + // 基本类型:boolean
370 + $isAuthed = $objectInstance->getMyAuthedFlag();
371 +
372 + // 基本类型:int
373 + $cntAccount = 1;
374 +
375 + // date类型
376 + $dtToday = Carbon::now();
377 + $tsExpires = time() + 3800;
378 +
379 + // 基本类型:array
380 + $accountList = [1,2,3];
381 + $acounts = [1,2,3];
382 +
383 + // 基本类型对象: object
384 + $clientInstance = $this->getClient();
385 +
386 + // foreach使用时尤其是需要明确变量的单复数
387 + foreach($items as $key=>$item) {
388 + // do sth
389 + }
390 +
391 + ```
392 +
393 + ?
...\ No newline at end of file ...\ No newline at end of file