-
Notifications
You must be signed in to change notification settings - Fork 0
/
search.xml
588 lines (283 loc) · 749 KB
/
search.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>使用 Navicat 连接群晖的 PostgreSQL 数据库</title>
<link href="/2022/09/157c1b2f6f39/"/>
<url>/2022/09/157c1b2f6f39/</url>
<content type="html"><![CDATA[<p>群晖的类似 Moments、Audio station、Video Station 等套件都是使用群晖内置的一个 PostgreSQL 数据库,记录一下连接这个数据库的方法。温馨提示: 群晖多个套件均依赖此数据库,没有一定基础的同学,请做好备份,自行评估操作风险。</p><h1 id="创建数据库用户并授权"><a href="#创建数据库用户并授权" class="headerlink" title="创建数据库用户并授权"></a>创建数据库用户并授权</h1><p>打开ssh 连接并群晖获取 root 权限,切换到 posgres 用户,进入 psql 交互命令行,创建新用户并授权:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 切换到postgres用户</span></span><br><span class="line">su - postgres</span><br><span class="line"><span class="meta"></span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 进入posql交互</span></span><br><span class="line">psql</span><br></pre></td></tr></table></figure><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 创建用户</span></span><br><span class="line">CREATE USER 用户名 PASSWORD '密码';</span><br><span class="line"><span class="meta"></span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 授权所有权限</span></span><br><span class="line">ALTER USER 用户名 WITH SUPERUSER CREATEDB;</span><br><span class="line">ALTER USER 用户名 WITH CREATEDB;</span><br><span class="line">ALTER USER 用户名 WITH CREATEROLE;</span><br><span class="line">ALTER USER 用户名 WITH REPLICATION;</span><br><span class="line"><span class="meta"></span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 查看用户列表 看是否执行成功</span></span><br><span class="line">\du</span><br><span class="line"><span class="meta"></span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 退出psql</span></span><br><span class="line">\q</span><br></pre></td></tr></table></figure><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 退出postgres用户,回到root下</span></span><br><span class="line">exit</span><br></pre></td></tr></table></figure><p>修改 <code>pg_hba.conf</code>,将新建的用户授权登陆:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vi /etc/postgresql/pg_hba.conf</span><br></pre></td></tr></table></figure><p>原始内容为:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"># TYPE DATABASE USER ADDRESS METHOD</span><br><span class="line"></span><br><span class="line">local all postgres peer map=pg_root</span><br><span class="line">local all all peer</span><br></pre></td></tr></table></figure><p>我们新增一行,<code>host all 用户名 127.0.0.1/0 md5</code>,修改之后内容为:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"># TYPE DATABASE USER ADDRESS METHOD</span><br><span class="line">host all 用户名 127.0.0.1/0 md5</span><br><span class="line">local all postgres peer map=pg_root</span><br><span class="line">local all all peer</span><br></pre></td></tr></table></figure><p>重新载入配置文件:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">su -l postgres -c "exec /usr/bin/pg_ctl reload"</span><br></pre></td></tr></table></figure><h1 id="修改群晖-sshd-配置,允许端口转发"><a href="#修改群晖-sshd-配置,允许端口转发" class="headerlink" title="修改群晖 sshd 配置,允许端口转发"></a>修改群晖 sshd 配置,允许端口转发</h1><p>不进行此步操作,后面使用 <code>ssh</code> 隧道连接数据库的时候,终端会出现类似 <code>channel 4: open failed: administratively prohibited: open failed</code> 的报错。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vi /etc/ssh/sshd_config</span><br></pre></td></tr></table></figure><p>在约 <code>86</code> 行,找到<code>AllowTcpForwarding no</code> 将其改为 <code>AllowTcpForwarding yes</code>,保存退出。<br>直接登陆网页的 DSM 控制台,依次进入 控制面板——终端机和SNMP——终端机,将“启动SSH功能”取消勾选,应用之后,重新勾选并应用,即可重启 sshd 服务。</p><h1 id="使用-Navicat-连接数据库"><a href="#使用-Navicat-连接数据库" class="headerlink" title="使用 Navicat 连接数据库"></a>使用 Navicat 连接数据库</h1><p>新建——PostgreSQL,连接名随意,主机填写<code>127.0.0.1</code>,端口填写 PostgreSQL 监听的端口 5432,初始数据库填写 <code>postgres</code>,用户名、密码为前面新建数据库用户设置的,在 “SSH” 页选择使用 SSH 通道,IP、用户名、密码使用群晖的 ssh 连接信息即可。</p><p> 使用 macOS 的同学如果 Navicat 自带的 SSH 通道兼容性有问题的,可以本地使用SSH隧道进行端口转发:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 1234为本地监听的端口,5432 为群晖上postgreSQL的监听端口</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> [email protected] -p 22 表示Alliot的群晖用户名为root,IP为192.168.1.2,sshd端口为22</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> ssh -L 5432:127.0.0.1:1234 [email protected] -p 22 (我是用这句成功的)</span></span><br><span class="line">ssh -L 5432:127.0.0.1:5432 [email protected] -p 22</span><br><span class="line"><span class="meta"></span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 查看macOS本地监听的端口,出现1234端口的监听则OK</span></span><br><span class="line">netstat -AaLlnW</span><br></pre></td></tr></table></figure><p>之后 Navicat 连接时,端口填 5432 。</p><h1 id="删除用户,回收权限"><a href="#删除用户,回收权限" class="headerlink" title="删除用户,回收权限"></a>删除用户,回收权限</h1><p>操作完成后,如果需要回收权限,恢复到原样。只需要删除我们新增的那行 <code>pg_hba.conf</code> 配置文件的内容。进入 psql 交互命令中,执行:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">drop user 用户名;</span><br></pre></td></tr></table></figure><p>即可。</p>]]></content>
<categories>
<category> 指南 </category>
</categories>
<tags>
<tag> 教程 </tag>
<tag> PostgreSQL </tag>
</tags>
</entry>
<entry>
<title>MySQL 中使用 find_in_set 方法处理字段中存储多 ID 的情况</title>
<link href="/2022/08/c7e62ac275f6/"/>
<url>/2022/08/c7e62ac275f6/</url>
<content type="html"><![CDATA[<p>开发中经常会遇到用在某一张表的某个字段中存储另一张表<code>id</code>的情况,通常情况下,会采用其他语言先查询出结果,再对这个字段做拆分,接着用拆分的字段去另一张表做查询。</p><p>实际上,这种方法效率较低,<code>MySQL</code>中有一个现成的方法可以很好的处理这种情况。</p><h1 id="场景"><a href="#场景" class="headerlink" title="场景"></a>场景</h1><p>现在假设有下面 2 张表,一张<code>教师表(teachers)</code>,一张<code>学生表(students)</code></p><ul><li>Teachers Table</li></ul><table><thead><tr><th align="center">id</th><th align="center">name</th><th align="center">student_ids</th></tr></thead><tbody><tr><td align="center">1</td><td align="center">老师A</td><td align="center">1,2,3</td></tr><tr><td align="center">2</td><td align="center">老师B</td><td align="center">4,5,6</td></tr><tr><td align="center">3</td><td align="center">老师C</td><td align="center">2</td></tr><tr><td align="center">4</td><td align="center">老师D</td><td align="center"></td></tr></tbody></table><ul><li>Students Table</li></ul><table><thead><tr><th align="center">id</th><th align="center">name</th></tr></thead><tbody><tr><td align="center">1</td><td align="center">学生A</td></tr><tr><td align="center">2</td><td align="center">学生B</td></tr><tr><td align="center">3</td><td align="center">学生C</td></tr><tr><td align="center">4</td><td align="center">学生D</td></tr><tr><td align="center">5</td><td align="center">学生E</td></tr><tr><td align="center">6</td><td align="center">学生F</td></tr></tbody></table><h1 id="FIND-IN-SET-函数"><a href="#FIND-IN-SET-函数" class="headerlink" title="FIND_IN_SET 函数"></a>FIND_IN_SET 函数</h1><blockquote><p>官方说明<br>FIND_IN_SET(str,strlist) : str 要查询的字符串,strlist 需查询的字段,参数以 <strong>“,”</strong> 分隔,形式如 (1,2,6,8,10,22);该函数的作用是查询字段(strlist)中是否包含(str)的结果,返回结果为null或记录。</p></blockquote><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">FIND_IN_SET(<span class="string">'被关联的ID'</span>, <span class="string">'用英文逗号连接来存储ID集合的字段'</span>)</span><br></pre></td></tr></table></figure><p><em><strong>只有以<span style="color:red">英文逗号分隔</span>的字段值,才能使用</strong></em></p><h1 id="实际使用"><a href="#实际使用" class="headerlink" title="实际使用"></a>实际使用</h1><p>现在我们要将<code>教师表</code>和<code>学生表</code>做关联,得到每一位教师底下所拥有的学生,期望的结果如下表:</p><ul><li>Results table</li></ul><table><thead><tr><th align="center">id</th><th align="center">teacher</th><th align="center">student</th></tr></thead><tbody><tr><td align="center">1</td><td align="center">老师A</td><td align="center">学生A,学生B,学生C</td></tr><tr><td align="center">2</td><td align="center">老师B</td><td align="center">学生D,学生E,学生F</td></tr><tr><td align="center">3</td><td align="center">老师C</td><td align="center">学生B</td></tr><tr><td align="center">4</td><td align="center">老师D</td><td align="center"></td></tr></tbody></table><p>每一位教师的学生字段值,显示的是用逗号连接的学生名,原先比较笨的实现方法是,先查出所有教师的数据,然后拆分学生<code>id</code>,再用<code>id</code>去学生表查询出(好一点用<code>IN</code>查询)学生名字,最后组成结果。</p><p>现在可以用<code>FIND_IN_SET</code>和<code>GROUP_CONCAT</code>结合的方式做联表查询</p><p>具体语句如下:</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">SELECT</span></span><br><span class="line"> t.id,</span><br><span class="line"> t.name <span class="keyword">AS</span> teacher,</span><br><span class="line"> GROUP_CONCAT(s.name) <span class="keyword">AS</span> student</span><br><span class="line"><span class="keyword">FROM</span></span><br><span class="line"> teachers <span class="keyword">AS</span> t</span><br><span class="line"><span class="keyword">LEFT</span> <span class="keyword">JOIN</span> </span><br><span class="line"> students <span class="keyword">AS</span> s <span class="keyword">ON</span> FIND_IN_SET(s.id, t.student_ids)</span><br><span class="line"><span class="keyword">GROUP</span> <span class="keyword">BY</span></span><br><span class="line"> t.id; <span class="comment">-- 这里一定要 group by 一下,不然会出现结果丢失</span></span><br><span class="line"></span><br></pre></td></tr></table></figure><p>这样就能得到我们想要的结果了。</p><h1 id="其他注意点"><a href="#其他注意点" class="headerlink" title="其他注意点"></a>其他注意点</h1><p><em><strong>GROUP_CONCAT() 方法有最大字符限制</strong></em></p>]]></content>
<categories>
<category> SQL </category>
</categories>
<tags>
<tag> MySQL </tag>
<tag> 数据库 </tag>
</tags>
</entry>
<entry>
<title>最新Jetbrains IDE激活教程</title>
<link href="/2022/07/eb61ef635dda/"/>
<url>/2022/07/eb61ef635dda/</url>
<content type="html"><![CDATA[<blockquote><p>最新jetbrains全家桶激活方法</p></blockquote><p>原理是我们主要通过代码搜索其他授权服务器进行永久激活激活。</p><ul><li>通过censys</li></ul><p>地址:<a href="https://search.censys.io/">https://search.censys.io/</a></p><p>主要用到的代码</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">services.http.response.headers.location: account.jetbrains.com/fls-auth</span><br></pre></td></tr></table></figure><p>我们复制上面用到的代码 <code>services.http.response.headers.location: account.jetbrains.com/fls-auth</code> 进入 <code>censys</code> 进行搜索。</p><p><img src="/pictures/post/2022/07/01.png" alt="01"></p><p>可以看到出现了很多对应跳转到 jetbrains 的服务器 IP 和网址,我们随便点击一个看下状态是不是 <code>302</code> 只有 <code>302</code> 的才能 正常使用 。</p><p><img src="/pictures/post/2022/07/02.png" alt="02"></p><p>然后我们复制域名或者 IP 到 jetbrains 全家桶进行激活,比如我们使用第一个 <code>49.234.70.205</code> 复制到 <code>License server</code></p><p><img src="/pictures/post/2022/07/03.png" alt="03"></p><p>可以看到已经连接到 jetbrains 授权服务器成功了,然后我们点击 <code>ACTIVATE</code> 进行启动就可以了。</p><p><img src="/pictures/post/2022/07/04.png" alt="04"></p><p>jetbrains激活原理:</p><p>通过以上方式激活 jetbrains 全家桶 主要是用到了 爬取网站服务 这一类的 搜索引擎 实现的通过 搜索引擎 我们找到全世界的 jetbrains 授权服务器 进行激活。</p><p>注意事项</p><ul><li>每个服务器IP承载激活的数量优先, 如果激活时候提示失败,可以多换几个.</li></ul>]]></content>
<categories>
<category> 软件 </category>
</categories>
<tags>
<tag> 教程 </tag>
<tag> 破解 </tag>
</tags>
</entry>
<entry>
<title>Select2 插件使用示例</title>
<link href="/2022/04/3191a260254e/"/>
<url>/2022/04/3191a260254e/</url>
<content type="html"><![CDATA[<p>示例代码</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> select2Setting = {</span><br><span class="line"> <span class="attr">width</span>: <span class="number">260</span>, <span class="comment">// 宽度</span></span><br><span class="line"> <span class="attr">minimumResultsForSearch</span>: -<span class="number">1</span>, <span class="comment">// -1 时,下拉框中的输入框不显示</span></span><br><span class="line"> <span class="comment">// ajax 获取下拉选项数据</span></span><br><span class="line"> <span class="attr">ajax</span>: {</span><br><span class="line"> <span class="attr">url</span>: <span class="string">'请求地址'</span>,</span><br><span class="line"> <span class="attr">dataType</span>: <span class="string">'json'</span>, <span class="comment">// 数据类型</span></span><br><span class="line"> <span class="function"><span class="title">processResults</span>(<span class="params">response</span>)</span> {</span><br><span class="line"> <span class="comment">// return 需要返回带 results 键的对象</span></span><br><span class="line"> <span class="keyword">return</span> {<span class="attr">results</span>: response}</span><br><span class="line"> }</span><br><span class="line"> },</span><br><span class="line"> <span class="attr">templateResult</span>: <span class="function">(<span class="params">state</span>) =></span> {</span><br><span class="line"> <span class="comment">// 下拉时,下拉选项</span></span><br><span class="line"> <span class="keyword">let</span> id = state.id <span class="comment">// 对应 option 的 value</span></span><br><span class="line"> <span class="keyword">let</span> text = state.text <span class="comment">// 对应 option 的 text</span></span><br><span class="line"> <span class="comment">// 下面是给下拉选项加图片的例子</span></span><br><span class="line"> <span class="keyword">return</span> $(<span class="string">`<span><img src="<span class="subst">${imgPath}</span>" class="img-responsive" style="width: 10%;display: inline" alt="<span class="subst">${text}</span>" /> <span class="subst">${text}</span></span>`</span>);</span><br><span class="line"></span><br><span class="line"> },<span class="comment">// 选择时</span></span><br><span class="line"> <span class="attr">templateSelection</span>: <span class="function">(<span class="params">state</span>) =></span> {</span><br><span class="line"> <span class="comment">// 这里的方法尽量要和 templateResult 中一致</span></span><br><span class="line"> <span class="keyword">let</span> id = state.id <span class="comment">// 对应 option 的 value</span></span><br><span class="line"> <span class="keyword">let</span> text = state.text <span class="comment">// 对应 option 的 text</span></span><br><span class="line"> <span class="comment">// 下面是给下拉选项加图片的例子</span></span><br><span class="line"> <span class="keyword">return</span> $(<span class="string">`<span><img src="<span class="subst">${imgPath}</span>" class="img-responsive" style="width: 10%;display: inline" alt="<span class="subst">${text}</span>" /> <span class="subst">${text}</span></span>`</span>);</span><br><span class="line"> } <span class="comment">// 选择后</span></span><br><span class="line">}</span><br><span class="line">$(<span class="string">'.element'</span>).select2(select2Setting)</span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category> JavaScript </category>
</categories>
<tags>
<tag> JS </tag>
<tag> 教程 </tag>
<tag> select2 </tag>
<tag> 下拉选择 </tag>
</tags>
</entry>
<entry>
<title>jQuery DataTable 使用示例</title>
<link href="/2022/04/10daf386098e/"/>
<url>/2022/04/10daf386098e/</url>
<content type="html"><![CDATA[<p>示例代码</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">let</span> settings = {</span><br><span class="line"> <span class="attr">bAutoWidth</span>: <span class="literal">false</span>, <span class="comment">// 自动宽度</span></span><br><span class="line"> <span class="attr">serverSide</span>: <span class="literal">true</span>, <span class="comment">// 服务端启用分页,开启分页后,需要服务端计算总数,false 的时候,需要一次性返回所有数据给表格</span></span><br><span class="line"> <span class="attr">bFilter</span>: <span class="literal">false</span>, <span class="comment">// 自带搜索框是否显示</span></span><br><span class="line"> <span class="attr">ordering</span>: <span class="literal">false</span>, <span class="comment">// 是否需要排序功能</span></span><br><span class="line"> <span class="attr">scrollY</span>: <span class="literal">false</span>, <span class="comment">// 垂直滚动 这里后期改成窗口高度</span></span><br><span class="line"> <span class="attr">aoColumns</span>: [</span><br><span class="line"> {</span><br><span class="line"> <span class="attr">title</span>: <span class="string">'页面上显示的表格头标题'</span>,</span><br><span class="line"> <span class="attr">className</span>: <span class="string">'text-center'</span>, <span class="comment">// 表头的样式</span></span><br><span class="line"> <span class="attr">orderable</span>: <span class="literal">false</span>, <span class="comment">// 是否需要排序,全局排序为 false,这个值无意义</span></span><br><span class="line"> <span class="attr">width</span>: <span class="number">45</span>, <span class="comment">// 表头的宽度</span></span><br><span class="line"> <span class="attr">data</span>: <span class="string">'id'</span>, <span class="comment">// 对应服务端响应数据的名称</span></span><br><span class="line"> <span class="attr">render</span>: <span class="function">(<span class="params">data, type, full, meta</span>) =></span> {</span><br><span class="line"> <span class="comment">// data - 服务端返回的数据值</span></span><br><span class="line"> <span class="comment">// type</span></span><br><span class="line"> <span class="comment">// full - 服务端返回的全部数据</span></span><br><span class="line"> <span class="comment">// meta - 行索引 0 为起始</span></span><br><span class="line"> <span class="keyword">return</span> data</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// ....</span></span><br><span class="line"> ],</span><br><span class="line"> <span class="attr">language</span>: {</span><br><span class="line"> <span class="attr">decimal</span>: <span class="string">''</span>,</span><br><span class="line"> <span class="attr">emptyTable</span>: <span class="string">'暂无数据'</span>,</span><br><span class="line"> <span class="attr">info</span>: <span class="string">'第 _START_ 到 _END_ 条,共 _TOTAL_ 条 | '</span>,</span><br><span class="line"> <span class="attr">infoEmpty</span>: <span class="string">''</span>,</span><br><span class="line"> <span class="attr">infoFiltered</span>: <span class="string">'(从 _MAX_ 条结果中过滤)'</span>,</span><br><span class="line"> <span class="attr">infoPostFix</span>: <span class="string">''</span>,</span><br><span class="line"> <span class="attr">thousands</span>: <span class="string">','</span>,</span><br><span class="line"> <span class="attr">lengthMenu</span>: <span class="string">'_MENU_ 条/页'</span>,</span><br><span class="line"> <span class="attr">loadingRecords</span>: <span class="string">'加载中...'</span>,</span><br><span class="line"> <span class="attr">processing</span>: <span class="string">'加载中...'</span>,</span><br><span class="line"> <span class="attr">search</span>: <span class="string">'搜索:'</span>,</span><br><span class="line"> <span class="attr">zeroRecords</span>: <span class="string">'暂无匹配数据'</span>,</span><br><span class="line"> <span class="attr">paginate</span>: {</span><br><span class="line"> <span class="attr">first</span>: <span class="string">'第一页'</span>,</span><br><span class="line"> <span class="attr">last</span>: <span class="string">'最后一页'</span>,</span><br><span class="line"> <span class="attr">next</span>: <span class="string">'>'</span>,</span><br><span class="line"> <span class="attr">previous</span>: <span class="string">'<'</span></span><br><span class="line"> },</span><br><span class="line"> <span class="attr">aria</span>: {</span><br><span class="line"> <span class="attr">sortAscending</span>: <span class="string">': 以升序排列此列'</span>,</span><br><span class="line"> <span class="attr">sortDescending</span>: <span class="string">': 以降序排列此列'</span></span><br><span class="line"> },</span><br><span class="line"> <span class="attr">select</span>: {</span><br><span class="line"> <span class="attr">rows</span>: {</span><br><span class="line"> <span class="attr">_</span>: <span class="string">"选中 %d 行"</span>,</span><br><span class="line"> <span class="number">0</span>: <span class="string">"点击选中行"</span>,</span><br><span class="line"> <span class="number">1</span>: <span class="string">"选中 1 行"</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> },</span><br><span class="line"> <span class="attr">aaSorting</span>: [], <span class="comment">// 允许排序的字段</span></span><br><span class="line"> <span class="attr">bProcessing</span>: <span class="literal">true</span>, <span class="comment">// 加载表格的进度条</span></span><br><span class="line"> <span class="attr">buttons</span>: [</span><br><span class="line"> {</span><br><span class="line"> <span class="attr">text</span>: <span class="string">'按钮的文字'</span>,</span><br><span class="line"> <span class="attr">className</span>: <span class="string">'btn btn-xs btn-success jqtable-btn'</span>, <span class="comment">// 按钮的类名</span></span><br><span class="line"> <span class="attr">action</span>: <span class="function">(<span class="params">event, dt, node, config</span>) =></span> {</span><br><span class="line"> <span class="comment">// 当点击按钮时,需要做的事情</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> ], <span class="comment">// 是否需要按钮,这个需要引入 jQuery.DataTables.button 这个 js</span></span><br><span class="line"> <span class="attr">select</span>: <span class="literal">false</span>, <span class="comment">// 表格行是否可以被选中</span></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * DOM 参考</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <div class="row"></span></span><br><span class="line"><span class="comment"> * <div class="col-xs-3">{Button - B}</div></span></span><br><span class="line"><span class="comment"> * <div class="col-xs-9 search-area"></div></span></span><br><span class="line"><span class="comment"> * {process - r}</span></span><br><span class="line"><span class="comment"> * {table - t}</span></span><br><span class="line"><span class="comment"> * <div class="row"></span></span><br><span class="line"><span class="comment"> * <div class="col-xs-6"></span></span><br><span class="line"><span class="comment"> * <div class="inline">{info - i}</div></span></span><br><span class="line"><span class="comment"> * <div class="inline">{length - l}</div></span></span><br><span class="line"><span class="comment"> * </div></span></span><br><span class="line"><span class="comment"> * <div class="col-xs-6">{page - p}</div></span></span><br><span class="line"><span class="comment"> * </div></span></span><br><span class="line"><span class="comment"> * </div></span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * B - Button 按钮</span></span><br><span class="line"><span class="comment"> * r - process 进度条</span></span><br><span class="line"><span class="comment"> * t - table 表格</span></span><br><span class="line"><span class="comment"> * i - info 数据信息</span></span><br><span class="line"><span class="comment"> * l - length 数据长度</span></span><br><span class="line"><span class="comment"> * p - page 分页</span></span><br><span class="line"><span class="comment"> * < - <div></span></span><br><span class="line"><span class="comment"> * > - </div></span></span><br><span class="line"><span class="comment"> * 'xxx' - '类名'</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="attr">dom</span>: <span class="string">"<'row'<'col-xs-3'B><'col-xs-9 search-area'>r>t<'row'<'col-xs-6'<'inline'i><'inline'l>><'col-xs-6'p>>"</span>,</span><br><span class="line"> <span class="attr">initComplete</span>: <span class="function">(<span class="params">settings, json</span>) =></span> {</span><br><span class="line"> <span class="comment">// 当表格第一次初始化后的事件</span></span><br><span class="line"> },</span><br><span class="line"> <span class="attr">drawCallback</span>: <span class="function">(<span class="params">settings</span>) =></span> {</span><br><span class="line"> <span class="comment">// 当表格每次重绘的事件</span></span><br><span class="line"> },</span><br><span class="line"> <span class="attr">ajax</span>: <span class="function">(<span class="params">data, callback, settings</span>) =></span> {</span><br><span class="line"> <span class="comment">// ajax 请求获取数据</span></span><br><span class="line"> <span class="keyword">let</span> pagesize = data.length; <span class="comment">// 页面显示记录条数,在页面显示每页显示多少项的时候,页大小</span></span><br><span class="line"> <span class="keyword">let</span> start = data.start; <span class="comment">// 开始的记录序号</span></span><br><span class="line"> <span class="keyword">let</span> page = start / pagesize + <span class="number">1</span>; <span class="comment">//当前页码</span></span><br><span class="line"> $.ajax({</span><br><span class="line"> <span class="attr">type</span>: option.ajax.type || <span class="string">'GET'</span>,</span><br><span class="line"> <span class="attr">url</span>: option.ajax.url,</span><br><span class="line"> <span class="attr">cache</span>: <span class="literal">false</span>,</span><br><span class="line"> <span class="attr">data</span>: {},</span><br><span class="line"> <span class="attr">success</span>: <span class="function"><span class="keyword">function</span> (<span class="params">response</span>) </span>{</span><br><span class="line"> <span class="comment">// 成功请求后,一定要返回这个对象,对象的键参考如下</span></span><br><span class="line"> <span class="keyword">let</span> return_data = {</span><br><span class="line"> <span class="attr">recordsTotal</span>: response.total || <span class="number">0</span>,</span><br><span class="line"> <span class="attr">recordsFiltered</span>: response.total || <span class="number">0</span>,</span><br><span class="line"> <span class="attr">data</span>: response.data || []</span><br><span class="line"> }</span><br><span class="line"> },</span><br><span class="line"> <span class="attr">complete</span>: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"></span><br><span class="line"> },</span><br><span class="line"> <span class="attr">error</span>: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">let</span> return_data = {</span><br><span class="line"> <span class="attr">recordsTotal</span>: <span class="number">0</span>,</span><br><span class="line"> <span class="attr">recordsFiltered</span>: <span class="number">0</span>,</span><br><span class="line"> <span class="attr">data</span>: []</span><br><span class="line"> }</span><br><span class="line"> callback(return_data)</span><br><span class="line"> }</span><br><span class="line"> })</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line">$(<span class="string">'.elements'</span>).dataTable(settings)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 表格重载事件</span></span><br><span class="line">$(<span class="string">'.elements'</span>).api().ajax.reload()</span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category> JavaScript </category>
</categories>
<tags>
<tag> JS </tag>
<tag> 教程 </tag>
<tag> jqueryDataTable </tag>
<tag> 表格 </tag>
</tags>
</entry>
<entry>
<title>hexo 部署到云服务器</title>
<link href="/2022/04/12fb008f68d1/"/>
<url>/2022/04/12fb008f68d1/</url>
<content type="html"><![CDATA[<p>云服务器购买、git 安装、hexo 安装等基础部分略,只整理一些我部署时遇到的问题</p><h1 id="1-创建仓库"><a href="#1-创建仓库" class="headerlink" title="1. 创建仓库"></a>1. 创建仓库</h1><p>首先创建一个空仓,这个仓库会存储<code>hexo</code>的相关代码(改动记录等)</p><span id="more"></span><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git init --bare [你的仓库名称]</span><br></pre></td></tr></table></figure><p>进入这个仓库目录的<code>hooks</code>文件夹下,创建一个新文件,名称为 <code>post-receive</code></p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vim [你的仓库路径]/hooks/post-receive</span><br></pre></td></tr></table></figure><p>写入以下内容</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git --work-tree=[你的博客站点路径,hexo 生成的 html 文件会存储到这里] --git-dir=[你的仓库路径] checkout -f</span><br></pre></td></tr></table></figure><p>保存后退出,赋予权限</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">chmod +x [你的仓库路径]/hooks/post-receive</span><br></pre></td></tr></table></figure><h1 id="2-配置中填写部署的地址"><a href="#2-配置中填写部署的地址" class="headerlink" title="2. 配置中填写部署的地址"></a>2. 配置中填写部署的地址</h1><p>在 <code>_config.yml</code>中填写自己服务器仓库地址</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">deploy:</span></span><br><span class="line"> <span class="attr">branch:</span> <span class="string">master</span></span><br><span class="line"> <span class="attr">type:</span> <span class="string">git</span></span><br><span class="line"> <span class="attr">repo:</span> <span class="string">ssh://[用户名]@[服务器地址]:[服务器端口]/[仓库路径]</span> <span class="comment"># 此处举例而已,适用于特定端口号的服务器</span></span><br></pre></td></tr></table></figure><h1 id="3-最后"><a href="#3-最后" class="headerlink" title="3. 最后"></a>3. 最后</h1><p>将<code>nginx</code>或<code>Apache</code>的站点路径指向对应的博客目录即可完成访问</p>]]></content>
<categories>
<category> 指南 </category>
</categories>
<tags>
<tag> JS </tag>
<tag> 教程 </tag>
<tag> Hexo </tag>
</tags>
</entry>
<entry>
<title>群晖 Video Station 插件开发文档翻译</title>
<link href="/2022/03/b3a54c4c40e8/"/>
<url>/2022/03/b3a54c4c40e8/</url>
<content type="html"><![CDATA[<blockquote><p>群晖 Video Station 插件官方开发文档翻译</p></blockquote><h1 id="1-介绍"><a href="#1-介绍" class="headerlink" title="1. 介绍"></a>1. 介绍</h1><h2 id="1-1-关于视频信息插件"><a href="#1-1-关于视频信息插件" class="headerlink" title="1.1 关于视频信息插件"></a>1.1 关于视频信息插件</h2><p>从 DSM 7.0 的 Video Station 3.0.0 和 DSM 6.0 的 2.5.0 开始,您可以上传自己开发的视频信息索引插件<br>使用视频信息插件功能检索电影和电视节目的视频信息。<br>本文件规定了信息检索工作流程、文件要求、包装<br>视频信息插件的说明和测试详细信息。 </p><span id="more"></span><p><a href="https://global.download.synology.com/download/Addons/VideoStation/com.synology.TMDBExample.zip">下载示例代码</a></p><h1 id="2-信息搜索流程"><a href="#2-信息搜索流程" class="headerlink" title="2. 信息搜索流程"></a>2. 信息搜索流程</h1><p>要在 Video Station 中运行视频信息插件,主要步骤如下:</p><h2 id="2-1-触发视频信息搜索"><a href="#2-1-触发视频信息搜索" class="headerlink" title="2.1 触发视频信息搜索"></a>2.1 触发视频信息搜索</h2><p>单击 Video Station 中的 “从视频信息插件搜索” 按钮后,PluginSearch API 将发送请求以触发视频信息搜索。 </p><h2 id="2-2-转换-INFO-文件"><a href="#2-2-转换-INFO-文件" class="headerlink" title="2.2 转换 INFO 文件"></a>2.2 转换 INFO 文件</h2><p>Video Station 检查插件状态并检索插件 ID 和 INFO 文件中的入口文件路径 </p><h2 id="2-3-运行插件"><a href="#2-3-运行插件" class="headerlink" title="2.3 运行插件"></a>2.3 运行插件</h2><p>Video Station 找到入口文件 (loader.sh) 并以 “nobody” 权限运行它。 一旦信息搜索完成后,Video Station 将解析插件响应并将其保存到数据库 </p><p><img src="/pictures/post/2022/03/1.png" alt="1"></p><h1 id="3-文件要求"><a href="#3-文件要求" class="headerlink" title="3. 文件要求"></a>3. 文件要求</h1><h2 id="3-1-INFO"><a href="#3-1-INFO" class="headerlink" title="3.1 INFO"></a>3.1 INFO</h2><p>INFO 文件提供插件 ID、支持的视频类型、入口文件位置和测试验证插件的示例。 内容必须使用 JSON 格式的 UTF-8 编码,通常如下所示</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> <span class="attr">"id"</span>: <span class="string">"com.synology.TMDBExample"</span>,</span><br><span class="line"> <span class="attr">"description"</span>: <span class="string">""</span>,</span><br><span class="line"> <span class="attr">"version"</span>: <span class="string">"1.0"</span>,</span><br><span class="line"> <span class="attr">"site"</span>: <span class="string">"http://www.themoviedb.org/"</span>,</span><br><span class="line"> <span class="attr">"entry_file"</span>: <span class="string">"loader.sh"</span>,</span><br><span class="line"> <span class="attr">"type"</span>: [</span><br><span class="line"> <span class="string">"movie"</span>,</span><br><span class="line"> <span class="string">"tvshow"</span></span><br><span class="line"> ],</span><br><span class="line"> <span class="attr">"language"</span>: [</span><br><span class="line"> <span class="string">"enu"</span></span><br><span class="line"> ],</span><br><span class="line"> <span class="attr">"test_example"</span>: {</span><br><span class="line"> <span class="attr">"movie"</span>: {</span><br><span class="line"> <span class="attr">"title"</span>: <span class="string">"Harry Potter"</span>,</span><br><span class="line"> <span class="attr">"original_available"</span>: <span class="string">"2001-11-16"</span></span><br><span class="line"> },</span><br><span class="line"> <span class="attr">"tvshow"</span>: {</span><br><span class="line"> <span class="attr">"title"</span>: <span class="string">"Game of Thrones"</span>,</span><br><span class="line"> <span class="attr">"original_available"</span>: <span class="string">"2011-04-17"</span></span><br><span class="line"> },</span><br><span class="line"> <span class="attr">"tvshow_episode"</span>: {</span><br><span class="line"> <span class="attr">"title"</span>: <span class="string">"Game of Thrones"</span>,</span><br><span class="line"> <span class="attr">"original_available"</span>: <span class="string">"2011-04-17"</span>,</span><br><span class="line"> <span class="attr">"season"</span>: <span class="number">1</span>,</span><br><span class="line"> <span class="attr">"episode"</span>: <span class="number">1</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>表1. INFO 文件的内容</strong></p><table><thead><tr><th align="center">key</th><th align="center">类型</th><th align="center">描述</th><th align="center">是否必须</th></tr></thead><tbody><tr><td align="center">id</td><td align="center">string</td><td align="center">唯一的插件ID,应该和插件一样,作为文件夹名称。如果插件ID重复,插件不能上传</td><td align="center">必须</td></tr><tr><td align="center">entry_file</td><td align="center">string</td><td align="center">入口文件loader.sh的相对文件路径。</td><td align="center">必须</td></tr><tr><td align="center">type</td><td align="center">array of string</td><td align="center">插件支持的视频类型,必须是以下之一:[‘movie’]、[‘tvshow’] 或 [‘movie’, ‘tvshow’]。</td><td align="center">必须</td></tr><tr><td align="center">version</td><td align="center">string</td><td align="center">插件的版本号</td><td align="center">可选</td></tr><tr><td align="center">description</td><td align="center">string</td><td align="center">插件的描述信息</td><td align="center">可选</td></tr><tr><td align="center">site</td><td align="center">string</td><td align="center">插件的源地址</td><td align="center">可选</td></tr><tr><td align="center">language</td><td align="center">array of string</td><td align="center">插件支持的语言 (e.g. [‘cht’, ‘enu’])</td><td align="center">可选</td></tr><tr><td align="center">test_example</td><td align="center">JSON object</td><td align="center">此值可确保您的插件在您使用时可用上传或测试插件的连接。 这是一个测试_电影的例子:”movie”: {“title”: “Harry Potter”, “original_available”: “2001-11-16”},如果插件支持电视剧类型的视频,这里提供一个相关类型的例子:”tvshow”: {“title”: “Game of Thrones”, “original_available”: “2011-04-17”},”tvshow_episode”: {“title”: “Game of Thrones”, “original_available”: “2011-04-17”, “season”: 1, “episode”: 1}</td><td align="center">必须</td></tr></tbody></table><h2 id="3-2-loader-sh"><a href="#3-2-loader-sh" class="headerlink" title="3.2 loader.sh"></a>3.2 loader.sh</h2><p>Video Station 将执行 loader.sh 以检索视频信息。 您可以使用 PHP 或 Python 3.x 搜索算法并在 loader.sh 中运行。 Video Station 将运行您的具有以下参数的插件: </p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">/bin/bash loader.sh --<span class="built_in">type</span> movie --lang enu --input <span class="string">"{\"title\":\"Toy Story\", \"original_available\": \"1995-11-22\"}"</span> --<span class="built_in">limit</span> 1 --allowguess <span class="literal">false</span></span><br></pre></td></tr></table></figure><p>下表解释了 Video Station 传递的参数的详细信息</p><p><strong>表2. 发送给 loader.sh 的参数说明</strong></p><table><thead><tr><th align="center">参数</th><th align="center">类型</th><th align="center">描述</th><th align="center">是否必须</th></tr></thead><tbody><tr><td align="center">input</td><td align="center">JSON object</td><td align="center">查询输入必须是 JSON 对象,包括以下内容:title(必填)和 original_available(可选)。搜索电视剧集的信息时,必须包含 episode 和 season</td><td align="center">必须</td></tr><tr><td align="center">lang</td><td align="center">string</td><td align="center">首选语言(必须是以下任何一种:chs、cht, csy, dan, enu, fre, ger, hun, ita, jpn, krn, nld, nor, plk, ptb, ptg、rus、spn、sve、trk、tha)</td><td align="center">必须</td></tr><tr><td align="center">type</td><td align="center">string</td><td align="center">查询的视频类型, 必须是下列的一种: movie, tvshow, tvshow_episode</td><td align="center">必须</td></tr><tr><td align="center">limit</td><td align="center">int</td><td align="center">允许的最大结果数</td><td align="center">必须</td></tr><tr><td align="center">allowguess</td><td align="center">boolean</td><td align="center">如果 title guessing 功能支持的时候才可用</td><td align="center">可选</td></tr></tbody></table><blockquote><ol><li>如果电视剧的 season 值为 0,意味着这是季的特别篇(e.g. 日剧的SP)。如果输入的参数没有 tvshow_episode (集的信息),意味着将获得 season 的全部集信息</li><li>标题猜测功能应该由插件实现。 可查看示例代码的 <code>searchinc.py</code> 的 <code>get_guessing_names</code> 方法 </li></ol></blockquote><h1 id="4-插件响应"><a href="#4-插件响应" class="headerlink" title="4. 插件响应"></a>4. 插件响应</h1><p>所有插件响应都应编码为 JSON 对象。 搜索结果插件由键 “success” 表示,其值可以是真/假(布尔值)取决于请求的状态</p><h2 id="4-1-成功响应"><a href="#4-1-成功响应" class="headerlink" title="4.1 成功响应"></a>4.1 成功响应</h2><p>成功的响应将包含 “success” 的键,值为 “true”, “result” 的值是 JSON 数组,内容因视频类型而异(例如,电影、电视节目、电视,显示剧集)</p><h3 id="4-1-1-电影"><a href="#4-1-1-电影" class="headerlink" title="4.1.1 电影"></a>4.1.1 电影</h3><p>电影的检索结果将包括以下属性:</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> <span class="attr">"success"</span>: <span class="literal">true</span>,</span><br><span class="line"> <span class="attr">"result"</span>: [</span><br><span class="line"> {</span><br><span class="line"> <span class="attr">"title"</span>: <span class="string">"Toy Story"</span>,</span><br><span class="line"> <span class="attr">"tagline"</span>: <span class="string">""</span>,</span><br><span class="line"> <span class="attr">"original_available"</span>: <span class="string">"1995-10-30"</span>,</span><br><span class="line"> <span class="attr">"original_title"</span>: <span class="string">"Toy Story"</span>,</span><br><span class="line"> <span class="attr">"summary"</span>: <span class="string">"Led by Woody, Andy's toys live happily in his room until Andy's birthday brings Buzz Lightyear onto the scene. Afraid of losing his place in Andy's heart, Woody plots against Buzz. But when circumstances separate Buzz and Woody from their owner, the duo eventually learns to put aside their differences."</span>,</span><br><span class="line"> <span class="attr">"certificate"</span>: <span class="string">"G"</span>,</span><br><span class="line"> <span class="attr">"genre"</span>: [</span><br><span class="line"> <span class="string">"Animation"</span>,</span><br><span class="line"> <span class="string">"Adventure"</span>,</span><br><span class="line"> <span class="string">"Family"</span>,</span><br><span class="line"> <span class="string">"Comedy"</span></span><br><span class="line"> ],</span><br><span class="line"> <span class="attr">"actor"</span>: [</span><br><span class="line"> <span class="string">"Tom Hanks"</span></span><br><span class="line"> ],</span><br><span class="line"> <span class="attr">"director"</span>: [</span><br><span class="line"> <span class="string">"John Lasseter"</span></span><br><span class="line"> ],</span><br><span class="line"> <span class="attr">"writer"</span>: [</span><br><span class="line"> <span class="string">"Andrew Stanton"</span></span><br><span class="line"> ],</span><br><span class="line"> <span class="attr">"extra"</span>: {</span><br><span class="line"> <span class="attr">"com.synology.TMDBExample"</span>: {</span><br><span class="line"> <span class="attr">"rating"</span>: {</span><br><span class="line"> <span class="attr">"com.synology.TMDBExample"</span>: <span class="number">7.9</span></span><br><span class="line"> },</span><br><span class="line"> <span class="attr">"poster"</span>: [</span><br><span class="line"> <span class="string">"https://image.tmdb.org/t/p/w500/uXDfjJbdP4ijW5hWSBrPrlKpxab.jpg"</span></span><br><span class="line"> ],</span><br><span class="line"> <span class="attr">"backdrop"</span>: [</span><br><span class="line"> <span class="string">"https://image.tmdb.org/t/p/original/3Rfvhy1Nl6sSGJwyjb0QiZzZYlB.jpg"</span></span><br><span class="line"> ]</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> ]</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="4-1-2-电视剧"><a href="#4-1-2-电视剧" class="headerlink" title="4.1.2 电视剧"></a>4.1.2 电视剧</h3><p>电视剧的搜索结果将包含以下属性:</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> <span class="attr">"success"</span>: <span class="literal">true</span>,</span><br><span class="line"> <span class="attr">"result"</span>: [</span><br><span class="line"> {</span><br><span class="line"> <span class="attr">"title"</span>: <span class="string">"Elementary"</span>,</span><br><span class="line"> <span class="attr">"original_available"</span>: <span class="string">"2012-09-27"</span>,</span><br><span class="line"> <span class="attr">"original_title"</span>: <span class="string">"Elementary"</span>,</span><br><span class="line"> <span class="attr">"summary"</span>: <span class="string">"A modern-day drama about a crime-solving duo that cracks the NYPD's most impossible cases. Following his fall from grace in London and a stint in rehab, eccentric Sherlock escapes to Manhattan where his wealthy father forces him to live with his worst nightmare - a sober companion, Dr. Watson."</span>,</span><br><span class="line"> <span class="attr">"extra"</span>: {</span><br><span class="line"> <span class="attr">"com.synology.TMDBExample"</span>: {</span><br><span class="line"> <span class="attr">"poster"</span>: [</span><br><span class="line"> <span class="string">"https://image.tmdb.org/t/p/w500/q9dObe29W4bDpgzUfOOH3ZnzDbR.jpg"</span></span><br><span class="line"> ],</span><br><span class="line"> <span class="attr">"backdrop"</span>: [</span><br><span class="line"> <span class="string">"https://image.tmdb.org/t/p/original/7sJrNKwzyJWnFPFpDL9wnZ859LZ.jpg"</span></span><br><span class="line"> ]</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> ]</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="4-1-3-电视剧的集信息"><a href="#4-1-3-电视剧的集信息" class="headerlink" title="4.1.3 电视剧的集信息"></a>4.1.3 电视剧的集信息</h3><p>电视节目特定剧集的搜索结果将包括以下属性:</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> <span class="attr">"success"</span>: <span class="literal">true</span>,</span><br><span class="line"> <span class="attr">"result"</span>: [</span><br><span class="line"> {</span><br><span class="line"> <span class="attr">"title"</span>: <span class="string">"Elementary"</span>,</span><br><span class="line"> <span class="attr">"tagline"</span>: <span class="string">"Pilot"</span>,</span><br><span class="line"> <span class="attr">"original_available"</span>: <span class="string">"2012-09-27"</span>,</span><br><span class="line"> <span class="attr">"summary"</span>: <span class="string">"Detective Sherlock Holmes, along with his sober companion, Dr. Joan Watson, uses his uncanny ability to read people and analyze crimes to assist the NYPD on some of their more difficult cases."</span>,</span><br><span class="line"> <span class="attr">"certificate"</span>: <span class="string">"TV-14"</span>,</span><br><span class="line"> <span class="attr">"genre"</span>: [</span><br><span class="line"> <span class="string">"Drama"</span>,</span><br><span class="line"> <span class="string">"Mystery"</span>,</span><br><span class="line"> <span class="string">"Crime"</span></span><br><span class="line"> ],</span><br><span class="line"> <span class="attr">"actor"</span>: [</span><br><span class="line"> <span class="string">"Jonny Lee Miller"</span>,</span><br><span class="line"> <span class="string">"Lucy Liu"</span></span><br><span class="line"> ],</span><br><span class="line"> <span class="attr">"director"</span>: [</span><br><span class="line"> <span class="string">"Michael Cuesta"</span></span><br><span class="line"> ],</span><br><span class="line"> <span class="attr">"writer"</span>: [</span><br><span class="line"> <span class="string">"Robert Doherty"</span></span><br><span class="line"> ],</span><br><span class="line"> <span class="attr">"season"</span>: <span class="number">1</span>,</span><br><span class="line"> <span class="attr">"episode"</span>: <span class="number">1</span>,</span><br><span class="line"> <span class="attr">"extra"</span>: {</span><br><span class="line"> <span class="attr">"com.synology.TheMovieDb"</span>: {</span><br><span class="line"> <span class="attr">"tvshow"</span>: {</span><br><span class="line"> <span class="attr">"title"</span>: <span class="string">"Elementary"</span>,</span><br><span class="line"> <span class="attr">"original_available"</span>: <span class="string">"2012-09-27"</span>,</span><br><span class="line"> <span class="attr">"original_title"</span>: <span class="string">"Elementary"</span>,</span><br><span class="line"> <span class="attr">"summary"</span>: <span class="string">"A modern-day drama about a crime-solving duo that cracks the NYPD's most impossible cases. Following his fall from grace in London and a stint in rehab, eccentric Sherlock escapes to Manhattan where his wealthy father forces him to live with his worst nightmare - a sober companion, Dr. Watson."</span>,</span><br><span class="line"> <span class="attr">"extra"</span>: {</span><br><span class="line"> <span class="attr">"com.synology.TMDBExample"</span>: {</span><br><span class="line"> <span class="attr">"poster"</span>: [</span><br><span class="line"> <span class="string">"https://image.tmdb.org/t/p/w500/q9dObe29W4bDpgzUfOOH3ZnzDbR.jpg"</span></span><br><span class="line"> ],</span><br><span class="line"> <span class="attr">"backdrop"</span>: [</span><br><span class="line"> <span class="string">"https://image.tmdb.org/t/p/original/7sJrNKwzyJWnFPFpDL9wnZ859LZ.jpg"</span></span><br><span class="line"> ]</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> },</span><br><span class="line"> <span class="attr">"poster"</span>: [</span><br><span class="line"> <span class="string">"https://image.tmdb.org/t/p/w500/14PEsYWrZGYaQONPxQHaHjqufK5.jpg"</span></span><br><span class="line"> ],</span><br><span class="line"> <span class="attr">"rating"</span>: {</span><br><span class="line"> <span class="attr">"com.synology.TheMovieDb"</span>: <span class="number">7.4</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> ]</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="4-2-错误响应"><a href="#4-2-错误响应" class="headerlink" title="4.2 错误响应"></a>4.2 错误响应</h2><p>当 API 请求由于某些搜索错误而失败时,响应将包含键 “success”,值为 “false”,错误代码指示导致失败的条件</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">{<span class="attr">"success"</span>:<span class="literal">false</span>,<span class="attr">"error_code"</span>:<span class="number">1003</span>}</span><br></pre></td></tr></table></figure><p>根据发生的错误类型,显示以下状态代码</p><table><thead><tr><th align="center">错误码</th><th align="center">描述</th></tr></thead><tbody><tr><td align="center">1003</td><td align="center">该代码表示搜索失败。 例如,插件可能无法连接到源网站或无法检索请求的数据。</td></tr><tr><td align="center">1004</td><td align="center">该代码表示无法解析响应结果。 这可能是由于缺少必填信息或其他意外错误</td></tr></tbody></table><h1 id="5-打包你的插件"><a href="#5-打包你的插件" class="headerlink" title="5. 打包你的插件"></a>5. 打包你的插件</h1><p>应与文件夹名称和您的插件 ID 相同。 Video Station 将提取带有 tar 的 .tar 和带有 7z 的 .zip</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">System<span class="comment"># tar --no-xattrs -cvf com.synology.TMDBExample.tar com.synology.TMDBExample</span></span><br><span class="line">System<span class="comment"># 7z a com.synology.TMDBExample.zip com.synology.TMDBExample</span></span><br></pre></td></tr></table></figure><h1 id="6-测试你的插件"><a href="#6-测试你的插件" class="headerlink" title="6. 测试你的插件"></a>6. 测试你的插件</h1><p>在开发阶段,您可以使用插件测试器检查您的插件是否有效</p><h2 id="6-1-快速测试"><a href="#6-1-快速测试" class="headerlink" title="6.1 快速测试"></a>6.1 快速测试</h2><p>此方法允许您测试插件的搜索功能。 测试你的插件功能齐全,请参阅完整测试部分。</p><ol><li><p>在插件测试器所在的位置安装 Video Station。</p></li><li><p>使用 File Station 将插件文件上传到 Synology NAS。</p></li><li><p>使用 nobody 权限输入以下命令来测试您的插件。</p></li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo -u nobody /var/packages/VideoStation/target/plugins/syno_plugin_tester/loader.sh --<span class="built_in">type</span> movie --lang enu --input <span class="string">"{\"title\":\"{movie title}\", \"original_available\":\"2001-11-16\"}"</span> --<span class="built_in">limit</span> 1 --path <span class="string">"<span class="variable">${entry file path of your search plugin}</span>"</span> --pluginid <span class="variable">$your</span> plugin id}</span><br></pre></td></tr></table></figure><ol start="4"><li>如果插件验证通过,会收到成功响应:<code>{"success": true}</code></li></ol><ol start="5"><li>否则,<code>success</code> 的值为 <code>false</code>,并带有错误代码指示导致故障的条件</li></ol><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">{<span class="attr">"success"</span>: <span class="literal">false</span>, <span class="attr">"error_code"</span>: <span class="number">1004</span>, <span class="attr">"msg"</span>: <span class="string">"execute plugin fail"</span>}</span><br></pre></td></tr></table></figure><p><strong>下面是插件测试器的参数说明</strong></p><table><thead><tr><th align="center">参数</th><th align="center">类型</th><th align="center">描述</th><th align="center">是否强制</th></tr></thead><tbody><tr><td align="center">input</td><td align="center">JSON object</td><td align="center">input 字段必须是 JSON object 并且包含下列内容: title (必填) 和 original_available (可选). 如果搜索的是 tvshow_episode, input 必须包含 episode 和 season</td><td align="center">必须</td></tr><tr><td align="center">lang</td><td align="center">string</td><td align="center">语言选项必须是下列中的一种 : chs, cht, csy, dan, enu, fre, ger, hun, ita, jpn, krn, nld, nor, plk, ptb, ptg, rus, spn, sve, trk, tha.</td><td align="center">必须</td></tr><tr><td align="center">type</td><td align="center">string</td><td align="center">查询视频的类型,必须是下列的一种: movie, tvshow, tvshow_episode.</td><td align="center">必须</td></tr><tr><td align="center">limit</td><td align="center">int</td><td align="center">插件返回的最大查询结果数</td><td align="center">必须</td></tr><tr><td align="center">path</td><td align="center">string</td><td align="center">入口文件的绝对路径</td><td align="center">必须</td></tr><tr><td align="center">pluginid</td><td align="center">string</td><td align="center">插件ID</td><td align="center">必须</td></tr></tbody></table><h2 id="6-2-完整测试"><a href="#6-2-完整测试" class="headerlink" title="6.2 完整测试"></a>6.2 完整测试</h2><p>完整测试你的插件, 你可以上传到 Video Station 使用 Chrome DevTools 来检查你插件的状态</p>]]></content>
<categories>
<category> 指南 </category>
</categories>
<tags>
<tag> 群晖 </tag>
<tag> Video Station </tag>
<tag> 翻译 </tag>
</tags>
</entry>
<entry>
<title>RESTful 详解</title>
<link href="/2021/12/6907dde1b0f1/"/>
<url>/2021/12/6907dde1b0f1/</url>
<content type="html"><![CDATA[<p>本文转载自 <a href="https://mp.weixin.qq.com/s/um5kDYBscf5sy7FUhmP7ww">到底什么是 RESTful ?</a> </p><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>在学习 RESTful 风格接口之前,即使你不知道它是什么,但你肯定会好奇它能解决什么问题?有什么应用场景?听完下面描述我想你就会明白:<br>在互联网并没有完全流行的初期,移动端也没有那么盛行,页面请求和并发量也不高,那时候人们对接口的要求没那么高,一些动态页面 (jsp) 就能满足绝大多数的使用需求。</p><span id="more"></span><p><img src="/pictures/post/2021/12/1.webp" alt="1"></p><p>但是随着互联网和移动设备的发展,人们对Web应用的使用需求也增加,传统的动态页面由于低效率而渐渐被 HTML + JavaScript(Ajax) 的前后端分离所取代,并且安卓、IOS、小程序等形式客户端层出不穷,客户端的种类出现多元化,而<strong>客户端和服务端就需要接口进行通信</strong>,但接口的<strong>规范性</strong>就又成了一个问题:</p><p><img src="/pictures/post/2021/12/2.webp" alt="2"></p><p>所以一套<strong>结构清晰、符合标准、易于理解、扩展方便</strong>让大部分人都能够理解接受的接口风格就显得越来越重要,而 RESTful 风格的接口 (RESTful API) 刚好有以上特点,就逐渐被实践应用而变得流行起来。</p><p><img src="/pictures/post/2021/12/3.webp" alt="3"></p><p>现在,RESTful是目前最流行的接口设计规范,在很多公司有着广泛的应用,其中 Github 的 API 设计就是很标准的 RESTful API,你可以参考学习。<br>在开发实践中我们很多人可能还是使用传统API进行请求交互,很多人其实并不特别了解 RESTful API,对 RESTful API 的认知可能会停留在:</p><ul><li>面向资源类型的</li><li>是一种风格</li><li>(误区)接口传递参数使用斜杠(/)分割而不用问号(?)传参。</li></ul><p>而其实一个很大的误区不要认为没有查询字符串就是 RESTful API,也不要认为用了查询字符串就不是 RESTful API,更不要认为用了 JSON 传输的 API 就是 RESTful API。</p><h1 id="一、REST介绍"><a href="#一、REST介绍" class="headerlink" title="一、REST介绍"></a>一、REST介绍</h1><p>REST 涉及一些概念性的东西可能比较多,在实战 RESTful API 之前,要对 REST 相关的知识有个系统的认知。</p><h2 id="REST的诞生"><a href="#REST的诞生" class="headerlink" title="REST的诞生"></a>REST的诞生</h2><p>REST(英文:Representational State Transfer,简称 REST,直译过来表现层状态转换)是一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。</p><p>它首次出现在 2000 年 Roy Thomas Fielding 的博士论文中,这篇论文定义并详细介绍了表述性状态转移(Representational State Transfer,REST)的架构风格,并且描述了 如何使用 REST 来指导现代 Web 架构的设计和开发。用他自己的原话说:</p><blockquote><p>写这篇文章的目的是:在符合架构原理前提下,理解和评估基于网络的应用软件的架构设计,得到一个功能强、性能好、适宜通信的架构。</p></blockquote><p>需要注意的是 REST 并没有一个明确的标准,而更像是一种设计的风格,满足这种设计风格的程序或接口我们称之为 RESTful (从单词字面来看就是一个形容词)。所以 RESTful API 就是满足 REST 架构风格的接口。</p><p><img src="/pictures/post/2021/12/4.webp" alt="Fielding博士答辩"></p><p>Fielding 博士当时提出的是 REST 架构在很久的时间内并没有被关注太多,而近些年 REST 在国内才变得越来越流行。下面开始详细学习 REST 架构特征。</p><h2 id="REST架构特征"><a href="#REST架构特征" class="headerlink" title="REST架构特征"></a>REST架构特征</h2><p>既然知道 REST 和 RESTful 的联系和区别,现在就要开始好好了解 RESTful 的一些约束条件和规则,RESTful 是一种风格而不是标准,而这个风格大致有以下几个主要<strong>特征</strong>:</p><p><strong>以资源为基础</strong> :资源可以是一个图片、音乐、一个 XML 格式、HTML 格式或者 JSON 格式等网络上的一个实体,除了一些二进制的资源外普通的文本资源更多以 JSON 为载体、面向用户的一组数据(通常从数据库中查询而得到)。</p><p><strong>统一接口</strong>: 对资源的操作包括获取、创建、修改和删除,这些操作正好对应 HTTP 协议提供的 GET、POST、PUT 和 DELETE 方法。换言而知,使用 RESTful 风格的接口但从接口上你可能只能定位其资源,但是无法知晓它具体进行了什么操作,需要具体了解其发生了什么操作动作要从其 HTTP 请求方法类型上进行判断。具体的 HTTP 方法和方法含义如下:</p><ul><li><p>GET(SELECT):从服务器取出资源(一项或多项)。</p></li><li><p>POST(CREATE):在服务器新建一个资源。</p></li><li><p>PUT(UPDATE):在服务器更新资源(客户端提供完整资源数据)。</p></li><li><p>PATCH(UPDATE):在服务器更新资源(客户端提供需要修改的资源数据)。</p></li><li><p>DELETE(DELETE):从服务器删除资源。</p></li></ul><p>当然也有很多在具体使用的时候使用 PUT 表示更新。从请求的流程来看,RESTful API 和传统 API 大致架构如下:</p><p><img src="/pictures/post/2021/12/5.webp" alt="5"></p><p><strong>URI指向资源</strong>:URI = Universal Resource Identifier 统一资源标志符,用来标识抽象或物理资源的一个紧凑字符串。URI 包括 URL 和 URN,在这里更多时候可能代指URL(统一资源定位符)。RESTful 是面向资源的,每种资源可能由一个或多个 URI 对应,但一个 URI 只指向一种资源。</p><p><strong>无状态</strong>:服务器不能保存客户端的信息, 每一次从客户端发送的请求中,要包含所有必须的状态信息,会话信息由客户端保存, 服务器端根据这些状态信息来处理请求。当客户端可以切换到一个新状态的时候发送请求信息, 当一个或者多个请求被发送之后, 客户端就处于一个状态变迁过程中。每一个应用的状态描述可以被客户端用来初始化下一次的状态变迁。</p><h2 id="REST架构限制条件"><a href="#REST架构限制条件" class="headerlink" title="REST架构限制条件"></a>REST架构限制条件</h2><p>Fielding 在论文中提出 REST 架构的 6 个<strong>限制条件</strong>,也可称为 RESTful 6 大原则, 标准的 REST 约束应满足以下 6 个<strong>原则</strong>:</p><ul><li><p><strong>客户端-服务端(Client-Server)</strong>: 这个更专注客户端和服务端的分离,服务端独立可更好服务于前端、安卓、IOS 等客户端设备。</p></li><li><p><strong>无状态(Stateless)</strong>:服务端不保存客户端状态,客户端保存状态信息每次请求携带状态信息。</p></li><li><p><strong>可缓存性(Cacheability)</strong>:服务端需回复是否可以缓存以让客户端甄别是否缓存提高效率。</p></li><li><p><strong>统一接口(Uniform Interface)</strong>:通过一定原则设计接口降低耦合,简化系统架构,这是 RESTful 设计的基本出发点。当然这个内容除了上述特点提到部分具体内容比较多详细了解可以参考这篇 REST 论文内容。</p></li><li><p><strong>分层系统(Layered System)</strong>:客户端无法直接知道连接的到终端还是中间设备,分层允许你灵活的部署服务端项目。</p></li><li><p><strong>按需代码(Code-On-Demand,可选)</strong>:按需代码允许我们灵活的发送一些看似特殊的代码给客户端例如 JavaScript 代码。</p></li></ul><p>REST 架构的一些风格和限制条件就先介绍到这里,后面就对 RESTful 风格 API 具体介绍。</p><h1 id="二、RESTful-API设计规范"><a href="#二、RESTful-API设计规范" class="headerlink" title="二、RESTful API设计规范"></a>二、RESTful API设计规范</h1><p>既然了解了 RESTful 的一些规则和特性,那么具体该怎么去设计一个 RESTful API 呢?要从 URL 路径、HTTP 请求动词、状态码和返回结果等方面详细考虑。至于其他的方面例如错误处理、过滤信息等规范这里就不详细介绍了。</p><h2 id="URL-设计规范"><a href="#URL-设计规范" class="headerlink" title="URL 设计规范"></a>URL 设计规范</h2><p>URL 为统一资源定位器,接口属于服务端资源,首先要通过 URL 定位到资源才能去访问,而通常一个完整的 URL 组成由以下几个部分构成:</p><figure class="highlight http"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">URI = scheme "://" host ":" port "/" path [ "?" query ][ "#" fragment ]</span><br></pre></td></tr></table></figure><ul><li>scheme: 指底层用的协议,如 http、https、ftp</li><li>host: 服务器的 IP 地址或者域名</li><li>port: 端口,http 默认为 80 端口</li><li>path: 访问资源的路径,就是各种 web 框架中定义的 route 路由</li><li>query: 查询字符串,为发送给服务器的参数,在这里更多发送数据分页、排序等参数。</li><li>fragment: 锚点,定位到页面的资源</li></ul><p>我们在设计 API 时 URL 的 path 是需要认真考虑的,而 RESTful 对 path 的设计做了一些规范,通常一个 RESTful API 的 path 组成如下:</p><figure class="highlight http"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">/{version}/{resources}/{resource_id}</span><br></pre></td></tr></table></figure><ul><li>version:API 版本号,有些版本号放置在头信息中也可以,通过控制版本号有利于应用迭代。</li><li>resources:资源,RESTful API 推荐用小写英文单词的复数形式。</li><li>resource_id:资源的 id,访问或操作该资源。</li></ul><p>当然,有时候可能资源级别较大,其下还可细分很多子资源也可以灵活设计 URL 的 path,例如:</p><figure class="highlight http"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">/{version}/{resources}/{resource_id}/{subresources}/{subresource_id}</span><br></pre></td></tr></table></figure><p>此外,有时可能增删改查无法满足业务要求,可以在 URL 末尾加上 action,例如</p><figure class="highlight http"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">/{version}/{resources}/{resource_id}/action</span><br></pre></td></tr></table></figure><p>其中 action 就是对资源的操作。</p><p>从大体样式了解 URL 路径组成之后,对于 RESTful API 的 URL 具体设计的规范如下:</p><ol><li>不用大写字母,所有单词使用英文且小写。</li><li>连字符用中杠<code>"-"</code>而不用下杠<code>"_"</code></li><li>正确使用 <code>"/"</code>表示层级关系, URL 的层级不要过深,并且越靠前的层级应该相对越稳定</li><li>结尾不要包含正斜杠分隔符<code>"/"</code></li><li><code>URL</code> 中不出现动词,用请求方式表示动作</li><li>资源表示用复数不要用单数</li><li>不要使用文件扩展名</li></ol><h2 id="HTTP动词"><a href="#HTTP动词" class="headerlink" title="HTTP动词"></a>HTTP动词</h2><p>在 RESTful API 中,不同的 HTTP 请求方法有各自的含义,这里就展示 GET, POST, PUT, DELETE 几种请求 API 的设计与含义分析。针对不同操作,具体的含义如下:</p><figure class="highlight http"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">GET /collection:从服务器查询资源的列表(数组)</span><br><span class="line">GET /collection/resource:从服务器查询单个资源</span><br><span class="line">POST /collection:在服务器创建新的资源</span><br><span class="line">PUT /collection/resource:更新服务器资源</span><br><span class="line">DELETE /collection/resource:从服务器删除资源</span><br></pre></td></tr></table></figure><p>在非 RESTful 风格的 API 中,我们通常使用 GET 请求和 POST 请求完成增删改查以及其他操作,查询和删除一般使用 GET 方式请求,更新和插入一般使用 POST 请求。从请求方式上无法知道 API 具体是干嘛的,所有在 URL 上都会有操作的动词来表示 API 进行的动作,例如:query,add,update,delete 等等。</p><p>而 RESTful 风格的 API 则要求在 URL 上都以名词的方式出现,从几种请求方式上就可以看出想要进行的操作,这点与非 RESTful 风格的 API 形成鲜明对比。</p><p>在谈及 GET,POST,PUT,DELETE 的时候,就必须提一下接口的安全性和幂等性,其中安全性是指方法不会修改资源状态,即读的为安全的,写的操作为非安全的。而幂等性的意思是操作一次和操作多次的最终效果相同,客户端重复调用也只返回同一个结果。</p><p>上述四个 HTTP 请求方法的安全性和幂等性如下:</p><table><thead><tr><th align="center">HTTP Method</th><th align="center">安全性</th><th align="center">幂等性</th><th align="center">解释</th></tr></thead><tbody><tr><td align="center">GET</td><td align="center">安全</td><td align="center">幂等</td><td align="center">读操作安全,查询一次多次结果一致</td></tr><tr><td align="center">POST</td><td align="center">非安全</td><td align="center">非幂等</td><td align="center">写操作非安全,每多插入一次都会出现新结果</td></tr><tr><td align="center">PUT</td><td align="center">非安全</td><td align="center">幂等</td><td align="center">写操作非安全,一次和多次更新结果一致</td></tr><tr><td align="center">DELETE</td><td align="center">非安全</td><td align="center">幂等</td><td align="center">写操作非安全,一次和多次删除结果一致</td></tr></tbody></table><h2 id="状态码和返回数据"><a href="#状态码和返回数据" class="headerlink" title="状态码和返回数据"></a>状态码和返回数据</h2><p>服务端处理完成后客户端也可能不知道具体成功了还是失败了,服务器响应时,包含<strong>状态码</strong>和<strong>返回数据</strong>两个部分。</p><h3 id="状态码"><a href="#状态码" class="headerlink" title="状态码"></a>状态码</h3><p>我们首先要正确使用各类状态码来表示该请求的处理执行结果。状态码主要分为五大类:</p><blockquote><p>1xx:相关信息<br>2xx:操作成功<br>3xx:重定向<br>4xx:客户端错误<br>5xx:服务器错误</p></blockquote><p>每一大类有若干小类,状态码的种类比较多,而主要常用状态码罗列在下面:</p><p>200 <code>OK - [GET]</code>:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。<br>201 <code>CREATED - [POST/PUT/PATCH]</code>:用户新建或修改数据成功。<br>202 <code>Accepted - [*]</code>:表示一个请求已经进入后台排队(异步任务)<br>204 <code>NO CONTENT - [DELETE]</code>:用户删除数据成功。<br>400 <code>INVALID REQUEST - [POST/PUT/PATCH]</code>:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。<br>401 <code>Unauthorized - [*]</code>:表示用户没有权限(令牌、用户名、密码错误)。<br>403 <code>Forbidden - [*]</code> 表示用户得到授权(与 401 错误相对),但是访问是被禁止的。<br>404 <code>NOT FOUND - [*]</code>:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。<br>406 <code>Not Acceptable - [GET]</code>:用户请求的格式不可得(比如用户请求 JSON 格式,但是只有 XML 格式)。<br>410 <code>Gone -[GET]</code>:用户请求的资源被永久删除,且不会再得到的。<br>422 <code>Unprocesable entity - [POST/PUT/PATCH]</code> 当创建一个对象时,发生一个验证错误。<br>500 <code>INTERNAL SERVER ERROR - [*]</code>:服务器发生错误,用户将无法判断发出的请求是否成功。</p><p><strong>返回结果</strong></p><p>针对不同操作,服务器向用户返回数据,而各个团队或公司封装的返回实体类也不同,但都返回 JSON 格式数据给客户端。</p><h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>RESTful 风格的 API 固然很好很规范,但大多数互联网公司并没有按照或者完全按照其规则来设计,因为 REST 是一种风格,而不是一种约束或规则,过于理想的 RESTful API 会付出太多的成本。</p><p>比如 RESTful API 也有一些缺点</p><p>比如操作方式繁琐,RESTful API 通常根据 GET、POST、PUT、DELETE 来区分操作资源的动作,而 HTTP Method 本身不可直接见,是隐藏的,而如果将动作放到 URL 的 path 上反而清晰可见,更利于团队的理解和交流。</p><p>并且有些浏览器对 GET,POST 之外的请求支持不太友好,还需要特殊额外的处理。</p><p>过分强调资源,而实际业务 API 可能有各种需求比较复杂,单单使用资源的增删改查可能并不能有效满足使用需求,强行使用 RESTful 风格 API 只会增加开发难度和成本。</p><p>所以,当你或你们的技术团队在设计 API 的时候,如果使用场景和 REST 风格很匹配,那么你们可以采用 RESTful 风格 API。但是如果业务需求和 RESTful 风格 API 不太匹配或者很麻烦,那也可以不用 RESTful 风格 API 或者可以借鉴一下,毕竟无论那种风格的 API 都是为了方便团队开发、协商以及管理,不能墨守成规。</p><p>不同的人对 RESTful API 可能有着不同的理解,但存在即合理,RESTful API 有着其鲜明的优势和特点,目前也是一种 API 设计的主要选型之一,所以掌握和理解 RESTful API 还是相当重要的!</p>]]></content>
<categories>
<category> 指南 </category>
</categories>
<tags>
<tag> 规范 </tag>
<tag> RESTful </tag>
<tag> 指南 </tag>
</tags>
</entry>
<entry>
<title>在 ThinkPHP5.1 中使用 blade 模板</title>
<link href="/2021/12/7e6b9fedc0f5/"/>
<url>/2021/12/7e6b9fedc0f5/</url>
<content type="html"><![CDATA[<p><code>composer</code> 安装 <code>blade</code> 包</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">composer require terranc/think-blade</span><br></pre></td></tr></table></figure><span id="more"></span><p>在 <code>config.php</code> 中修改对应配置</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">......</span><br><span class="line"></span><br><span class="line"><span class="string">'template'</span> => [</span><br><span class="line"> <span class="comment">// 模板引擎类型 支持 php think 支持扩展</span></span><br><span class="line"> <span class="string">'type'</span> => <span class="string">'Blade'</span>,</span><br><span class="line"> <span class="comment">// 模板路径</span></span><br><span class="line"> <span class="string">'view_path'</span> => <span class="string">''</span>,</span><br><span class="line"> <span class="comment">// 模板后缀</span></span><br><span class="line"> <span class="string">'view_suffix'</span> => <span class="string">'blade.php'</span>,</span><br><span class="line"> <span class="comment">// 模板文件名分隔符</span></span><br><span class="line"> <span class="string">'view_depr'</span> => DS,</span><br><span class="line"> <span class="comment">// 模板引擎普通标签开始标记</span></span><br><span class="line"> <span class="string">'tpl_begin'</span> => <span class="string">'{{'</span>,</span><br><span class="line"> <span class="comment">// 模板引擎普通标签结束标记</span></span><br><span class="line"> <span class="string">'tpl_end'</span> => <span class="string">'}}'</span>,</span><br><span class="line"> <span class="string">'tpl_raw_begin'</span> => <span class="string">'{!!'</span>,</span><br><span class="line"> <span class="string">'tpl_raw_end'</span> => <span class="string">'{!!'</span>,</span><br><span class="line"> <span class="comment">// 标签库标签开始标记</span></span><br><span class="line"> <span class="string">'taglib_begin'</span> => <span class="string">'{'</span>,</span><br><span class="line"> <span class="comment">// 标签库标签结束标记</span></span><br><span class="line"> <span class="string">'taglib_end'</span> => <span class="string">'}'</span>,</span><br><span class="line">],</span><br><span class="line"></span><br><span class="line">......</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>示例:</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><header id=<span class="string">"navbar"</span>></span><br><span class="line"> <div <span class="class"><span class="keyword">class</span>="<span class="title">row</span> <span class="title">navbar</span>-<span class="title">inner</span>"></span></span><br><span class="line"><span class="class"> <<span class="title">div</span> <span class="title">class</span>="<span class="title">col</span>-<span class="title">xs</span>-6 <span class="title">brand</span>-<span class="title">block</span>"></span></span><br><span class="line"><span class="class"> <<span class="title">h4</span>><<span class="title">a</span> <span class="title">href</span>="</span>{{ url(<span class="string">'/admin'</span>) }}<span class="string">"><img src="</span>/assets/admin/images/logo.png<span class="string">"></a> · 管理后台</span></span><br><span class="line"><span class="string"> </h4></span></span><br><span class="line"><span class="string"> <a href="</span>javascript:;<span class="string">" class="</span>cd_nav_trigger<span class="string">"><span></span></a></span></span><br><span class="line"><span class="string"> </div></span></span><br><span class="line"><span class="string"> <div class="</span>col-xs-<span class="number">6</span> text-right user-block<span class="string">"></span></span><br><span class="line"><span class="string"> 你好,{{ <span class="subst">$manage_user</span>->nickname }}({{ <span class="subst">$manage_user</span>->username }})</span></span><br><span class="line"><span class="string"> <span class="</span>gap-line<span class="string">"></span></span></span><br><span class="line"><span class="string"> <a href="</span>{{ url(<span class="string">'/manage/index/account'</span>) }}<span class="string">" class="</span>item<span class="string">">修改资料</a></span></span><br><span class="line"><span class="string"> <span class="</span>gap-line<span class="string">"></span></span></span><br><span class="line"><span class="string"> <a href="</span>{{ url(<span class="string">'/manage/start/logout'</span>) }}<span class="string">" class="</span>confirm item<span class="string">" title="</span>确认要退出吗?<span class="string">">退出</a></span></span><br><span class="line"><span class="string"> </div></span></span><br><span class="line"><span class="string"> </div></span></span><br><span class="line"><span class="string"></header></span></span><br><span class="line"><span class="string"></span></span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category> PHP </category>
</categories>
<tags>
<tag> PHP </tag>
<tag> ThinkPHP </tag>
</tags>
</entry>
<entry>
<title>CentOS7 下搭建 LAMP + FreeRadius + Daloradius Web 管理</title>
<link href="/2021/11/8e661f37ed3a/"/>
<url>/2021/11/8e661f37ed3a/</url>
<content type="html"><![CDATA[<blockquote><p>FreeRadius 服务官网:<a href="http://freeradius.org/">http://freeradius.org/</a><br>Daloradius Web 管理页面官网:<a href="https://sourceforge.net/projects/daloradius/">https://sourceforge.net/projects/daloradius/</a></p></blockquote><span id="more"></span><h1 id="创建-radius-数据库"><a href="#创建-radius-数据库" class="headerlink" title="创建 radius 数据库"></a>创建 radius 数据库</h1><p>创建 radius 数据库和用户名密码</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">mysql -h 127.0.0.1 -u root -p</span><br><span class="line"><span class="meta">#</span><span class="bash"> 下列在 mysql 命令行中操作</span></span><br><span class="line"><span class="meta">mysql></span><span class="bash"> create database radius;</span></span><br><span class="line"><span class="meta">mysql></span><span class="bash"> grant all on radius.* to radius@<span class="string">"localhost"</span> identified by <span class="string">"radpass"</span>;</span></span><br><span class="line"><span class="meta">mysql></span><span class="bash"> flush privileges;</span></span><br><span class="line"><span class="meta">mysql></span><span class="bash"> <span class="built_in">exit</span></span></span><br></pre></td></tr></table></figure><h1 id="安装-FreeRadius"><a href="#安装-FreeRadius" class="headerlink" title="安装 FreeRadius"></a>安装 FreeRadius</h1><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">yum -y install freeradius freeradius-utils freeradius-mysql</span><br><span class="line">systemctl start radiusd.service</span><br><span class="line">systemctl enable radiusd.service</span><br></pre></td></tr></table></figure><p>查看 Radius 使用的端口,然后添加 Radius 服务到防火墙中;也可以直接关闭防火墙</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">cat /usr/lib/firewalld/services/radius.xml</span><br><span class="line">firewall-cmd --state # 查看防火墙状态,启动状态才能添加规则</span><br><span class="line">firewall-cmd --add-service=radius --permanent # 添加 Radius 服务到 firewalld 防火墙中。</span><br><span class="line">firewall-cmd --reload # 让配置的防火墙策略立即生效</span><br><span class="line">firewall-cmd --list-services # 列举区域中启用的服务</span><br></pre></td></tr></table></figure><h1 id="配置-FreeRadius"><a href="#配置-FreeRadius" class="headerlink" title="配置 FreeRadius"></a>配置 FreeRadius</h1><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">cd /etc/raddb/mods-config/sql/main/mysql/</span><br><span class="line"><span class="meta">#</span><span class="bash"> 备份 setup.sql 配置文件</span></span><br><span class="line">mv setup.sql setup.sql-backup </span><br><span class="line"><span class="meta">#</span><span class="bash"> 过滤有 <span class="comment"># 注释符号的信息行</span></span></span><br><span class="line">grep -v "#" /etc/raddb/mods-config/sql/main/mysql/setup.sql-backup > /etc/raddb/mods-config/sql/main/mysql/setup.sql </span><br><span class="line"><span class="meta"></span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 进入数据库命令行操作</span></span><br><span class="line">mysql -h 127.0.0.1 -u root -p</span><br><span class="line"><span class="meta">mysql></span><span class="bash"> <span class="built_in">source</span> /etc/raddb/mods-config/sql/main/mysql/setup.sql</span> </span><br><span class="line"><span class="meta">mysql></span><span class="bash"> use radius</span> </span><br><span class="line"><span class="meta">mysql></span><span class="bash"> <span class="built_in">source</span> /etc/raddb/mods-config/sql/main/mysql/schema.sql</span> </span><br><span class="line"><span class="meta">mysql></span><span class="bash"> <span class="built_in">exit</span>;</span> </span><br></pre></td></tr></table></figure><p>导入完成后,可以看到如下的表结构</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">+------------------+</span><br><span class="line">| Tables_in_radius |</span><br><span class="line">+------------------+</span><br><span class="line">| nas |</span><br><span class="line">| radacct |</span><br><span class="line">| radcheck |</span><br><span class="line">| radgroupcheck |</span><br><span class="line">| radgroupreply |</span><br><span class="line">| radpostauth |</span><br><span class="line">| radreply |</span><br><span class="line">| radusergroup |</span><br><span class="line">+------------------+</span><br></pre></td></tr></table></figure><p><code>MySQL</code> 中表结构的定义<br>针对 <code>FreeRadius3</code>,数据表的设计和结构定义在下面的文件中:<code>/etc/raddb/sql/mysql/schema.sql</code><br>主数据库定义,8个表,包括<br><code>nas # 网络设备表</code><br><code>radacct # 计费情况表</code><br><code>radcheck # 用户检查信息表</code><br><code>radgroupcheck # 用户组检查信息表</code><br><code>radgroupreply # 用户组回复信息表</code><br><code>radpostauth # 认证后处理信息,可以包括认证请求成功和拒绝的记录。</code><br><code>radreply # 用户回复信息表</code><br><code>radusergroup # 用户和组关系表 </code></p><p>为 <code>/etc/raddb/mods-enabled</code> 创建软连接(涉及到后续 Radius 验证是否使用数据库)</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ln -s /etc/raddb/mods-available/sql /etc/raddb/mods-enabled/</span><br></pre></td></tr></table></figure><p>配置 <code>SQL</code> 模块 <code>/raddb/mods-available/sql</code>,并更改数据库连接参数,以适合自己的配置环境:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vi /etc/raddb/mods-available/sql</span><br></pre></td></tr></table></figure><figure class="highlight apacheconf"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">31</span> # driver = <span class="string">"rlm_sql_null"</span> # 注释掉这行</span><br><span class="line"><span class="attribute">32</span> driver = <span class="string">"rlm_sql_mysql"</span> # 新增这行,表示使用 MySQL 数据库</span><br><span class="line"><span class="attribute">88</span> # dialect = <span class="string">"sqlite"</span> # 注释掉这行</span><br><span class="line"><span class="attribute">89</span> dialect = <span class="string">"mysql"</span> # 修改连接类型为 MySQL</span><br><span class="line"><span class="attribute">90</span></span><br><span class="line"><span class="attribute">91</span> # Connection info:</span><br><span class="line"><span class="attribute">92</span> # (这里可以改成root账号) </span><br><span class="line"><span class="attribute">93</span> server = <span class="string">"localhost"</span></span><br><span class="line"><span class="attribute">94</span> port = <span class="number">3306</span></span><br><span class="line"><span class="attribute">95</span> login = <span class="string">"radius"</span></span><br><span class="line"><span class="attribute">96</span> password = <span class="string">"radpass"</span> # 对应数据库密码</span><br><span class="line"><span class="attribute">97</span></span><br><span class="line"><span class="attribute">98</span> # Database table configuration for everything except Oracle</span><br><span class="line"><span class="attribute">99</span> radius_db = <span class="string">"radius"</span></span><br><span class="line"><span class="attribute">247</span> read_clients = yes</span><br><span class="line"><span class="attribute">250</span> client_table = <span class="string">"nas"</span></span><br><span class="line">其他配置默认无需更改。</span><br></pre></td></tr></table></figure><p>然后,将 <code>/etc/raddb/mods-enabled/sql</code> 所属组更改为 <code>radiusd</code>:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">chgrp -h radiusd /etc/raddb/mods-enabled/sql</span><br></pre></td></tr></table></figure><p>添加启动服务,调整 <code>FreeRadius</code> 与 <code>MariaDB</code> 的启动顺序,<code>FreeRadius</code> 必须在 <code>MariaDB</code> 启动之后启动,在 <code>[Unit]</code> 部分,增加 <code>After=mariadb.service</code>,如下所示:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">systemctl enable radiusd.service</span><br><span class="line">vi /etc/systemd/system/multi-user.target.wants/radiusd.service</span><br></pre></td></tr></table></figure><figure class="highlight apacheconf"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">[<span class="attribute">Unit</span>]</span><br><span class="line"><span class="attribute">Description</span>=FreeRADIUS high performance RADIUS server.</span><br><span class="line"><span class="attribute">After</span>=syslog.target network.target ipa.service dirsrv.target krb<span class="number">5</span>kdc.service</span><br><span class="line"><span class="attribute">After</span>=mysqld.service</span><br></pre></td></tr></table></figure><p>添加客户端(路由器、交换机等设备)连接设置,ip 可以自由更改。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">mv /etc/raddb/clients.conf /etc/raddb/clients.conf-backup</span><br><span class="line">grep -v "#" /etc/raddb/clients.conf-backup > /etc/raddb/clients.conf # 过滤有 # 注释符号的信息行 </span><br><span class="line">vi /etc/raddb/clients.conf</span><br></pre></td></tr></table></figure><figure class="highlight apacheconf"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">client</span> localhost {</span><br><span class="line"> <span class="attribute">ipaddr</span> = <span class="number">127.0.0.1</span></span><br><span class="line"> <span class="attribute">proto</span> = *</span><br><span class="line"> <span class="attribute">secret</span> = testing<span class="number">123</span></span><br><span class="line"> <span class="attribute">require_message_authenticator</span> = no</span><br><span class="line"> <span class="attribute">limit</span> {</span><br><span class="line"> <span class="attribute">max_connections</span> = <span class="number">16</span></span><br><span class="line"> <span class="attribute">lifetime</span> = <span class="number">0</span></span><br><span class="line"> <span class="attribute">idle_timeout</span> = <span class="number">30</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>需要注意,上面配置的 <code>127.0.0.1</code> 主要用于测试,将来真正的客户端要按照下面的信息进行补充:<br>将来你真正的 <code>raidus</code> 客户端,如路由器、交换机等需要在这里配置 <code>ip</code> 信息,例如:</p><figure class="highlight apacheconf"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 这里的 x.x.x.x 就是交换机或者路由器等设备的IP地址</span></span><br><span class="line"><span class="attribute">client</span> x.x.x.x {</span><br><span class="line"> <span class="attribute">ipaddr</span> = x.x.x.x # 交换机或者路由器等设备的IP地址</span><br><span class="line"> <span class="attribute">secret</span> = xxxxxxxxxx # 自己定义的交换机或者路由器等设备和 radius 服务器的连接密码</span><br><span class="line"> <span class="comment"># require_message_authenticator = no # 这个可以注释掉,不用管</span></span><br><span class="line"> </span><br><span class="line"> <span class="attribute">client</span> <span class="number">0.0.0.0</span>/<span class="number">0</span> {</span><br><span class="line"> <span class="attribute">secret</span> = testing<span class="number">123</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>可以执行 <code>cat /var/log/radius/radius.log</code> 去查看 <code>radius</code> 服务的日志看有没有错误。</p><h1 id="安装-FreeRADIUS-管理界面-Daloradius"><a href="#安装-FreeRADIUS-管理界面-Daloradius" class="headerlink" title="安装 FreeRADIUS 管理界面 Daloradius"></a>安装 FreeRADIUS 管理界面 Daloradius</h1><p>进入 <code>Apache</code> 网站根目录,下载 <code>daloradius</code> 源文件</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">yum install -y php-pear-DB</span><br><span class="line">cd /var/www/html/</span><br><span class="line">wget https://github.com/lirantal/daloradius/archive/master.zip</span><br><span class="line">unzip master.zip</span><br><span class="line">mv daloradius-master/ daloradius</span><br></pre></td></tr></table></figure><p>下载 <code>daloradius-0.9-9.tar.gz</code>,解压后合并到 <code>daloradius</code> 文件夹中</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">wget http://liquidtelecom.dl.sourceforge.net/project/daloradius/daloradius/daloradius0.9-9/daloradius-0.9-9.tar.gz</span><br><span class="line">tar -zxvf daloradius-0.9-9.tar.gz</span><br><span class="line">mv daloradius-0.9-9 daloradius</span><br></pre></td></tr></table></figure><p>进入 <code>daloradius</code> 目录,导入 <code>daloradius</code> 数据库</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">cd daloradius</span><br><span class="line">mysql -h 127.0.0.1 -u root -p radius < contrib/db/fr2-mysql-daloradius-and-freeradius.sql</span><br><span class="line">mysql -h 127.0.0.1 -u root -p radius < contrib/db/mysql-daloradius.sql</span><br></pre></td></tr></table></figure><p>复制一份 <code>daloradius.conf.php.sample</code> 为 <code>daloradius.conf.php</code></p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mv /var/www/html/daloradius/library/daloradius.conf.php.sample /var/www/html/daloradius/library/daloradius.conf.php</span><br></pre></td></tr></table></figure><p>设置 <code>daloradius</code> 目录用户组和用户,设置 <code>daloradius.conf.php</code> 权限</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">chown -R apache:apache /var/www/html/daloradius/</span><br><span class="line">chmod 664 /var/www/html/daloradius/library/daloradius.conf.php</span><br></pre></td></tr></table></figure><p>设置 <code>daloradius</code> 数据库连接信息,打开 <code>daloradius.conf.php</code> 文件,修改 <code>CONFIG_DB_USER</code>,<code>CONFIG_DB_PASS</code>,<code>CONFIG_DB_NAME</code>。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vi /var/www/html/daloradius/library/daloradius.conf.php</span><br></pre></td></tr></table></figure><p>找到下列变量进行修改</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// (28-33行)</span></span><br><span class="line"><span class="variable">$configValues</span>[<span class="string">'CONFIG_DB_ENGINE'</span>] = <span class="string">'mysql'</span>;</span><br><span class="line"><span class="variable">$configValues</span>[<span class="string">'CONFIG_DB_HOST'</span>] = <span class="string">'127.0.0.1'</span>;</span><br><span class="line"><span class="variable">$configValues</span>[<span class="string">'CONFIG_DB_PORT'</span>] = <span class="string">'3306'</span>; <span class="comment">// 连接 mysql 数据库的端口</span></span><br><span class="line"><span class="variable">$configValues</span>[<span class="string">'CONFIG_DB_USER'</span>] = <span class="string">'root'</span>; <span class="comment">// 连接 mysql 数据库的账户</span></span><br><span class="line"><span class="variable">$configValues</span>[<span class="string">'CONFIG_DB_PASS'</span>] = <span class="string">' '</span>; <span class="comment">// 连接 mysql 数据库账号的密码</span></span><br><span class="line"><span class="variable">$configValues</span>[<span class="string">'CONFIG_DB_NAME'</span>] = <span class="string">'radius'</span>; <span class="comment">// 连接 mysql 的 radius 数据库</span></span><br><span class="line"><span class="comment">// 下面还有几个 daloradius 的 bug,默认配置中有几个文件路径和我们导入的不一样,把它改过来:</span></span><br><span class="line"><span class="variable">$configValues</span>[<span class="string">'CONFIG_FILE_RADIUS_PROXY'</span>] = <span class="string">'/etc/raddb/proxy.conf'</span>; <span class="comment">//(68行)</span></span><br><span class="line"><span class="variable">$configValues</span>[<span class="string">'CONFIG_PATH_DALO_VARIABLE_DATA'</span>] = <span class="string">'/var/www/html/daloradius/var'</span>; <span class="comment">// (70行)</span></span><br><span class="line"><span class="variable">$configValues</span>[<span class="string">'CONFIG_MAINT_TEST_USER_RADIUSSECRET'</span>] = <span class="string">'testing123'</span>; <span class="comment">// (88行) # 注意这条,要和 /etc/raddb/clients.conf 文件设置的secret = xxxxxxxxxx 值一样。</span></span><br></pre></td></tr></table></figure><p>配置完成后保存退出<br>重启 <code>radius</code>、<code>mysql</code>、<code>http</code> 服务</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">systemctl restart radiusd</span><br><span class="line">systemctl restart mysqld</span><br><span class="line">systemctl restart httpd</span><br></pre></td></tr></table></figure><p>如果提示: <code>Warning: radiusd.service changed on disk. Run ‘systemctl daemon-reload’ to reload units.</code> 执行以下的命令,没有上面提示就忽略此步</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">systemctl daemon-reload # 重新加载守护进程</span><br><span class="line">systemctl restart radiusd</span><br></pre></td></tr></table></figure><p>现在打开浏览器访问 <code>http://your ip address//</code> 就可以看到 <code>daloradius</code> 的界面了,默认登录的用户名和密码分别为 <code>username: administrator</code>, <code>password: radius</code><br>至此 <code>LAMP</code> + <code>FreeRadius</code> + <code>Daloradius Web</code> 管理界面已经安装成功,下面是 Web 界面汉化教程。</p><h1 id="Daloradius-中文版设置"><a href="#Daloradius-中文版设置" class="headerlink" title="Daloradius 中文版设置"></a>Daloradius 中文版设置</h1><p>进入 <code>Daloradius</code> 文件目录,修改 <code>config-lang.php</code>,添加中文选项:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">vi /var/www/html/daloradius/config-lang.php</span><br><span class="line"><span class="meta">#</span><span class="bash"> Simplified Chinese (79行)</span></span><br></pre></td></tr></table></figure><h1 id="RADIUS-操作命令"><a href="#RADIUS-操作命令" class="headerlink" title="RADIUS 操作命令"></a>RADIUS 操作命令</h1><ol><li>启动 <code>RADIUS</code> 服务(调试模式)</li></ol><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">systemctl stop radiusd</span><br><span class="line">radiusd -X</span><br><span class="line">``` </span><br><span class="line"></span><br><span class="line">2. 配置文件添加账号</span><br><span class="line"></span><br><span class="line">```shell</span><br><span class="line">vi /etc/raddb/users</span><br><span class="line"><span class="meta">#</span><span class="bash">steve Cleartext-Password := <span class="string">"testing"</span>(这个注释去掉)</span></span><br></pre></td></tr></table></figure><ol start="3"><li>允许外部访问</li></ol><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vi /etc/raddb/clients.conf</span><br></pre></td></tr></table></figure><figure class="highlight apacheconf"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">client</span> <span class="number">192.168.0.0</span>/<span class="number">24</span> { # 地址根据实际情况去配置</span><br><span class="line"> <span class="attribute">secret</span> = testing<span class="number">123</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><ol start="4"><li>远程客户端登录 <code>RADIUS</code> 服务器</li></ol><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">radtest steve testing 192.168.70.116 1812 testing123 </span><br></pre></td></tr></table></figure><p>访问成功会收到 <code>Access-Accept</code> 的提示</p>]]></content>
<categories>
<category> Linux </category>
</categories>
<tags>
<tag> Linux </tag>
<tag> FreeRadius </tag>
<tag> Radius </tag>
</tags>
</entry>
<entry>
<title>HTTP API 设计指南</title>
<link href="/2021/11/5a52d619023a/"/>
<url>/2021/11/5a52d619023a/</url>
<content type="html"><![CDATA[<h1 id="基础"><a href="#基础" class="headerlink" title="基础"></a>基础</h1><blockquote><p>基础部分概述了本指南其余部分所依据的设计原则。</p></blockquote><h2 id="隔离关键点"><a href="#隔离关键点" class="headerlink" title="隔离关键点"></a>隔离关键点</h2><p>通过隔离请求和响应生命周期中不同部分的关注点,在设计时保持简单。保持简单的规则可以让更多的注意力集中在更大和更难的问题上。</p><p>请求和响应用以解决特定资源或集合。使用路径(path)来表示身份,使用正文(body)来传输内容,使用头(header)来传达元数据。 查询参数(query param)也可以在边缘情况下用作传递标头信息的手段,但首选头信息,因为它们更灵活并且可以传达更多样的信息。</p><span id="more"></span><h2 id="需要安全连接"><a href="#需要安全连接" class="headerlink" title="需要安全连接"></a>需要安全连接</h2><p>需要使用 TLS 安全连接才能访问所有的 API,没有特例。试图弄清楚或解释什么时候可以使用 TLS 以及什么时候不能使用是不值得的。一切都需要并且只需要 TLS。</p><p>理想情况下,只需通过不响应 http 或端口 80 的请求来拒绝任何非 TLS 请求,以避免任何不安全的数据交换。在无法做到这一点的环境中,请使用403 Forbidden.</p><p>不鼓励重定向,因为它们允许含混/不良客户端行为而不会提供任何明确的收益。依赖重定向的客户端会增加服务器流量并使 TLS 变得无用,因为在第一次调用期间敏感数据已经暴露。</p><h2 id="在-Accepts-标头中要求版本控制"><a href="#在-Accepts-标头中要求版本控制" class="headerlink" title="在 Accepts 标头中要求版本控制"></a>在 Accepts 标头中要求版本控制</h2><p>版本控制和版本之间的转换可能是设计和维护 API 的更具挑战性的一个方面。因此,最好从一开始就制定一些机制来预防这种情况。</p><p>为了防止对用户造成意外、破坏性更改,最好要求为所有请求指定一个版本。应避免使用默认版本,因为它们在未来很难更改。</p><p>最好在标头中提供版本规范以及其他元数据,使用Accept带有自定义内容类型的标头,例如:</p><figure class="highlight http"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">Accept</span><span class="punctuation">: </span>application/vnd.heroku+json; version=3</span><br></pre></td></tr></table></figure><h2 id="支持缓存的-ETag"><a href="#支持缓存的-ETag" class="headerlink" title="支持缓存的 ETag"></a>支持缓存的 ETag</h2><p>在所有响应中包含一个 <code>ETag</code> 标头,标识返回资源的特定版本。 这允许用户缓存资源并使用 <code>If-None-Match</code> 标头中使用具有此值的请求来确定是否应该更新缓存。</p><h2 id="为自省提供请求-ID"><a href="#为自省提供请求-ID" class="headerlink" title="为自省提供请求 ID"></a>为自省提供请求 ID</h2><p>在每个 API 响应中包含一个 <code>Request-Id</code> 标头,填充一个 UUID 值。 通过在客户端、服务器和任何支持服务上记录这些值,它提供了一种跟踪、诊断和调试请求的机制。</p><h2 id="在具有范围的请求之间划分大响应"><a href="#在具有范围的请求之间划分大响应" class="headerlink" title="在具有范围的请求之间划分大响应"></a>在具有范围的请求之间划分大响应</h2><p>应使用 <code>Range</code> 标头指定何时有更多数据可用以及如何检索数据,从而将大型响应拆分为多个请求。</p><h1 id="请求"><a href="#请求" class="headerlink" title="请求"></a>请求</h1><blockquote><p>请求部分概述了API请求的模式。</p></blockquote><h2 id="接受请求正文中的序列化-JSON"><a href="#接受请求正文中的序列化-JSON" class="headerlink" title="接受请求正文中的序列化 JSON"></a>接受请求正文中的序列化 JSON</h2><p>接受序列化JSON在 <code>PUT/PATCH/POST</code> 请求机构中,代替或除了的 <code>form-encoded</code> 的数据。 这创建了与 JSON 序列化响应主体的对称性,例如:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span><span class="bash"> curl -X POST https://service.com/apps \</span></span><br><span class="line"><span class="bash"> -H <span class="string">"Content-Type: application/json"</span> \</span></span><br><span class="line"><span class="bash"> -d <span class="string">'{"name": "demoapp"}'</span></span></span><br><span class="line"></span><br><span class="line">{</span><br><span class="line"> "id": "01234567-89ab-cdef-0123-456789abcdef",</span><br><span class="line"> "name": "demoapp",</span><br><span class="line"> "owner": {</span><br><span class="line"> "email": "[email protected]",</span><br><span class="line"> "id": "01234567-89ab-cdef-0123-456789abcdef"</span><br><span class="line"> },</span><br><span class="line"> ...</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="资源名称"><a href="#资源名称" class="headerlink" title="资源名称"></a>资源名称</h2><p>使用复数形式的资源名称,除非相关资源是系统内的单例(例如,系统的整体状态可能是 <code>/status</code>)。这使它在您引用特定资源的方式上保持一致。</p><h2 id="操作"><a href="#操作" class="headerlink" title="操作"></a>操作</h2><p>首选不需要特殊操作的端点配置。在需要指定操作的情况下,用 <code>actions</code> 前缀清楚地描述它们:</p><figure class="highlight http"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">/resources/:resource/actions/:action</span><br></pre></td></tr></table></figure><p>例如停止特定的运行:</p><figure class="highlight http"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">/runs/{run_id}/actions/stop</span><br></pre></td></tr></table></figure><p>还应尽量减少对集合的操作。在需要时,他们应该使用顶级操作描述来避免命名空间冲突并清楚地显示操作范围:</p><figure class="highlight http"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">/actions/:action/resources</span><br></pre></td></tr></table></figure><p>例如重新启动所有服务器:</p><figure class="highlight http"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">/actions/restart/servers</span><br></pre></td></tr></table></figure><h2 id="使用一致的路径格式"><a href="#使用一致的路径格式" class="headerlink" title="使用一致的路径格式"></a>使用一致的路径格式</h2><h3 id="小写路径和属性"><a href="#小写路径和属性" class="headerlink" title="小写路径和属性"></a>小写路径和属性</h3><p>使用小写和破折号分隔的路径名,与主机名对齐,例如:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">service-api.com/users</span><br><span class="line">service-api.com/app-setups</span><br></pre></td></tr></table></figure><p>小写属性也是如此,但使用下划线分隔符,以便在 JavaScript 中输入属性名称时无需引号,例如:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">service_class: "first"</span><br></pre></td></tr></table></figure><h3 id="为方便起见,支持非id间接引用"><a href="#为方便起见,支持非id间接引用" class="headerlink" title="为方便起见,支持非id间接引用"></a>为方便起见,支持非id间接引用</h3><p>在某些情况下,最终用户可能不方便提供 ID 来标识资源。例如,用户可能会想到 Heroku 的应用程序名称,但该应用程序可能由 UUID 标识。 在这些情况下,您可能希望同时接受 id 或名称,例如:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span><span class="bash"> curl https://service.com/apps/{app_id_or_name}</span></span><br><span class="line"><span class="meta">$</span><span class="bash"> curl https://service.com/apps/97addcf0-c182</span></span><br><span class="line"><span class="meta">$</span><span class="bash"> curl https://service.com/apps/www-prod</span></span><br></pre></td></tr></table></figure><p>不要只接受名称而排除 ID。</p><h3 id="最小化路径嵌套"><a href="#最小化路径嵌套" class="headerlink" title="最小化路径嵌套"></a>最小化路径嵌套</h3><p>在具有嵌套父/子资源关系的数据模型中,路径可能会深度嵌套,例如:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">/orgs/{org_id}/apps/{app_id}/dynos/{dyno_id}</span><br></pre></td></tr></table></figure><p>通过优先在根路径上定位资源来限制嵌套深度。使用嵌套来指示范围集合。例如,对于上面的 dyno 属于一个应用程序属于一个组织的情况:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">/orgs/{org_id}</span><br><span class="line">/orgs/{org_id}/apps</span><br><span class="line">/apps/{app_id}</span><br><span class="line">/apps/{app_id}/dynos</span><br><span class="line">/dynos/{dyno_id}</span><br></pre></td></tr></table></figure><h2 id="响应"><a href="#响应" class="headerlink" title="响应"></a>响应</h2><p>响应部分提供了 API 响应模式的概述。</p><h3 id="返回适当的状态代码"><a href="#返回适当的状态代码" class="headerlink" title="返回适当的状态代码"></a>返回适当的状态代码</h3><p>为每个响应返回适当的 HTTP 状态代码。成功的响应应根据本指南进行编码:</p><ul><li><p><code>200</code>:请求成功了<code>GET</code>,<code>POST</code>,<code>DELETE</code>,或 <code>PATCH</code> 调用同步完成,或 <code>PUT</code> 调用同步更新现有资源</p></li><li><p><code>201</code>:请求成功 <code>POST</code>,或 <code>PUT</code> 同步创建新资源的调用。提供指向新创建资源的”位置”标头也是最佳实践。 这在 <code>POST</code> 上下文中特别有用,因为新资源将具有与原始请求不同的 <code>URL</code></p></li><li><p><code>202</code>:接受请求的 <code>POST</code>,<code>PUT</code>,<code>DELETE</code>,或 <code>PATCH</code> 通话将被异步处理</p></li><li><p><code>206</code>:请求成功 <code>GET</code>,但只返回了部分响应:见上面的范围<br>注意认证和授权错误码的使用:</p></li><li><p><code>401 Unauthorized</code>:请求失败,因为用户未通过身份验证</p></li><li><p><code>403 Forbidden</code>:请求失败,因为用户无权访问特定资源<br>出现错误时返回合适的代码以提供附加信息:</p></li><li><p><code>422 Unprocessable Entity</code>:您的请求已被理解,但包含无效参数</p></li><li><p><code>429 Too Many Requests</code>: 你被限速了,稍后重试</p></li><li><p><code>500 Internal Server Error</code>:服务器出现问题,检查状态站点和/或报告问题</p></li></ul><h3 id="在可用的情况下提供完整的资源"><a href="#在可用的情况下提供完整的资源" class="headerlink" title="在可用的情况下提供完整的资源"></a>在可用的情况下提供完整的资源</h3><p>尽可能在响应中提供完整的资源表示(即具有所有属性的对象)。始终提供 200 和 201 响应的完整资源,包括 <code>PUT/PATCH</code> 和 <code>DELETE</code> 请求,例如:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span><span class="bash"> curl -X DELETE \</span></span><br><span class="line"><span class="bash"> https://service.com/apps/1f9b/domains/0fd4</span></span><br><span class="line"></span><br><span class="line">HTTP/1.1 200 OK</span><br><span class="line">Content-Type: application/json;charset=utf-8</span><br><span class="line">...</span><br><span class="line">{</span><br><span class="line"> "created_at": "2012-01-01T12:00:00Z",</span><br><span class="line"> "hostname": "subdomain.example.com",</span><br><span class="line"> "id": "01234567-89ab-cdef-0123-456789abcdef",</span><br><span class="line"> "updated_at": "2012-01-01T12:00:00Z"</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>202 响应将不包括完整的资源表示,例如:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span><span class="bash"> curl -X DELETE \</span></span><br><span class="line"><span class="bash"> https://service.com/apps/1f9b/dynos/05bd</span></span><br><span class="line"></span><br><span class="line">HTTP/1.1 202 Accepted</span><br><span class="line">Content-Type: application/json;charset=utf-8</span><br><span class="line">...</span><br><span class="line">{}</span><br></pre></td></tr></table></figure><h3 id="提供资源-UU-ID"><a href="#提供资源-UU-ID" class="headerlink" title="提供资源 (UU)ID"></a>提供资源 (UU)ID</h3><p><code>id</code> 默认给每个资源一个属性。除非您有充分的理由不使用 UUID,否则请使用 UUID。不要使用在服务实例或服务中的其他资源之间不是全局唯一的 ID,尤其是自动递增的 ID。</p><p>以小写8-4-4-4-12格式呈现 UUID ,例如:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">"id": "01234567-89ab-cdef-0123-456789abcdef"</span><br></pre></td></tr></table></figure><h3 id="提供标准时间戳"><a href="#提供标准时间戳" class="headerlink" title="提供标准时间戳"></a>提供标准时间戳</h3><p>提供 <code>created_at</code> 和 <code>updated_at</code> 时间戳在默认情况下,如:</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"><span class="comment">// ...</span></span><br><span class="line"><span class="attr">"created_at"</span>: <span class="string">"2012-01-01T12:00:00Z"</span>,</span><br><span class="line"><span class="attr">"updated_at"</span>: <span class="string">"2012-01-01T13:00:00Z"</span>,</span><br><span class="line"><span class="comment">// ...</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>这些时间戳对于某些资源可能没有意义,在这种情况下可以省略它们。</p><h3 id="提供标准响应类型"><a href="#提供标准响应类型" class="headerlink" title="提供标准响应类型"></a>提供标准响应类型</h3><p>本文档描述了每种 JSON 基本数据类型的可接受值。</p><h4 id="字符串"><a href="#字符串" class="headerlink" title="字符串"></a>字符串</h4><ul><li>可接受的值:<ul><li>字符串</li><li>null</li></ul></li></ul><p>例如:</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">[</span><br><span class="line"> {</span><br><span class="line"> <span class="attr">"description"</span>: <span class="string">"very descriptive description."</span></span><br><span class="line"> },</span><br><span class="line"> {</span><br><span class="line"> <span class="attr">"description"</span>: <span class="literal">null</span></span><br><span class="line"> },</span><br><span class="line">]</span><br></pre></td></tr></table></figure><h4 id="布尔值"><a href="#布尔值" class="headerlink" title="布尔值"></a>布尔值</h4><ul><li>可接受的值:<ul><li>true</li><li>false</li></ul></li></ul><p>例如:</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">[</span><br><span class="line"> {</span><br><span class="line"> <span class="attr">"provisioned_licenses"</span>: <span class="literal">true</span></span><br><span class="line"> },</span><br><span class="line"> {</span><br><span class="line"> <span class="attr">"provisioned_licenses"</span>: <span class="literal">false</span></span><br><span class="line"> },</span><br><span class="line">]</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="数字"><a href="#数字" class="headerlink" title="数字"></a>数字</h4><ul><li>可接受的值:<ul><li>数字</li><li>null</li></ul></li></ul><p>注意:一些 JSON 解析器会将精度超过 15 位小数的数字作为字符串返回。 如果您需要大于 15 位小数的精度,请始终为该值返回一个字符串。如果不是,请将这些字符串转换为数字,以便 API 的使用者始终知道期望的值类型。</p><p>例如:</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">[</span><br><span class="line"> {</span><br><span class="line"> <span class="attr">"average"</span>: <span class="number">27.123</span></span><br><span class="line"> },</span><br><span class="line"> {</span><br><span class="line"> <span class="attr">"average"</span>: <span class="number">12.123456789012</span></span><br><span class="line"> },</span><br><span class="line">]</span><br></pre></td></tr></table></figure><h4 id="数组"><a href="#数组" class="headerlink" title="数组"></a>数组</h4><ul><li>可接受的值:<ul><li>数组</li></ul></li></ul><p>注意:返回空数组而不是NULL当数组中没有值时。</p><p>例如:</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">[</span><br><span class="line"> {</span><br><span class="line"> <span class="attr">"child_ids"</span>: [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>],</span><br><span class="line"> },</span><br><span class="line"> {</span><br><span class="line"> <span class="attr">"child_ids"</span>: [],</span><br><span class="line"> }</span><br><span class="line">]</span><br></pre></td></tr></table></figure><h4 id="对象"><a href="#对象" class="headerlink" title="对象"></a>对象</h4><ul><li>可接受的值:<ul><li>对象</li><li>null</li></ul></li></ul><p>例如:</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">[</span><br><span class="line"> {</span><br><span class="line"> <span class="attr">"name"</span>: <span class="string">"service-production"</span>,</span><br><span class="line"> <span class="attr">"owner"</span>: {</span><br><span class="line"> <span class="attr">"id"</span>: <span class="string">"5d8201b0..."</span></span><br><span class="line"> }</span><br><span class="line"> },</span><br><span class="line"> {</span><br><span class="line"> <span class="attr">"name"</span>: <span class="string">"service-staging"</span>,</span><br><span class="line"> <span class="attr">"owner"</span>: <span class="literal">null</span></span><br><span class="line"> }</span><br><span class="line">]</span><br></pre></td></tr></table></figure><h3 id="使用-ISO8601-格式的-UTC-时间"><a href="#使用-ISO8601-格式的-UTC-时间" class="headerlink" title="使用 ISO8601 格式的 UTC 时间"></a>使用 ISO8601 格式的 UTC 时间</h3><p>仅接受和返回 UTC 时间。ISO8601 格式的渲染时间,例如:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">"finished_at": "2012-01-01T12:00:00Z"</span><br></pre></td></tr></table></figure><h3 id="嵌套外键关系"><a href="#嵌套外键关系" class="headerlink" title="嵌套外键关系"></a>嵌套外键关系</h3><p>使用嵌套对象序列化外键引用,例如:</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> <span class="attr">"name"</span>: <span class="string">"service-production"</span>,</span><br><span class="line"> <span class="attr">"owner"</span>: {</span><br><span class="line"> <span class="attr">"id"</span>: <span class="string">"5d8201b0..."</span></span><br><span class="line"> },</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>而不是例如:</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> <span class="attr">"name"</span>: <span class="string">"service-production"</span>,</span><br><span class="line"> <span class="attr">"owner_id"</span>: <span class="string">"5d8201b0..."</span>,</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>这种方法可以内联有关相关资源的更多信息,而无需更改响应的结构或引入更多顶级响应字段,例如:</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> <span class="attr">"name"</span>: <span class="string">"service-production"</span>,</span><br><span class="line"> <span class="attr">"owner"</span>: {</span><br><span class="line"> <span class="attr">"id"</span>: <span class="string">"5d8201b0..."</span>,</span><br><span class="line"> <span class="attr">"email"</span>: <span class="string">"[email protected]"</span></span><br><span class="line"> },</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>嵌套外键关系时,请使用完整记录或仅使用外键。提供字段的子集可能会导致意外和混乱,使不同操作和端点之间更有可能出现不一致。</p><p>为避免不一致和混淆,请序列化:</p><ul><li>仅外键 - 可以查找完整记录的值,例如<code>id</code>,<code>slug</code>,<code>email</code>。</li><li>完整记录, 所有字段(这将是”嵌入记录”)</li></ul><h3 id="生成结构化错误"><a href="#生成结构化错误" class="headerlink" title="生成结构化错误"></a>生成结构化错误</h3><p>针对错误生成一致、结构化的响应主体。包括一个机器可读的错误 <code>id</code>,一个人类可读的错误 <code>message</code>,以及可选的url指向客户端关于错误和如何解决它的更多信息,例如:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">HTTP/1.1 429 Too Many Requests</span><br></pre></td></tr></table></figure><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> <span class="attr">"id"</span>: <span class="string">"rate_limit"</span>,</span><br><span class="line"> <span class="attr">"message"</span>: <span class="string">"Account reached its API rate limit."</span>,</span><br><span class="line"> <span class="attr">"url"</span>: <span class="string">"https://docs.service.com/rate-limits"</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>记录您的错误格式和 <code>id</code> 客户可能遇到的可能错误。</p><h3 id="显示速率限制状态"><a href="#显示速率限制状态" class="headerlink" title="显示速率限制状态"></a>显示速率限制状态</h3><p>来自客户端的速率限制请求,以保护服务的健康并为其他客户端保持高服务质量。 您可以使用 <a href="http://en.wikipedia.org/wiki/Token_bucket">令牌桶算法</a> 来量化请求限制。</p><p>返回 <code>RateLimit-Remaining</code> 响应标头中每个请求的剩余请求令牌数。</p><h3 id="在所有响应中保持-JSON-缩小"><a href="#在所有响应中保持-JSON-缩小" class="headerlink" title="在所有响应中保持 JSON 缩小"></a>在所有响应中保持 JSON 缩小</h3><p>额外的空白为请求增加了不必要的响应大小,许多供人类消费的客户端会自动“美化”JSON 输出。最好保持 JSON 响应最小化,例如:</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">{<span class="attr">"beta"</span>:<span class="literal">false</span>,<span class="attr">"email"</span>:<span class="string">"[email protected]"</span>,<span class="attr">"id"</span>:<span class="string">"01234567-89ab-cdef-0123-456789abcdef"</span>,<span class="attr">"last_login"</span>:<span class="string">"2012-01-01T12:00:00Z"</span>,<span class="attr">"created_at"</span>:<span class="string">"2012-01-01T12:00:00Z"</span>,<span class="attr">"updated_at"</span>:<span class="string">"2012-01-01T12:00:00Z"</span>}</span><br></pre></td></tr></table></figure><p>而不是例如:</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> <span class="attr">"beta"</span>: <span class="literal">false</span>,</span><br><span class="line"> <span class="attr">"email"</span>: <span class="string">"[email protected]"</span>,</span><br><span class="line"> <span class="attr">"id"</span>: <span class="string">"01234567-89ab-cdef-0123-456789abcdef"</span>,</span><br><span class="line"> <span class="attr">"last_login"</span>: <span class="string">"2012-01-01T12:00:00Z"</span>,</span><br><span class="line"> <span class="attr">"created_at"</span>: <span class="string">"2012-01-01T12:00:00Z"</span>,</span><br><span class="line"> <span class="attr">"updated_at"</span>: <span class="string">"2012-01-01T12:00:00Z"</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>您可以考虑通过查询参数(例如 <code>?pretty=true</code>)或通过 <code>Accept</code> 标头参数(例如 <code>Accept: application/vnd.heroku+json; version=3; indent=4;</code>)为客户端提供一种可选的方式来检索更详细的响应。</p><h1 id="工件"><a href="#工件" class="headerlink" title="工件"></a>工件</h1><p>工件部分描述了我们用来管理和讨论 API 设计和模式的物理对象。</p><h2 id="提供机器可读的-JSON-模式"><a href="#提供机器可读的-JSON-模式" class="headerlink" title="提供机器可读的 JSON 模式"></a>提供机器可读的 JSON 模式</h2><p>提供机器可读的模式来准确指定您的 API。使用 <a href="https://github.com/interagent/prmd">prmd</a> 来管理您的架构,并确保它使用了 <code>prmd verify</code> 验证。</p><h2 id="提供人类可读的文档"><a href="#提供人类可读的文档" class="headerlink" title="提供人类可读的文档"></a>提供人类可读的文档</h2><p>提供人类可读的文档,客户开发人员可以使用这些文档来理解您的 API。</p><p>如果您如上所述使用 prmd 创建架构,您可以使用 <code>prmd doc</code> 轻松地为所有端点生成 Markdown 文档。</p><p>除了端点详细信息外,还提供包含以下信息的 API 概述:</p><ul><li>身份验证,包括获取和使用身份验证令牌。</li><li>API 稳定性和版本控制,包括如何选择所需的 API 版本。</li><li>常见的请求和响应头。</li><li>错误的序列化格式。</li><li>将 API 与不同语言的客户端一起使用的示例。</li></ul><h2 id="提供可执行示例"><a href="#提供可执行示例" class="headerlink" title="提供可执行示例"></a>提供可执行示例</h2><p>提供可执行示例,用户可以直接在其终端中键入以查看 API 调用。在最大程度上,这些示例应该逐字可用,以最大限度地减少用户尝试 API 所需的工作量,例如:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span><span class="bash"> <span class="built_in">export</span> TOKEN=... <span class="comment"># acquire from dashboard</span></span></span><br><span class="line"><span class="meta">$</span><span class="bash"> curl -is https://<span class="variable">$TOKEN</span>@service.com/users</span></span><br></pre></td></tr></table></figure><h2 id="描述稳定性"><a href="#描述稳定性" class="headerlink" title="描述稳定性"></a>描述稳定性</h2><p>根据 API 的成熟度和稳定性来描述您的 API 或其各种端点的稳定性,例如使用原型/开发/生产标志。</p><p>一旦您的 API 被声明为生产就绪且稳定,请不要在该 API 版本中进行向后不兼容的更改。如果您需要进行向后不兼容的更改,请创建一个版本号递增的新 API。</p>]]></content>
<categories>
<category> 指南 </category>
</categories>
<tags>
<tag> API </tag>
<tag> HTTP </tag>
<tag> RESTful </tag>
<tag> 设计指南 </tag>
</tags>
</entry>
<entry>
<title>中文文案排版指南</title>
<link href="/2021/11/7be1c7eb6db2/"/>
<url>/2021/11/7be1c7eb6db2/</url>
<content type="html"><![CDATA[<h1 id="中文文案排版指南"><a href="#中文文案排版指南" class="headerlink" title="中文文案排版指南"></a>中文文案排版指南</h1><p>統一中文文案、排版的相關用法,降低團隊成員之間的溝通成本,增強網站氣質。</p><hr><h2 id="空格"><a href="#空格" class="headerlink" title="空格"></a>空格</h2><blockquote><p>「有研究顯示,打字的時候不喜歡在中文和英文之間加空格的人,感情路都走得很辛苦,有七成的比例會在 34 歲的時候跟自己不愛的人結婚,而其餘三成的人最後只能把遺產留給自己的貓。畢竟愛情跟書寫都需要適時地留白。</p><p>與大家共勉之。」——<a href="https://github.com/vinta/pangu.js">vinta/paranoid-auto-spacing</a></p></blockquote><span id="more"></span><h3 id="中英文之間需要增加空格"><a href="#中英文之間需要增加空格" class="headerlink" title="中英文之間需要增加空格"></a>中英文之間需要增加空格</h3><p>正確:</p><blockquote><p>在 LeanCloud 上,數據存儲是圍繞 <code>AVObject</code> 進行的。</p></blockquote><p>錯誤:</p><blockquote><p>在LeanCloud上,數據存儲是圍繞<code>AVObject</code>進行的。</p></blockquote><blockquote><p>在 LeanCloud上,數據存儲是圍繞<code>AVObject</code> 進行的。</p></blockquote><p>完整的正確用法:</p><blockquote><p>在 LeanCloud 上,數據儲存是圍繞 <code>AVObject</code> 進行的。每個 <code>AVObject</code> 都包含了與 JSON 兼容的 key-value 對應的數據。數據是 schema-free 的,你不需要在每個 <code>AVObject</code> 上提前指定存在哪些键,只要直接設定對應的 key-value 即可。</p></blockquote><p>例外:「豆瓣FM」等產品名詞,按照官方所定義的格式書寫。</p><h3 id="中文與數字之間需要增加空格"><a href="#中文與數字之間需要增加空格" class="headerlink" title="中文與數字之間需要增加空格"></a>中文與數字之間需要增加空格</h3><p>正確:</p><blockquote><p>今天出去買菜花了 5000 元。</p></blockquote><p>錯誤:</p><blockquote><p>今天出去買菜花了 5000元。</p></blockquote><blockquote><p>今天出去買菜花了5000元。</p></blockquote><h3 id="數字與單位之間需要增加空格"><a href="#數字與單位之間需要增加空格" class="headerlink" title="數字與單位之間需要增加空格"></a>數字與單位之間需要增加空格</h3><p>正確:</p><blockquote><p>我家的光纖入屋寬頻有 10 Gbps,SSD 一共有 20 TB。</p></blockquote><p>錯誤:</p><blockquote><p>我家的光纖入屋寬頻有 10Gbps,SSD 一共有 20TB。</p></blockquote><p>例外:度/百分比與數字之間不需要增加空格:</p><p>正確:</p><blockquote><p>今天是 233° 的高溫。</p></blockquote><blockquote><p>新 MacBook Pro 有 15% 的 CPU 性能提升。</p></blockquote><p>錯誤:</p><blockquote><p>今天是 233 ° 的高溫。</p></blockquote><blockquote><p>新 MacBook Pro 有 15 % 的 CPU 性能提升。</p></blockquote><h3 id="全形標點與其他字符之間不加空格"><a href="#全形標點與其他字符之間不加空格" class="headerlink" title="全形標點與其他字符之間不加空格"></a>全形標點與其他字符之間不加空格</h3><p>正確:</p><blockquote><p>剛剛買了一部 iPhone,好開心!</p></blockquote><p>錯誤:</p><blockquote><p>剛剛買了一部 iPhone ,好開心!</p></blockquote><blockquote><p>剛剛買了一部 iPhone, 好開心!</p></blockquote><h3 id="text-spacing-to-the-rescue"><a href="#text-spacing-to-the-rescue" class="headerlink" title="text-spacing to the rescue?"></a><code>text-spacing</code> to the rescue?</h3><p>CSS Text Module Level 4 的 <a href="https://www.w3.org/TR/css-text-4/#text-spacing-property"><code>text-spacing</code></a> 和 Microsoft 的 <a href="https://msdn.microsoft.com/library/ms531164(v=vs.85).aspx"><code>-ms-text-autospace</code></a> 可以實現自動為中英文之間增加空白。不過目前並未普及,另外在其他應用場景,例如 macOS、iOS、Windows 等用戶介面目前并不存在這個特性,所以請繼續保持隨手加空格的習慣。</p><h2 id="標點符號"><a href="#標點符號" class="headerlink" title="標點符號"></a>標點符號</h2><h3 id="不重複使用標點符號"><a href="#不重複使用標點符號" class="headerlink" title="不重複使用標點符號"></a>不重複使用標點符號</h3><p>正確:</p><blockquote><p>德國隊竟然戰勝了巴西隊!</p></blockquote><blockquote><p>她竟然對你說「喵」?!</p></blockquote><p>錯誤:</p><blockquote><p>德國隊竟然戰勝了巴西隊!!</p></blockquote><blockquote><p>德國隊竟然戰勝了巴西隊!!!!!!!!</p></blockquote><blockquote><p>她竟然對你說「喵」??!!</p></blockquote><blockquote><p>她竟然對你說「喵」?!?!??!!</p></blockquote><h2 id="全形和半形"><a href="#全形和半形" class="headerlink" title="全形和半形"></a>全形和半形</h2><p>不明白什麼是全形(全角)與半形(半角)符號?請查看維基百科條目『<a href="https://zh.wikipedia.org/wiki/%E5%85%A8%E5%BD%A2%E5%92%8C%E5%8D%8A%E5%BD%A2">全形和半形</a>』。</p><h3 id="使用全形中文標點"><a href="#使用全形中文標點" class="headerlink" title="使用全形中文標點"></a>使用全形中文標點</h3><p>正確:</p><blockquote><p>嗨!你知道嘛?今天前台的小妹跟我說「喵」了哎!</p></blockquote><blockquote><p>核磁共振成像(NMRI)是什麼原理都不知道?JFGI!</p></blockquote><p>錯誤:</p><blockquote><p>嗨! 你知道嘛? 今天前台的小妹跟我說 “喵” 了哎!</p></blockquote><blockquote><p>嗨!你知道嘛?今天前台的小妹跟我說”喵”了哎!</p></blockquote><blockquote><p>核磁共振成像 (NMRI) 是什麼原理都不知道? JFGI!</p></blockquote><blockquote><p>核磁共振成像(NMRI)是什麼原理都不知道?JFGI!</p></blockquote><h3 id="數字使用半形字符"><a href="#數字使用半形字符" class="headerlink" title="數字使用半形字符"></a>數字使用半形字符</h3><p>正確:</p><blockquote><p>這件蛋糕只賣 1000 元。</p></blockquote><p>錯誤:</p><blockquote><p>這件蛋糕只賣 1000 元。</p></blockquote><p>例外:在設計稿、宣傳海報中如出現極少量數字的情形時,為方便文字對齊,是可以使用全形數字的。</p><h3 id="遇到完整的英文整句、特殊名詞,其內容使用半形標點"><a href="#遇到完整的英文整句、特殊名詞,其內容使用半形標點" class="headerlink" title="遇到完整的英文整句、特殊名詞,其內容使用半形標點"></a>遇到完整的英文整句、特殊名詞,其內容使用半形標點</h3><p>正確:</p><blockquote><p>賈伯斯那句話是怎麼說的?「Stay hungry, stay foolish.」</p></blockquote><blockquote><p>推薦你閱讀《Hackers & Painters: Big Ideas from the Computer Age》,非常的有趣。</p></blockquote><p>錯誤:</p><blockquote><p>賈伯斯那句話是怎麼說的?「Stay hungry,stay foolish。」</p></blockquote><blockquote><p>推薦你閱讀《Hackers&Painters:Big Ideas from the Computer Age》,非常的有趣。</p></blockquote><h2 id="名詞"><a href="#名詞" class="headerlink" title="名詞"></a>名詞</h2><h3 id="專有名詞使用正確的大小寫"><a href="#專有名詞使用正確的大小寫" class="headerlink" title="專有名詞使用正確的大小寫"></a>專有名詞使用正確的大小寫</h3><p>大小寫相關用法原屬於英文書寫範疇,不屬於本 wiki 討論內容,在這裡只對部分易錯用法進行簡述。</p><p>正確:</p><blockquote><p>使用 GitHub 登錄</p></blockquote><blockquote><p>我們的客戶有 GitHub、Foursquare、Microsoft Corporation、Google、Facebook, Inc.。</p></blockquote><p>錯誤:</p><blockquote><p>使用 github 登錄</p></blockquote><blockquote><p>使用 GITHUB 登錄</p></blockquote><blockquote><p>使用 Github 登錄</p></blockquote><blockquote><p>使用 gitHub 登錄</p></blockquote><blockquote><p>使用 gイんĤЦ8 登錄</p></blockquote><blockquote><p>我們的客戶有 github、foursquare、microsoft corporation、google、facebook, inc.。</p></blockquote><blockquote><p>我們的客戶有 GITHUB、FOURSQUARE、MICROSOFT CORPORATION、GOOGLE、FACEBOOK, INC.。</p></blockquote><blockquote><p>我們的客戶有 Github、FourSquare、MicroSoft Corporation、Google、FaceBook, Inc.。</p></blockquote><blockquote><p>我們的客戶有 gitHub、fourSquare、microSoft Corporation、google、faceBook, Inc.。</p></blockquote><blockquote><p>我們的客戶有 gイんĤЦ8、キouЯƧquムгє、๓เςг๏ร๏Ŧt ς๏гק๏гคtเ๏ภn、900913、ƒ4ᄃëв๏๏к, IПᄃ.。</p></blockquote><p>注意:當網頁中需要配合整體視覺風格而出現全部大寫/小寫的情形,HTML 中請使用標準的大小寫規範進行書寫;並通過 <code>text-transform: uppercase;</code>/<code>text-transform: lowercase;</code> 對表現形式進行定義。</p><h3 id="不要使用不道地的縮寫"><a href="#不要使用不道地的縮寫" class="headerlink" title="不要使用不道地的縮寫"></a>不要使用不道地的縮寫</h3><p>正確:</p><blockquote><p>我們需要一位熟悉 TypeScript、HTML5,至少理解一種框架(如 React、Next.js)的前端開發者。</p></blockquote><p>錯誤:</p><blockquote><p>我們需要一位熟悉 Ts、h5,至少理解一種框架(如 RJS、nextjs)的 FED。</p></blockquote><h2 id="爭議"><a href="#爭議" class="headerlink" title="爭議"></a>爭議</h2><p>以下用法略帶有個人色彩,即:無論是否遵循下述規則,從語法的角度來講都是<strong>正確</strong>的。</p><h3 id="超連結之間增加空格"><a href="#超連結之間增加空格" class="headerlink" title="超連結之間增加空格"></a>超連結之間增加空格</h3><p>用法:</p><blockquote><p>請 <a href="#">提交一個 issue</a> 並分配给相關同事。</p></blockquote><blockquote><p>訪問我們網站的最新動態,請 <a href="#">點擊這裡</a> 進行訂閱!</p></blockquote><p>對比用法:</p><blockquote><p>請<a href="#">提交一個 issue</a> 並分配给相關同事。</p></blockquote><blockquote><p>訪問我們網站的最新動態,請<a href="#">點擊這裡</a>進行訂閱!</p></blockquote><h3 id="簡體中文使用直角引號"><a href="#簡體中文使用直角引號" class="headerlink" title="簡體中文使用直角引號"></a>簡體中文使用直角引號</h3><p>用法:</p><blockquote><p>「老師,『有條不紊』的『紊』是什麼意思?」</p></blockquote><p>對比用法:</p><blockquote><p>“老師,‘有條不紊’的‘紊’是什麼意思?”</p></blockquote><h2 id="工具"><a href="#工具" class="headerlink" title="工具"></a>工具</h2><table><thead><tr><th>倉庫</th><th>語言</th></tr></thead><tbody><tr><td><a href="https://github.com/vinta/paranoid-auto-spacing">vinta/paranoid-auto-spacing</a></td><td>JavaScript</td></tr><tr><td><a href="https://github.com/huei90/pangu.node">huei90/pangu.node</a></td><td>Node.js</td></tr><tr><td><a href="https://github.com/huacnlee/auto-correct">huacnlee/auto-correct</a></td><td>Ruby</td></tr><tr><td><a href="https://github.com/huacnlee/autocorrect">huacnlee/autocorrect</a></td><td>Rust, WASM, CLI</td></tr><tr><td><a href="https://github.com/huacnlee/go-auto-correct">huacnlee/go-auto-correct</a></td><td>Go</td></tr><tr><td><a href="https://github.com/sparanoid/space-lover">sparanoid/space-lover</a></td><td>PHP (WordPress)</td></tr><tr><td><a href="https://github.com/NauxLiu/auto-correct">nauxliu/auto-correct</a></td><td>PHP</td></tr><tr><td><a href="https://github.com/jxlwqq/chinese-typesetting">jxlwqq/chinese-typesetting</a></td><td>PHP</td></tr><tr><td><a href="https://github.com/hotoo/pangu.vim">hotoo/pangu.vim</a></td><td>Vim</td></tr><tr><td><a href="https://github.com/sparanoid/grunt-auto-spacing">sparanoid/grunt-auto-spacing</a></td><td>Node.js (Grunt)</td></tr><tr><td><a href="https://github.com/hjiang/scripts/blob/master/add-space-between-latin-and-cjk">hjiang/scripts/add-space-between-latin-and-cjk</a></td><td>Python</td></tr><tr><td><a href="https://github.com/hustcc/hint">hustcc/hint</a></td><td>Python</td></tr><tr><td><a href="https://github.com/studygolang/autocorrect">studygolang/autocorrect</a></td><td>Go</td></tr><tr><td><a href="https://github.com/n0vad3v/Tekorrect">n0vad3v/Tekorrect</a></td><td>Python</td></tr><tr><td><a href="https://marketplace.visualstudio.com/items?itemName=huacnlee.auto-correct">VS Code - huacnlee.auto-correct</a></td><td>VS Code Extension</td></tr></tbody></table><h2 id="誰在這樣做?"><a href="#誰在這樣做?" class="headerlink" title="誰在這樣做?"></a>誰在這樣做?</h2><table><thead><tr><th>網站</th><th>文案</th><th>UGC</th></tr></thead><tbody><tr><td><a href="https://www.apple.com/cn/">Apple 中國</a></td><td>Yes</td><td>N/A</td></tr><tr><td><a href="https://www.apple.com/hk/">Apple 香港</a></td><td>Yes</td><td>N/A</td></tr><tr><td><a href="https://www.apple.com/tw/">Apple 台灣</a></td><td>Yes</td><td>N/A</td></tr><tr><td><a href="https://www.microsoft.com/zh-cn/">Microsoft 中國</a></td><td>Yes</td><td>N/A</td></tr><tr><td><a href="https://www.microsoft.com/zh-hk/">Microsoft 香港</a></td><td>Yes</td><td>N/A</td></tr><tr><td><a href="https://www.microsoft.com/zh-tw/">Microsoft 台灣</a></td><td>Yes</td><td>N/A</td></tr><tr><td><a href="https://leancloud.cn/">LeanCloud</a></td><td>Yes</td><td>N/A</td></tr><tr><td><a href="https://www.v2ex.com/">V2EX</a></td><td>Yes</td><td>Yes</td></tr><tr><td><a href="https://apple4us.com/">Apple4us</a></td><td>Yes</td><td>N/A</td></tr><tr><td><a href="https://ruby-china.org/">Ruby China</a></td><td>Yes</td><td>Yes</td></tr><tr><td><a href="https://phphub.org/">PHPHub</a></td><td>Yes</td><td>標題達成</td></tr><tr><td><a href="https://sspai.com/">少數派</a></td><td>Yes</td><td>N/A</td></tr></tbody></table><h2 id="參考文獻"><a href="#參考文獻" class="headerlink" title="參考文獻"></a>參考文獻</h2><ul><li><a href="https://www.thoughtco.com/guidelines-for-using-capital-letters-1691724">Guidelines for Using Capital Letters - ThoughtCo.</a></li><li><a href="https://en.wikipedia.org/wiki/Letter_case">Letter case - Wikipedia</a></li><li><a href="https://en.oxforddictionaries.com/grammar/punctuation">Punctuation - Oxford Dictionaries</a></li><li><a href="https://owl.english.purdue.edu/owl/section/1/6/">Punctuation - The Purdue OWL</a></li><li><a href="https://www.wikihow.com/Use-English-Punctuation-Correctly">How to Use English Punctuation Correctly - wikiHow</a></li><li><a href="https://zh.opensuse.org/index.php?title=Help:%E6%A0%BC%E5%BC%8F">格式 - openSUSE</a></li><li><a href="https://zh.wikipedia.org/wiki/%E5%85%A8%E5%BD%A2%E5%92%8C%E5%8D%8A%E5%BD%A2">全形和半形 - 維基百科</a></li><li><a href="https://zh.wikipedia.org/wiki/%E5%BC%95%E8%99%9F">引號 - 維基百科</a></li><li><a href="https://zh.wikipedia.org/wiki/%E7%96%91%E5%95%8F%E9%A9%9A%E5%98%86%E8%99%9F">疑問驚嘆號 - 維基百科</a></li></ul>]]></content>
<categories>
<category> 指南 </category>
</categories>
<tags>
<tag> 规范 </tag>
<tag> 文档 </tag>
</tags>
</entry>
<entry>
<title>PHP版的代码整洁之道</title>
<link href="/2021/11/3326abeb690f/"/>
<url>/2021/11/3326abeb690f/</url>
<content type="html"><![CDATA[<h1 id="Clean-Code-PHP"><a href="#Clean-Code-PHP" class="headerlink" title="Clean Code PHP"></a>Clean Code PHP</h1><h2 id="介绍"><a href="#介绍" class="headerlink" title="介绍"></a>介绍</h2><p>本文参考自 Robert C. Martin的<a href="https://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882"><em>Clean Code</em></a> 书中的软件工程师的原则<br>,适用于PHP。 这不是风格指南。 这是一个关于开发可读、可复用并且可重构的PHP软件指南。</p><span id="more"></span><p>并不是这里所有的原则都得遵循,甚至很少的能被普遍接受。 这些虽然只是指导,但是都是<em>Clean Code</em>作者多年总结出来的。</p><p>本文受到 <a href="https://github.com/ryanmcdermott/clean-code-javascript">clean-code-javascript</a> 的启发</p><p>虽然很多开发者还在使用PHP5,但是本文中的大部分示例的运行环境需要PHP 7.1+。</p><h2 id="翻译说明"><a href="#翻译说明" class="headerlink" title="翻译说明"></a>翻译说明</h2><p>翻译完成度100%,最后更新时间2020-10-26。本文由 php-cpm 基于 <a href="https://github.com/yangweijie/clean-code-php">yangweijie版本</a> 的<a href="https://github.com/jupeter/clean-code-php">clean-code-php</a>翻译并同步大量原文内容。</p><p>原文更新频率较高,我的翻译方法是直接用文本比较工具逐行对比。优先保证文字内容是最新的,再逐步提升翻译质量。</p><p>阅读过程中如果遇到各种链接失效、内容老旧、术语使用错误和其他翻译错误等问题,欢迎大家积极提交PR。</p><h2 id="变量"><a href="#变量" class="headerlink" title="变量"></a><strong>变量</strong></h2><h3 id="使用见字知意的变量名"><a href="#使用见字知意的变量名" class="headerlink" title="使用见字知意的变量名"></a>使用见字知意的变量名</h3><p><strong>坏:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$ymdstr</span> = <span class="variable">$moment</span>->format(<span class="string">'y-m-d'</span>);</span><br></pre></td></tr></table></figure><p><strong>好:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$currentDate</span> = <span class="variable">$moment</span>->format(<span class="string">'y-m-d'</span>);</span><br></pre></td></tr></table></figure><p><strong><a href="#%E7%9B%AE%E5%BD%95">⬆ 返回顶部</a></strong></p><h3 id="同一个实体要用相同的变量名"><a href="#同一个实体要用相同的变量名" class="headerlink" title="同一个实体要用相同的变量名"></a>同一个实体要用相同的变量名</h3><p><strong>坏:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">getUserInfo();</span><br><span class="line">getUserData();</span><br><span class="line">getUserRecord();</span><br><span class="line">getUserProfile();</span><br></pre></td></tr></table></figure><p><strong>好:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">getUser();</span><br></pre></td></tr></table></figure><p><strong><a href="#%E7%9B%AE%E5%BD%95">⬆ 返回顶部</a></strong></p><h3 id="使用便于搜索的名称-part-1"><a href="#使用便于搜索的名称-part-1" class="headerlink" title="使用便于搜索的名称 (part 1)"></a>使用便于搜索的名称 (part 1)</h3><p>写代码是用来读的。所以写出可读性高、便于搜索的代码至关重要。<br>命名变量时如果没有有意义、不好理解,那就是在伤害读者。<br>请让你的代码便于搜索。</p><p><strong>坏:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 448 ™ 干啥的?</span></span><br><span class="line"><span class="variable">$result</span> = <span class="variable">$serializer</span>->serialize(<span class="variable">$data</span>, <span class="number">448</span>);</span><br></pre></td></tr></table></figure><p><strong>好:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$json</span> = <span class="variable">$serializer</span>->serialize(<span class="variable">$data</span>, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);</span><br></pre></td></tr></table></figure><h3 id="使用便于搜索的名称-part-2"><a href="#使用便于搜索的名称-part-2" class="headerlink" title="使用便于搜索的名称 (part 2)"></a>使用便于搜索的名称 (part 2)</h3><p><strong>坏:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">User</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="comment">// 7 ™ 干啥的?</span></span><br><span class="line"> <span class="keyword">public</span> <span class="variable">$access</span> = <span class="number">7</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 4 ™ 干啥的?</span></span><br><span class="line"><span class="keyword">if</span> (<span class="variable">$user</span>->access & <span class="number">4</span>) {</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 这里会发生什么?</span></span><br><span class="line"><span class="variable">$user</span>->access ^= <span class="number">2</span>;</span><br></pre></td></tr></table></figure><p><strong>好:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">User</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">const</span> ACCESS_READ = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">const</span> ACCESS_CREATE = <span class="number">2</span>;</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">const</span> ACCESS_UPDATE = <span class="number">4</span>;</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">const</span> ACCESS_DELETE = <span class="number">8</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 默认情况下用户 具有读、写和更新权限</span></span><br><span class="line"> <span class="keyword">public</span> <span class="variable">$access</span> = <span class="built_in">self</span>::ACCESS_READ | <span class="built_in">self</span>::ACCESS_CREATE | <span class="built_in">self</span>::ACCESS_UPDATE;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (<span class="variable">$user</span>->access & User::ACCESS_UPDATE) {</span><br><span class="line"> <span class="comment">// do edit ...</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 禁用创建权限</span></span><br><span class="line"><span class="variable">$user</span>->access ^= User::ACCESS_CREATE;</span><br></pre></td></tr></table></figure><p><strong><a href="#%E7%9B%AE%E5%BD%95">⬆ 返回顶部</a></strong></p><h3 id="使用自解释型变量"><a href="#使用自解释型变量" class="headerlink" title="使用自解释型变量"></a>使用自解释型变量</h3><p><strong>坏:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$address</span> = <span class="string">'One Infinite Loop, Cupertino 95014'</span>;</span><br><span class="line"><span class="variable">$cityZipCodeRegex</span> = <span class="string">'/^[^,]+,\s*(.+?)\s*(\d{5})$/'</span>;</span><br><span class="line">preg_match(<span class="variable">$cityZipCodeRegex</span>, <span class="variable">$address</span>, <span class="variable">$matches</span>);</span><br><span class="line"></span><br><span class="line">saveCityZipCode(<span class="variable">$matches</span>[<span class="number">1</span>], <span class="variable">$matches</span>[<span class="number">2</span>]);</span><br></pre></td></tr></table></figure><p><strong>不错:</strong></p><p>好一些,但强依赖于正则表达式的熟悉程度</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$address</span> = <span class="string">'One Infinite Loop, Cupertino 95014'</span>;</span><br><span class="line"><span class="variable">$cityZipCodeRegex</span> = <span class="string">'/^[^,]+,\s*(.+?)\s*(\d{5})$/'</span>;</span><br><span class="line">preg_match(<span class="variable">$cityZipCodeRegex</span>, <span class="variable">$address</span>, <span class="variable">$matches</span>);</span><br><span class="line"></span><br><span class="line">[, <span class="variable">$city</span>, <span class="variable">$zipCode</span>] = <span class="variable">$matches</span>;</span><br><span class="line">saveCityZipCode(<span class="variable">$city</span>, <span class="variable">$zipCode</span>);</span><br></pre></td></tr></table></figure><p><strong>好:</strong></p><p>使用带名字的子规则,不用懂正则也能看的懂</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$address</span> = <span class="string">'One Infinite Loop, Cupertino 95014'</span>;</span><br><span class="line"><span class="variable">$cityZipCodeRegex</span> = <span class="string">'/^[^,]+,\s*(?<city>.+?)\s*(?<zipCode>\d{5})$/'</span>;</span><br><span class="line">preg_match(<span class="variable">$cityZipCodeRegex</span>, <span class="variable">$address</span>, <span class="variable">$matches</span>);</span><br><span class="line"></span><br><span class="line">saveCityZipCode(<span class="variable">$matches</span>[<span class="string">'city'</span>], <span class="variable">$matches</span>[<span class="string">'zipCode'</span>]);</span><br></pre></td></tr></table></figure><p><strong><a href="#%E7%9B%AE%E5%BD%95">⬆ 返回顶部</a></strong></p><h3 id="避免深层嵌套,尽早返回-part-1"><a href="#避免深层嵌套,尽早返回-part-1" class="headerlink" title="避免深层嵌套,尽早返回 (part 1)"></a>避免深层嵌套,尽早返回 (part 1)</h3><p>太多的if else语句通常会导致你的代码难以阅读,直白优于隐晦</p><p><strong>糟糕:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">isShopOpen</span>(<span class="params"><span class="variable">$day</span></span>): <span class="title">bool</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$day</span>) {</span><br><span class="line"> <span class="keyword">if</span> (is_string(<span class="variable">$day</span>)) {</span><br><span class="line"> <span class="variable">$day</span> = strtolower(<span class="variable">$day</span>);</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$day</span> === <span class="string">'friday'</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line"> } <span class="keyword">elseif</span> (<span class="variable">$day</span> === <span class="string">'saturday'</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line"> } <span class="keyword">elseif</span> (<span class="variable">$day</span> === <span class="string">'sunday'</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>好:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">isShopOpen</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$day</span></span>): <span class="title">bool</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">empty</span>(<span class="variable">$day</span>)) {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="variable">$openingDays</span> = [</span><br><span class="line"> <span class="string">'friday'</span>, <span class="string">'saturday'</span>, <span class="string">'sunday'</span></span><br><span class="line"> ];</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> in_array(strtolower(<span class="variable">$day</span>), <span class="variable">$openingDays</span>, <span class="literal">true</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong><a href="#%E7%9B%AE%E5%BD%95">⬆ 返回顶部</a></strong></p><h3 id="避免深层嵌套,尽早返回-part-2"><a href="#避免深层嵌套,尽早返回-part-2" class="headerlink" title="避免深层嵌套,尽早返回 (part 2)"></a>避免深层嵌套,尽早返回 (part 2)</h3><p><strong>糟糕的:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">fibonacci</span>(<span class="params"><span class="keyword">int</span> <span class="variable">$n</span></span>)</span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$n</span> < <span class="number">50</span>) {</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$n</span> !== <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$n</span> !== <span class="number">1</span>) {</span><br><span class="line"> <span class="keyword">return</span> fibonacci(<span class="variable">$n</span> - <span class="number">1</span>) + fibonacci(<span class="variable">$n</span> - <span class="number">2</span>);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="string">'Not supported'</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>好:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">fibonacci</span>(<span class="params"><span class="keyword">int</span> <span class="variable">$n</span></span>): <span class="title">int</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$n</span> === <span class="number">0</span> || <span class="variable">$n</span> === <span class="number">1</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="variable">$n</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$n</span> >= <span class="number">50</span>) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> \<span class="built_in">Exception</span>(<span class="string">'Not supported'</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> fibonacci(<span class="variable">$n</span> - <span class="number">1</span>) + fibonacci(<span class="variable">$n</span> - <span class="number">2</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong><a href="#%E7%9B%AE%E5%BD%95">⬆ 返回顶部</a></strong></p><h3 id="少用无意义的变量名"><a href="#少用无意义的变量名" class="headerlink" title="少用无意义的变量名"></a>少用无意义的变量名</h3><p>别让读你的代码的人猜你写的变量是什么意思。<br>写清楚好过模糊不清。</p><p><strong>坏:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$l</span> = [<span class="string">'Austin'</span>, <span class="string">'New York'</span>, <span class="string">'San Francisco'</span>];</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (<span class="variable">$i</span> = <span class="number">0</span>; <span class="variable">$i</span> < count(<span class="variable">$l</span>); <span class="variable">$i</span>++) {</span><br><span class="line"> <span class="variable">$li</span> = <span class="variable">$l</span>[<span class="variable">$i</span>];</span><br><span class="line"> doStuff();</span><br><span class="line"> doSomeOtherStuff();</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> <span class="comment">// 等等, `$li` 又代表什么?</span></span><br><span class="line"> dispatch(<span class="variable">$li</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>好:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$locations</span> = [<span class="string">'Austin'</span>, <span class="string">'New York'</span>, <span class="string">'San Francisco'</span>];</span><br><span class="line"></span><br><span class="line"><span class="keyword">foreach</span> (<span class="variable">$locations</span> <span class="keyword">as</span> <span class="variable">$location</span>) {</span><br><span class="line"> doStuff();</span><br><span class="line"> doSomeOtherStuff();</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> dispatch(<span class="variable">$location</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong><a href="#%E7%9B%AE%E5%BD%95">⬆ 返回顶部</a></strong></p><h3 id="不要添加不必要上下文"><a href="#不要添加不必要上下文" class="headerlink" title="不要添加不必要上下文"></a>不要添加不必要上下文</h3><p>如果从你的类名、对象名已经可以得知一些信息,就别再在变量名里重复。</p><p><strong>坏:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Car</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="variable">$carMake</span>;</span><br><span class="line"> <span class="keyword">public</span> <span class="variable">$carModel</span>;</span><br><span class="line"> <span class="keyword">public</span> <span class="variable">$carColor</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">//...</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>好:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Car</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="variable">$make</span>;</span><br><span class="line"> <span class="keyword">public</span> <span class="variable">$model</span>;</span><br><span class="line"> <span class="keyword">public</span> <span class="variable">$color</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">//...</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong><a href="#%E7%9B%AE%E5%BD%95">⬆ 返回顶部</a></strong></p><h3 id="合理使用参数默认值,没必要在方法里再做默认值检测"><a href="#合理使用参数默认值,没必要在方法里再做默认值检测" class="headerlink" title="合理使用参数默认值,没必要在方法里再做默认值检测"></a>合理使用参数默认值,没必要在方法里再做默认值检测</h3><p><strong>不好:</strong></p><p>不好,<code>$breweryName</code> 可能为 <code>NULL</code>.</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">createMicrobrewery</span>(<span class="params"><span class="variable">$breweryName</span> = <span class="string">'Hipster Brew Co.'</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>还行:</strong></p><p>比上一个好理解一些,但最好能控制变量的值</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">createMicrobrewery</span>(<span class="params"><span class="variable">$name</span> = <span class="literal">null</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="variable">$breweryName</span> = <span class="variable">$name</span> ?: <span class="string">'Hipster Brew Co.'</span>;</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>好:</strong></p><p>如果你的程序只支持 PHP 7+, 那你可以用 <a href="http://php.net/manual/en/functions.arguments.php#functions.arguments.type-declaration">type hinting</a> 保证变量 <code>$breweryName</code> 不是 <code>NULL</code>.</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">createMicrobrewery</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$breweryName</span> = <span class="string">'Hipster Brew Co.'</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong><a href="#%E7%9B%AE%E5%BD%95">⬆ 返回顶部</a></strong></p><h2 id="表达式"><a href="#表达式" class="headerlink" title="表达式"></a>表达式</h2><h3 id="使用恒等式"><a href="#使用恒等式" class="headerlink" title="使用恒等式"></a><a href="http://php.net/manual/en/language.operators.comparison.php">使用恒等式</a></h3><p><strong>不好:</strong></p><p>简易对比会将字符串转为整形</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$a</span> = <span class="string">'42'</span>;</span><br><span class="line"><span class="variable">$b</span> = <span class="number">42</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span>( <span class="variable">$a</span> != <span class="variable">$b</span> ) {</span><br><span class="line"> <span class="comment">//这里始终执行不到</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>对比 $a != $b 返回了 <code>FALSE</code> 但应该返回 <code>TRUE</code> !<br>字符串 ‘42’ 跟整数 42 不相等</p><p><strong>好:</strong></p><p>使用恒等判断检查类型和数据</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$a</span> = <span class="string">'42'</span>;</span><br><span class="line"><span class="variable">$b</span> = <span class="number">42</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (<span class="variable">$a</span> !== <span class="variable">$b</span>) {</span><br><span class="line"> <span class="comment">// The expression is verified</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>The comparison <code>$a !== $b</code> returns <code>TRUE</code>.</p><p><strong><a href="#%E7%9B%AE%E5%BD%95">⬆ 返回顶部</a></strong></p><h3 id="Null-coalescing-operator"><a href="#Null-coalescing-operator" class="headerlink" title="Null coalescing operator"></a>Null coalescing operator</h3><p>Null coalescing is a new operator <a href="https://www.php.net/manual/en/migration70.new-features.php">introduced in PHP 7</a>. The null coalescing operator <code>??</code> has been added as syntactic sugar for the common case of needing to use a ternary in conjunction with <code>isset()</code>. It returns its first operand if it exists and is not <code>null</code>; otherwise it returns its second operand.</p><p><strong>Bad:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (<span class="keyword">isset</span>(<span class="variable">$_GET</span>[<span class="string">'name'</span>])) {</span><br><span class="line"> <span class="variable">$name</span> = <span class="variable">$_GET</span>[<span class="string">'name'</span>];</span><br><span class="line">} <span class="keyword">elseif</span> (<span class="keyword">isset</span>(<span class="variable">$_POST</span>[<span class="string">'name'</span>])) {</span><br><span class="line"> <span class="variable">$name</span> = <span class="variable">$_POST</span>[<span class="string">'name'</span>];</span><br><span class="line">} <span class="keyword">else</span> {</span><br><span class="line"> <span class="variable">$name</span> = <span class="string">'nobody'</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>Good:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$name</span> = <span class="variable">$_GET</span>[<span class="string">'name'</span>] ?? <span class="variable">$_POST</span>[<span class="string">'name'</span>] ?? <span class="string">'nobody'</span>;</span><br></pre></td></tr></table></figure><p><strong><a href="#table-of-contents">⬆ back to top</a></strong></p><h2 id="函数"><a href="#函数" class="headerlink" title="函数"></a>函数</h2><h3 id="函数参数(最好少于2个)"><a href="#函数参数(最好少于2个)" class="headerlink" title="函数参数(最好少于2个)"></a>函数参数(最好少于2个)</h3><p>限制函数参数个数极其重要,这样测试你的函数容易点。有超过3个可选参数参数导致一个爆炸式组合增长,你会有成吨独立参数情形要测试。</p><p>无参数是理想情况。1个或2个都可以,最好避免3个。再多就需要加固了。通常如果你的函数有超过两个参数,说明他要处理的事太多了。 如果必须要传入很多数据,建议封装一个高级别对象作为参数。</p><p><strong>坏:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Questionnaire</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"></span></span></span><br><span class="line"><span class="params"><span class="function"> <span class="keyword">string</span> <span class="variable">$firstname</span>,</span></span></span><br><span class="line"><span class="params"><span class="function"> <span class="keyword">string</span> <span class="variable">$lastname</span>,</span></span></span><br><span class="line"><span class="params"><span class="function"> <span class="keyword">string</span> <span class="variable">$patronymic</span>,</span></span></span><br><span class="line"><span class="params"><span class="function"> <span class="keyword">string</span> <span class="variable">$region</span>,</span></span></span><br><span class="line"><span class="params"><span class="function"> <span class="keyword">string</span> <span class="variable">$district</span>,</span></span></span><br><span class="line"><span class="params"><span class="function"> <span class="keyword">string</span> <span class="variable">$city</span>,</span></span></span><br><span class="line"><span class="params"><span class="function"> <span class="keyword">string</span> <span class="variable">$phone</span>,</span></span></span><br><span class="line"><span class="params"><span class="function"> <span class="keyword">string</span> <span class="variable">$email</span></span></span></span><br><span class="line"><span class="params"><span class="function"> </span>) </span>{</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>好:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Name</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$firstname</span>;</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$lastname</span>;</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$patronymic</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$firstname</span>, <span class="keyword">string</span> <span class="variable">$lastname</span>, <span class="keyword">string</span> <span class="variable">$patronymic</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->firstname = <span class="variable">$firstname</span>;</span><br><span class="line"> <span class="keyword">$this</span>->lastname = <span class="variable">$lastname</span>;</span><br><span class="line"> <span class="keyword">$this</span>->patronymic = <span class="variable">$patronymic</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// getters ...</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">City</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$region</span>;</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$district</span>;</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$city</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$region</span>, <span class="keyword">string</span> <span class="variable">$district</span>, <span class="keyword">string</span> <span class="variable">$city</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->region = <span class="variable">$region</span>;</span><br><span class="line"> <span class="keyword">$this</span>->district = <span class="variable">$district</span>;</span><br><span class="line"> <span class="keyword">$this</span>->city = <span class="variable">$city</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// getters ...</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Contact</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$phone</span>;</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$email</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$phone</span>, <span class="keyword">string</span> <span class="variable">$email</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->phone = <span class="variable">$phone</span>;</span><br><span class="line"> <span class="keyword">$this</span>->email = <span class="variable">$email</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// getters ...</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Questionnaire</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params">Name <span class="variable">$name</span>, City <span class="variable">$city</span>, Contact <span class="variable">$contact</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong><a href="#%E7%9B%AE%E5%BD%95">⬆ 返回顶部</a></strong></p><h3 id="函数名应体现他做了什么事"><a href="#函数名应体现他做了什么事" class="headerlink" title="函数名应体现他做了什么事"></a>函数名应体现他做了什么事</h3><p><strong>坏:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Email</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="comment">//...</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">handle</span>(<span class="params"></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> mail(<span class="keyword">$this</span>->to, <span class="keyword">$this</span>->subject, <span class="keyword">$this</span>->body);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="variable">$message</span> = <span class="keyword">new</span> Email(...);</span><br><span class="line"><span class="comment">// 啥?handle处理一个消息干嘛了?是往一个文件里写吗?</span></span><br><span class="line"><span class="variable">$message</span>->handle();</span><br></pre></td></tr></table></figure><p><strong>好:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Email</span> </span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="comment">//...</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">send</span>(<span class="params"></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> mail(<span class="keyword">$this</span>->to, <span class="keyword">$this</span>->subject, <span class="keyword">$this</span>->body);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="variable">$message</span> = <span class="keyword">new</span> Email(...);</span><br><span class="line"><span class="comment">// 简单明了</span></span><br><span class="line"><span class="variable">$message</span>->send();</span><br></pre></td></tr></table></figure><p><strong><a href="#%E7%9B%AE%E5%BD%95">⬆ 返回顶部</a></strong></p><h3 id="函数里应当只有一层抽象abstraction"><a href="#函数里应当只有一层抽象abstraction" class="headerlink" title="函数里应当只有一层抽象abstraction"></a>函数里应当只有一层抽象abstraction</h3><p>当你抽象层次过多时时,函数处理的事情太多了。需要拆分功能来提高可重用性和易用性,以便简化测试。<br>(译者注:这里从示例代码看应该是指嵌套过多)</p><p><strong>坏:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">parseBetterPHPAlternative</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$code</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="variable">$regexes</span> = [</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> ];</span><br><span class="line"></span><br><span class="line"> <span class="variable">$statements</span> = explode(<span class="string">' '</span>, <span class="variable">$code</span>);</span><br><span class="line"> <span class="variable">$tokens</span> = [];</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable">$regexes</span> <span class="keyword">as</span> <span class="variable">$regex</span>) {</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable">$statements</span> <span class="keyword">as</span> <span class="variable">$statement</span>) {</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="variable">$ast</span> = [];</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable">$tokens</span> <span class="keyword">as</span> <span class="variable">$token</span>) {</span><br><span class="line"> <span class="comment">// lex...</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable">$ast</span> <span class="keyword">as</span> <span class="variable">$node</span>) {</span><br><span class="line"> <span class="comment">// parse...</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>坏:</strong></p><p>我们把一些方法从循环中提取出来,但是<code>parseBetterJSAlternative()</code>方法还是很复杂,而且不利于测试。</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">tokenize</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$code</span></span>): <span class="title">array</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="variable">$regexes</span> = [</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> ];</span><br><span class="line"></span><br><span class="line"> <span class="variable">$statements</span> = explode(<span class="string">' '</span>, <span class="variable">$code</span>);</span><br><span class="line"> <span class="variable">$tokens</span> = [];</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable">$regexes</span> <span class="keyword">as</span> <span class="variable">$regex</span>) {</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable">$statements</span> <span class="keyword">as</span> <span class="variable">$statement</span>) {</span><br><span class="line"> <span class="variable">$tokens</span>[] = <span class="comment">/* ... */</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="variable">$tokens</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">lexer</span>(<span class="params"><span class="keyword">array</span> <span class="variable">$tokens</span></span>): <span class="title">array</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="variable">$ast</span> = [];</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable">$tokens</span> <span class="keyword">as</span> <span class="variable">$token</span>) {</span><br><span class="line"> <span class="variable">$ast</span>[] = <span class="comment">/* ... */</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="variable">$ast</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">parseBetterPHPAlternative</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$code</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="variable">$tokens</span> = tokenize(<span class="variable">$code</span>);</span><br><span class="line"> <span class="variable">$ast</span> = lexer(<span class="variable">$tokens</span>);</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable">$ast</span> <span class="keyword">as</span> <span class="variable">$node</span>) {</span><br><span class="line"> <span class="comment">// 解析逻辑...</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>好:</strong></p><p>最好的解决方案是把 <code>parseBetterPHPAlternative()</code>方法的依赖移除。</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Tokenizer</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">tokenize</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$code</span></span>): <span class="title">array</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="variable">$regexes</span> = [</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> ];</span><br><span class="line"></span><br><span class="line"> <span class="variable">$statements</span> = explode(<span class="string">' '</span>, <span class="variable">$code</span>);</span><br><span class="line"> <span class="variable">$tokens</span> = [];</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable">$regexes</span> <span class="keyword">as</span> <span class="variable">$regex</span>) {</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable">$statements</span> <span class="keyword">as</span> <span class="variable">$statement</span>) {</span><br><span class="line"> <span class="variable">$tokens</span>[] = <span class="comment">/* ... */</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="variable">$tokens</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Lexer</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">lexify</span>(<span class="params"><span class="keyword">array</span> <span class="variable">$tokens</span></span>): <span class="title">array</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="variable">$ast</span> = [];</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable">$tokens</span> <span class="keyword">as</span> <span class="variable">$token</span>) {</span><br><span class="line"> <span class="variable">$ast</span>[] = <span class="comment">/* ... */</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="variable">$ast</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">BetterPHPAlternative</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$tokenizer</span>;</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$lexer</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params">Tokenizer <span class="variable">$tokenizer</span>, Lexer <span class="variable">$lexer</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->tokenizer = <span class="variable">$tokenizer</span>;</span><br><span class="line"> <span class="keyword">$this</span>->lexer = <span class="variable">$lexer</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">parse</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$code</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="variable">$tokens</span> = <span class="keyword">$this</span>->tokenizer->tokenize(<span class="variable">$code</span>);</span><br><span class="line"> <span class="variable">$ast</span> = <span class="keyword">$this</span>->lexer->lexify(<span class="variable">$tokens</span>);</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable">$ast</span> <span class="keyword">as</span> <span class="variable">$node</span>) {</span><br><span class="line"> <span class="comment">// 解析逻辑...</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong><a href="#%E7%9B%AE%E5%BD%95">⬆ 返回顶部</a></strong></p><h3 id="不要用flag作为函数的参数"><a href="#不要用flag作为函数的参数" class="headerlink" title="不要用flag作为函数的参数"></a>不要用flag作为函数的参数</h3><p>flag就是在告诉大家,这个方法里处理很多事。前面刚说过,一个函数应当只做一件事。 把不同flag的代码拆分到多个函数里。</p><p><strong>坏:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">createFile</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$name</span>, <span class="keyword">bool</span> <span class="variable">$temp</span> = <span class="literal">false</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$temp</span>) {</span><br><span class="line"> touch(<span class="string">'./temp/'</span>.<span class="variable">$name</span>);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> touch(<span class="variable">$name</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>好:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">createFile</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$name</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> touch(<span class="variable">$name</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">createTempFile</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$name</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> touch(<span class="string">'./temp/'</span>.<span class="variable">$name</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong><a href="#%E7%9B%AE%E5%BD%95">⬆ 返回顶部</a></strong></p><h3 id="避免副作用"><a href="#避免副作用" class="headerlink" title="避免副作用"></a>避免副作用</h3><p>一个函数做了比获取一个值然后返回另外一个值或值们会产生副作用如果。副作用可能是写入一个文件,修改某些全局变量或者偶然的把你全部的钱给了陌生人。</p><p>现在,你的确需要在一个程序或者场合里要有副作用,像之前的例子,你也许需要写一个文件。你想要做的是把你做这些的地方集中起来。不要用几个函数和类来写入一个特定的文件。用一个服务来做它,一个只有一个。</p><p>重点是避免常见陷阱比如对象间共享无结构的数据,使用可以写入任何的可变数据类型,不集中处理副作用发生的地方。如果你做了这些你就会比大多数程序员快乐。</p><p><strong>坏:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Global variable referenced by following function.</span></span><br><span class="line"><span class="comment">// If we had another function that used this name, now it'd be an array and it could break it.</span></span><br><span class="line"><span class="variable">$name</span> = <span class="string">'Ryan McDermott'</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">splitIntoFirstAndLastName</span>(<span class="params"></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">global</span> <span class="variable">$name</span>;</span><br><span class="line"></span><br><span class="line"> <span class="variable">$name</span> = explode(<span class="string">' '</span>, <span class="variable">$name</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">splitIntoFirstAndLastName();</span><br><span class="line"></span><br><span class="line">var_dump(<span class="variable">$name</span>); <span class="comment">// ['Ryan', 'McDermott'];</span></span><br></pre></td></tr></table></figure><p><strong>好:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">splitIntoFirstAndLastName</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$name</span></span>): <span class="title">array</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">return</span> explode(<span class="string">' '</span>, <span class="variable">$name</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="variable">$name</span> = <span class="string">'Ryan McDermott'</span>;</span><br><span class="line"><span class="variable">$newName</span> = splitIntoFirstAndLastName(<span class="variable">$name</span>);</span><br><span class="line"></span><br><span class="line">var_dump(<span class="variable">$name</span>); <span class="comment">// 'Ryan McDermott';</span></span><br><span class="line">var_dump(<span class="variable">$newName</span>); <span class="comment">// ['Ryan', 'McDermott'];</span></span><br></pre></td></tr></table></figure><p><strong><a href="#%E7%9B%AE%E5%BD%95">⬆ 返回顶部</a></strong></p><h3 id="不要写全局函数"><a href="#不要写全局函数" class="headerlink" title="不要写全局函数"></a>不要写全局函数</h3><p>在大多数语言中污染全局变量是一个坏的实践,因为你可能和其他类库冲突<br>并且调用你api的人直到他们捕获异常才知道踩坑了。让我们思考一种场景:<br>如果你想配置一个数组,你可能会写一个全局函数<code>config()</code>,但是他可能<br>和试着做同样事的其他类库冲突。</p><p><strong>坏:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">config</span>(<span class="params"></span>): <span class="title">array</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">return</span> [</span><br><span class="line"> <span class="string">'foo'</span> => <span class="string">'bar'</span>,</span><br><span class="line"> ]</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>好:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Configuration</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$configuration</span> = [];</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"><span class="keyword">array</span> <span class="variable">$configuration</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->configuration = <span class="variable">$configuration</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">get</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$key</span></span>): ?<span class="title">string</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">// null coalescing operator </span></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->configuration[<span class="variable">$key</span>] ?? <span class="literal">null</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>加载配置并创建 <code>Configuration</code> 类的实例</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$configuration</span> = <span class="keyword">new</span> Configuration([</span><br><span class="line"> <span class="string">'foo'</span> => <span class="string">'bar'</span>,</span><br><span class="line">]);</span><br></pre></td></tr></table></figure><p>现在你必须在程序中用 <code>Configuration</code> 的实例了</p><p><strong><a href="#%E7%9B%AE%E5%BD%95">⬆ 返回顶部</a></strong></p><h3 id="不要使用单例模式"><a href="#不要使用单例模式" class="headerlink" title="不要使用单例模式"></a>不要使用单例模式</h3><p>单例是一种 <a href="https://en.wikipedia.org/wiki/Singleton_pattern">反模式</a>. 以下是解释:Paraphrased from Brian Button:</p><ol><li>总是被用成全局实例。They are generally used as a <strong>global instance</strong>, why is that so bad? Because <strong>you hide the dependencies</strong> of your application in your code, instead of exposing them through the interfaces. Making something global to avoid passing it around is a <a href="https://en.wikipedia.org/wiki/Code_smell">code smell</a>.</li><li>违反了<a href="">单一响应原则</a>They violate the <a href="#single-responsibility-principle-srp">single responsibility principle</a>: by virtue of the fact that <strong>they control their own creation and lifecycle</strong>.</li><li>导致代码强耦合They inherently cause code to be tightly <a href="https://en.wikipedia.org/wiki/Coupling_%28computer_programming%29">coupled</a>. This makes faking them out under <strong>test rather difficult</strong> in many cases.</li><li>在整个程序的生命周期中始终携带状态。They carry state around for the lifetime of the application. Another hit to testing since <strong>you can end up with a situation where tests need to be ordered</strong> which is a big no for unit tests. Why? Because each unit test should be independent from the other.</li></ol><p>这里有一篇非常好的讨论单例模式的[根本问题((<a href="http://misko.hevery.com/2008/08/25/root-cause-of-singletons/)%E7%9A%84%E6%96%87%E7%AB%A0%EF%BC%8C%E6%98%AF[Misko">http://misko.hevery.com/2008/08/25/root-cause-of-singletons/)的文章,是[Misko</a> Hevery](<a href="http://misko.hevery.com/about/">http://misko.hevery.com/about/</a>) 写的。</p><p><strong>坏:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">DBConnection</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="built_in">static</span> <span class="variable">$instance</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$dsn</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="built_in">static</span> <span class="function"><span class="keyword">function</span> <span class="title">getInstance</span>(<span class="params"></span>): <span class="title">DBConnection</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">self</span>::<span class="variable">$instance</span> === <span class="literal">null</span>) {</span><br><span class="line"> <span class="built_in">self</span>::<span class="variable">$instance</span> = <span class="keyword">new</span> <span class="built_in">self</span>();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">self</span>::<span class="variable">$instance</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="variable">$singleton</span> = DBConnection::getInstance();</span><br></pre></td></tr></table></figure><p><strong>好:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">DBConnection</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$dsn</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>创建 <code>DBConnection</code> 类的实例并通过 <a href="http://php.net/manual/en/pdo.construct.php#refsect1-pdo.construct-parameters">DSN</a> 配置.</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$connection</span> = <span class="keyword">new</span> DBConnection(<span class="variable">$dsn</span>);</span><br></pre></td></tr></table></figure><p>现在你必须在程序中 使用 <code>DBConnection</code> 的实例了</p><p><strong><a href="#%E7%9B%AE%E5%BD%95">⬆ 返回顶部</a></strong></p><h3 id="封装条件语句"><a href="#封装条件语句" class="headerlink" title="封装条件语句"></a>封装条件语句</h3><p><strong>坏:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (<span class="variable">$article</span>->state === <span class="string">'published'</span>) {</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>好:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (<span class="variable">$article</span>->isPublished()) {</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong><a href="#%E7%9B%AE%E5%BD%95">⬆ 返回顶部</a></strong></p><h3 id="避免用反义条件判断"><a href="#避免用反义条件判断" class="headerlink" title="避免用反义条件判断"></a>避免用反义条件判断</h3><p><strong>坏:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">isDOMNodeNotPresent</span>(<span class="params">\DOMNode <span class="variable">$node</span></span>): <span class="title">bool</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (!isDOMNodeNotPresent(<span class="variable">$node</span>))</span><br><span class="line">{</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>好:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">isDOMNodePresent</span>(<span class="params">\DOMNode <span class="variable">$node</span></span>): <span class="title">bool</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (isDOMNodePresent(<span class="variable">$node</span>)) {</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong><a href="#%E7%9B%AE%E5%BD%95">⬆ 返回顶部</a></strong></p><h3 id="避免条件判断"><a href="#避免条件判断" class="headerlink" title="避免条件判断"></a>避免条件判断</h3><p>这看起来像一个不可能任务。当人们第一次听到这句话是都会这么说。<br>“没有<code>if语句</code>我还能做啥?” 答案是你可以使用多态来实现多种场景<br>的相同任务。第二个问题很常见, “这么做可以,但为什么我要这么做?”<br> 答案是前面我们学过的一个Clean Code原则:一个函数应当只做一件事。<br> 当你有很多含有<code>if</code>语句的类和函数时,你的函数做了不止一件事。<br> 记住,只做一件事。</p><p><strong>坏:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Airplane</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">getCruisingAltitude</span>(<span class="params"></span>): <span class="title">int</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">switch</span> (<span class="keyword">$this</span>->type) {</span><br><span class="line"> <span class="keyword">case</span> <span class="string">'777'</span>:</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->getMaxAltitude() - <span class="keyword">$this</span>->getPassengerCount();</span><br><span class="line"> <span class="keyword">case</span> <span class="string">'Air Force One'</span>:</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->getMaxAltitude();</span><br><span class="line"> <span class="keyword">case</span> <span class="string">'Cessna'</span>:</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->getMaxAltitude() - <span class="keyword">$this</span>->getFuelExpenditure();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>好:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">interface</span> <span class="title">Airplane</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">getCruisingAltitude</span>(<span class="params"></span>): <span class="title">int</span></span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Boeing777</span> <span class="keyword">implements</span> <span class="title">Airplane</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">getCruisingAltitude</span>(<span class="params"></span>): <span class="title">int</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->getMaxAltitude() - <span class="keyword">$this</span>->getPassengerCount();</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">AirForceOne</span> <span class="keyword">implements</span> <span class="title">Airplane</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">getCruisingAltitude</span>(<span class="params"></span>): <span class="title">int</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->getMaxAltitude();</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Cessna</span> <span class="keyword">implements</span> <span class="title">Airplane</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">getCruisingAltitude</span>(<span class="params"></span>): <span class="title">int</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->getMaxAltitude() - <span class="keyword">$this</span>->getFuelExpenditure();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong><a href="#%E7%9B%AE%E5%BD%95">⬆ 返回顶部</a></strong></p><h3 id="避免类型检查-part-1"><a href="#避免类型检查-part-1" class="headerlink" title="避免类型检查 (part 1)"></a>避免类型检查 (part 1)</h3><p>PHP是弱类型的,这意味着你的函数可以接收任何类型的参数。<br>有时候你为这自由所痛苦并且在你的函数渐渐尝试类型检查。<br>有很多方法去避免这么做。第一种是统一API。</p><p><strong>坏:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">travelToTexas</span>(<span class="params"><span class="variable">$vehicle</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$vehicle</span> <span class="keyword">instanceof</span> Bicycle) {</span><br><span class="line"> <span class="variable">$vehicle</span>->pedalTo(<span class="keyword">new</span> Location(<span class="string">'texas'</span>));</span><br><span class="line"> } <span class="keyword">elseif</span> (<span class="variable">$vehicle</span> <span class="keyword">instanceof</span> Car) {</span><br><span class="line"> <span class="variable">$vehicle</span>->driveTo(<span class="keyword">new</span> Location(<span class="string">'texas'</span>));</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>好:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">travelToTexas</span>(<span class="params">Vehicle <span class="variable">$vehicle</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="variable">$vehicle</span>->travelTo(<span class="keyword">new</span> Location(<span class="string">'texas'</span>));</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong><a href="#%E7%9B%AE%E5%BD%95">⬆ 返回顶部</a></strong></p><h3 id="避免类型检查-part-2"><a href="#避免类型检查-part-2" class="headerlink" title="避免类型检查 (part 2)"></a>避免类型检查 (part 2)</h3><p>如果你正使用基本原始值比如字符串、整形和数组,要求版本是PHP 7+,不用多态,需要类型检测,<br>那你应当考虑<a href="http://php.net/manual/en/functions.arguments.php#functions.arguments.type-declaration">类型声明</a>或者严格模式。<br>提供了基于标准PHP语法的静态类型。 手动检查类型的问题是做好了需要好多的废话,好像为了安全就可以不顾损失可读性。<br>保持你的PHP 整洁,写好测试,做好代码回顾。做不到就用PHP严格类型声明和严格模式来确保安全。</p><p><strong>坏:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">combine</span>(<span class="params"><span class="variable">$val1</span>, <span class="variable">$val2</span></span>): <span class="title">int</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (!is_numeric(<span class="variable">$val1</span>) || !is_numeric(<span class="variable">$val2</span>)) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> \<span class="built_in">Exception</span>(<span class="string">'Must be of type Number'</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="variable">$val1</span> + <span class="variable">$val2</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>好:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">combine</span>(<span class="params"><span class="keyword">int</span> <span class="variable">$val1</span>, <span class="keyword">int</span> <span class="variable">$val2</span></span>): <span class="title">int</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="variable">$val1</span> + <span class="variable">$val2</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong><a href="#%E7%9B%AE%E5%BD%95">⬆ 返回顶部</a></strong></p><h3 id="移除僵尸代码"><a href="#移除僵尸代码" class="headerlink" title="移除僵尸代码"></a>移除僵尸代码</h3><p>僵尸代码和重复代码一样坏。没有理由保留在你的代码库中。如果从来没被调用过,就删掉!<br>因为还在代码版本库里,因此很安全。</p><p><strong>坏:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">oldRequestModule</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$url</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">newRequestModule</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$url</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="variable">$request</span> = newRequestModule(<span class="variable">$requestUrl</span>);</span><br><span class="line">inventoryTracker(<span class="string">'apples'</span>, <span class="variable">$request</span>, <span class="string">'www.inventory-awesome.io'</span>);</span><br></pre></td></tr></table></figure><p><strong>好:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">requestModule</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$url</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="variable">$request</span> = requestModule(<span class="variable">$requestUrl</span>);</span><br><span class="line">inventoryTracker(<span class="string">'apples'</span>, <span class="variable">$request</span>, <span class="string">'www.inventory-awesome.io'</span>);</span><br></pre></td></tr></table></figure><p><strong><a href="#%E7%9B%AE%E5%BD%95">⬆ 返回顶部</a></strong></p><h2 id="对象和数据结构"><a href="#对象和数据结构" class="headerlink" title="对象和数据结构"></a>对象和数据结构</h2><h3 id="使用-getters-和-setters"><a href="#使用-getters-和-setters" class="headerlink" title="使用 getters 和 setters"></a>使用 getters 和 setters</h3><p>在PHP中你可以对方法使用<code>public</code>, <code>protected</code>, <code>private</code> 来控制对象属性的变更。</p><ul><li>当你想对对象属性做获取之外的操作时,你不需要在代码中去寻找并修改每一个该属性访问方法</li><li>当有<code>set</code>对应的属性方法时,易于增加参数的验证</li><li>封装内部的表示</li><li>使用set<em>和get</em>时,易于增加日志和错误控制</li><li>继承当前类时,可以复写默认的方法功能</li><li>当对象属性是从远端服务器获取时,get<em>,set</em>易于使用延迟加载</li></ul><p>此外,这样的方式也符合OOP开发中的<a href="#%E5%BC%80%E9%97%AD%E5%8E%9F%E5%88%99">开闭原则</a></p><p><strong>坏:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">BankAccount</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="variable">$balance</span> = <span class="number">1000</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="variable">$bankAccount</span> = <span class="keyword">new</span> BankAccount();</span><br><span class="line"></span><br><span class="line"><span class="comment">// Buy shoes...</span></span><br><span class="line"><span class="variable">$bankAccount</span>->balance -= <span class="number">100</span>;</span><br></pre></td></tr></table></figure><p><strong>好:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">BankAccount</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$balance</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"><span class="keyword">int</span> <span class="variable">$balance</span> = <span class="number">1000</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->balance = <span class="variable">$balance</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">withdraw</span>(<span class="params"><span class="keyword">int</span> <span class="variable">$amount</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$amount</span> > <span class="keyword">$this</span>->balance) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> \<span class="built_in">Exception</span>(<span class="string">'Amount greater than available balance.'</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">$this</span>->balance -= <span class="variable">$amount</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">deposit</span>(<span class="params"><span class="keyword">int</span> <span class="variable">$amount</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->balance += <span class="variable">$amount</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">getBalance</span>(<span class="params"></span>): <span class="title">int</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->balance;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="variable">$bankAccount</span> = <span class="keyword">new</span> BankAccount();</span><br><span class="line"></span><br><span class="line"><span class="comment">// Buy shoes...</span></span><br><span class="line"><span class="variable">$bankAccount</span>->withdraw(<span class="variable">$shoesPrice</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// Get balance</span></span><br><span class="line"><span class="variable">$balance</span> = <span class="variable">$bankAccount</span>->getBalance();</span><br></pre></td></tr></table></figure><p><strong><a href="#%E7%9B%AE%E5%BD%95">⬆ 返回顶部</a></strong></p><h3 id="给对象使用私有或受保护的成员变量"><a href="#给对象使用私有或受保护的成员变量" class="headerlink" title="给对象使用私有或受保护的成员变量"></a>给对象使用私有或受保护的成员变量</h3><ul><li>对<code>public</code>方法和属性进行修改非常危险,因为外部代码容易依赖他,而你没办法控制。<strong>对之修改影响所有这个类的使用者。</strong> <code>public</code> methods and properties are most dangerous for changes, because some outside code may easily rely on them and you can’t control what code relies on them. <strong>Modifications in class are dangerous for all users of class.</strong></li><li>对<code>protected</code>的修改跟对<code>public</code>修改差不多危险,因为他们对子类可用,他俩的唯一区别就是可调用的位置不一样,<strong>对之修改影响所有集成这个类的地方。</strong> <code>protected</code> modifier are as dangerous as public, because they are available in scope of any child class. This effectively means that difference between public and protected is only in access mechanism, but encapsulation guarantee remains the same. <strong>Modifications in class are dangerous for all descendant classes.</strong></li><li>对<code>private</code>的修改保证了这部分代码<strong>只会影响当前类</strong><code>private</code> modifier guarantees that code is <strong>dangerous to modify only in boundaries of single class</strong> (you are safe for modifications and you won’t have <a href="http://www.urbandictionary.com/define.php?term=Jengaphobia&defid=2494196">Jenga effect</a>).</li></ul><p>所以,当你需要控制类里的代码可以被访问时才用<code>public/protected</code>,其他时候都用<code>private</code>。</p><p>可以读一读这篇 <a href="http://fabien.potencier.org/pragmatism-over-theory-protected-vs-private.html">博客文章</a> ,<a href="https://github.com/fabpot">Fabien Potencier</a>写的.</p><p><strong>坏:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Employee</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="variable">$name</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$name</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->name = <span class="variable">$name</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="variable">$employee</span> = <span class="keyword">new</span> Employee(<span class="string">'John Doe'</span>);</span><br><span class="line"><span class="keyword">echo</span> <span class="string">'Employee name: '</span>.<span class="variable">$employee</span>->name; <span class="comment">// Employee name: John Doe</span></span><br></pre></td></tr></table></figure><p><strong>好:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Employee</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$name</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$name</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->name = <span class="variable">$name</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">getName</span>(<span class="params"></span>): <span class="title">string</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->name;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="variable">$employee</span> = <span class="keyword">new</span> Employee(<span class="string">'John Doe'</span>);</span><br><span class="line"><span class="keyword">echo</span> <span class="string">'Employee name: '</span>.<span class="variable">$employee</span>->getName(); <span class="comment">// Employee name: John Doe</span></span><br></pre></td></tr></table></figure><p><strong><a href="#%E7%9B%AE%E5%BD%95">⬆ 返回顶部</a></strong></p><h2 id="类"><a href="#类" class="headerlink" title="类"></a>类</h2><h3 id="少用继承多用组合"><a href="#少用继承多用组合" class="headerlink" title="少用继承多用组合"></a>少用继承多用组合</h3><p>正如 the Gang of Four 所著的<a href="https://en.wikipedia.org/wiki/Design_Patterns"><em>设计模式</em></a>之前所说,<br>我们应该尽量优先选择组合而不是继承的方式。使用继承和组合都有很多好处。<br>这个准则的主要意义在于当你本能的使用继承时,试着思考一下<code>组合</code>是否能更好对你的需求建模。<br>在一些情况下,是这样的。</p><p>接下来你或许会想,“那我应该在什么时候使用继承?”<br>答案依赖于你的问题,当然下面有一些何时继承比组合更好的说明:</p><ol><li>你的继承表达了“是一个”而不是“有一个”的关系(人类-》动物,用户-》用户详情)</li><li>你可以复用基类的代码(人类可以像动物一样移动)</li><li>你想通过修改基类对所有派生类做全局的修改(当动物移动时,修改她们的能量消耗)</li></ol><p><strong>糟糕的:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Employee</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$name</span>;</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$email</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$name</span>, <span class="keyword">string</span> <span class="variable">$email</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->name = <span class="variable">$name</span>;</span><br><span class="line"> <span class="keyword">$this</span>->email = <span class="variable">$email</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 不好,因为 Employees "有" taxdata</span></span><br><span class="line"><span class="comment">// 而 EmployeeTaxData 不是 Employee 类型的</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">EmployeeTaxData</span> <span class="keyword">extends</span> <span class="title">Employee</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$ssn</span>;</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$salary</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$name</span>, <span class="keyword">string</span> <span class="variable">$email</span>, <span class="keyword">string</span> <span class="variable">$ssn</span>, <span class="keyword">string</span> <span class="variable">$salary</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="built_in">parent</span>::__construct(<span class="variable">$name</span>, <span class="variable">$email</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">$this</span>->ssn = <span class="variable">$ssn</span>;</span><br><span class="line"> <span class="keyword">$this</span>->salary = <span class="variable">$salary</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>好:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">EmployeeTaxData</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$ssn</span>;</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$salary</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$ssn</span>, <span class="keyword">string</span> <span class="variable">$salary</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->ssn = <span class="variable">$ssn</span>;</span><br><span class="line"> <span class="keyword">$this</span>->salary = <span class="variable">$salary</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Employee</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$name</span>;</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$email</span>;</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$taxData</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$name</span>, <span class="keyword">string</span> <span class="variable">$email</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->name = <span class="variable">$name</span>;</span><br><span class="line"> <span class="keyword">$this</span>->email = <span class="variable">$email</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">setTaxData</span>(<span class="params">EmployeeTaxData <span class="variable">$taxData</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->taxData = <span class="variable">$taxData</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong><a href="#%E7%9B%AE%E5%BD%95">⬆ 返回顶部</a></strong></p><h3 id="避免连贯接口"><a href="#避免连贯接口" class="headerlink" title="避免连贯接口"></a>避免连贯接口</h3><p><a href="https://en.wikipedia.org/wiki/Fluent_interface">连贯接口Fluent interface</a>是一种<br>旨在提高面向对象编程时代码可读性的API设计模式,他基于<a href="https://en.wikipedia.org/wiki/Method_chaining">方法链Method chaining</a></p><p>有上下文的地方可以降低代码复杂度,例如<a href="https://phpunit.de/manual/current/en/test-doubles.html">PHPUnit Mock Builder</a><br>和<a href="http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/query-builder.html">Doctrine Query Builder</a><br>,更多的情况会带来较大代价:</p><p>While there can be some contexts, frequently builder objects, where this<br>pattern reduces the verbosity of the code (for example the <a href="https://phpunit.de/manual/current/en/test-doubles.html">PHPUnit Mock Builder</a><br>or the <a href="http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/query-builder.html">Doctrine Query Builder</a>),<br>more often it comes at some costs:</p><ol><li>破坏了 <a href="https://en.wikipedia.org/wiki/Encapsulation_%28object-oriented_programming%29">对象封装</a></li><li>破坏了 <a href="https://en.wikipedia.org/wiki/Decorator_pattern">装饰器模式</a></li><li>在测试组件中不好做<a href="https://en.wikipedia.org/wiki/Mock_object">mock</a></li><li>导致提交的diff不好阅读</li></ol><p>了解更多请阅读 <a href="https://ocramius.github.io/blog/fluent-interfaces-are-evil/">连贯接口为什么不好</a><br>,作者 <a href="https://github.com/Ocramius">Marco Pivetta</a>.</p><p><strong>坏:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Car</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$make</span> = <span class="string">'Honda'</span>;</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$model</span> = <span class="string">'Accord'</span>;</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$color</span> = <span class="string">'white'</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">setMake</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$make</span></span>): <span class="title">self</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->make = <span class="variable">$make</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// <span class="doctag">NOTE:</span> Returning this for chaining</span></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">setModel</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$model</span></span>): <span class="title">self</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->model = <span class="variable">$model</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// <span class="doctag">NOTE:</span> Returning this for chaining</span></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">setColor</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$color</span></span>): <span class="title">self</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->color = <span class="variable">$color</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// <span class="doctag">NOTE:</span> Returning this for chaining</span></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">dump</span>(<span class="params"></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> var_dump(<span class="keyword">$this</span>->make, <span class="keyword">$this</span>->model, <span class="keyword">$this</span>->color);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="variable">$car</span> = (<span class="keyword">new</span> Car())</span><br><span class="line"> ->setColor(<span class="string">'pink'</span>)</span><br><span class="line"> ->setMake(<span class="string">'Ford'</span>)</span><br><span class="line"> ->setModel(<span class="string">'F-150'</span>)</span><br><span class="line"> ->dump();</span><br></pre></td></tr></table></figure><p><strong>好:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Car</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$make</span> = <span class="string">'Honda'</span>;</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$model</span> = <span class="string">'Accord'</span>;</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$color</span> = <span class="string">'white'</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">setMake</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$make</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->make = <span class="variable">$make</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">setModel</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$model</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->model = <span class="variable">$model</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">setColor</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$color</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->color = <span class="variable">$color</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">dump</span>(<span class="params"></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> var_dump(<span class="keyword">$this</span>->make, <span class="keyword">$this</span>->model, <span class="keyword">$this</span>->color);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="variable">$car</span> = <span class="keyword">new</span> Car();</span><br><span class="line"><span class="variable">$car</span>->setColor(<span class="string">'pink'</span>);</span><br><span class="line"><span class="variable">$car</span>->setMake(<span class="string">'Ford'</span>);</span><br><span class="line"><span class="variable">$car</span>->setModel(<span class="string">'F-150'</span>);</span><br><span class="line"><span class="variable">$car</span>->dump();</span><br></pre></td></tr></table></figure><p><strong><a href="#%E7%9B%AE%E5%BD%95">⬆ 返回顶部</a></strong></p><h3 id="推荐使用-final-类"><a href="#推荐使用-final-类" class="headerlink" title="推荐使用 final 类"></a>推荐使用 final 类</h3><p>能用时尽量使用 <code>final</code> 关键字:</p><ol><li>阻止不受控的继承链</li><li>鼓励 <a href="#%E5%B0%91%E7%94%A8%E7%BB%A7%E6%89%BF%E5%A4%9A%E7%94%A8%E7%BB%84%E5%90%88">组合</a>.</li><li>鼓励 <a href="#%E5%8D%95%E4%B8%80%E8%81%8C%E8%B4%A3%E6%A8%A1%E5%BC%8F">单一职责模式</a>.</li><li>鼓励开发者用你的公开方法而非通过继承类获取受保护方法的访问权限.</li><li>使得在不破坏使用你的类的应用的情况下修改代码成为可能.</li></ol><p>The only condition is that your class should implement an interface and no other public methods are defined.</p><p>For more informations you can read <a href="https://ocramius.github.io/blog/when-to-declare-classes-final/">the blog post</a> on this topic written by <a href="https://ocramius.github.io/">Marco Pivetta (Ocramius)</a>.</p><p><strong>Bad:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">final</span> <span class="class"><span class="keyword">class</span> <span class="title">Car</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$color</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"><span class="variable">$color</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->color = <span class="variable">$color</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> string The color of the vehicle</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">getColor</span>(<span class="params"></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->color;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>Good:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">interface</span> <span class="title">Vehicle</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> string The color of the vehicle</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">getColor</span>(<span class="params"></span>)</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">final</span> <span class="class"><span class="keyword">class</span> <span class="title">Car</span> <span class="keyword">implements</span> <span class="title">Vehicle</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$color</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"><span class="variable">$color</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->color = <span class="variable">$color</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * {<span class="doctag">@inheritdoc</span>}</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">getColor</span>(<span class="params"></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->color;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong><a href="#%E7%9B%AE%E5%BD%95">⬆ 返回顶部</a></strong></p><h2 id="SOLID"><a href="#SOLID" class="headerlink" title="SOLID"></a>SOLID</h2><p><strong>SOLID</strong> 是Michael Feathers推荐的便于记忆的首字母简写,它代表了Robert Martin命名的最重要的五个面对对象编码设计原则</p><ul><li><a href="#%E8%81%8C%E8%B4%A3%E5%8E%9F%E5%88%99">S: 单一职责原则 (SRP)</a></li><li><a href="#%E5%BC%80%E9%97%AD%E5%8E%9F%E5%88%99">O: 开闭原则 (OCP)</a></li><li><a href="#%E9%87%8C%E6%B0%8F%E6%9B%BF%E6%8D%A2%E5%8E%9F%E5%88%99">L: 里氏替换原则 (LSP)</a></li><li><a href="#%E6%8E%A5%E5%8F%A3%E9%9A%94%E7%A6%BB%E5%8E%9F%E5%88%99">I: 接口隔离原则 (ISP)</a></li><li><a href="#%E4%BE%9D%E8%B5%96%E5%80%92%E7%BD%AE%E5%8E%9F%E5%88%99">D: 依赖倒置原则 (DIP)</a></li></ul><h3 id="单一职责原则"><a href="#单一职责原则" class="headerlink" title="单一职责原则"></a>单一职责原则</h3><p>Single Responsibility Principle (SRP)</p><p>正如在Clean Code所述,”修改一个类应该只为一个理由”。<br>人们总是易于用一堆方法塞满一个类,如同我们只能在飞机上<br>只能携带一个行李箱(把所有的东西都塞到箱子里)。这样做<br>的问题是:从概念上这样的类不是高内聚的,并且留下了很多<br>理由去修改它。将你需要修改类的次数降低到最小很重要。<br>这是因为,当有很多方法在类中时,修改其中一处,你很难知<br>晓在代码库中哪些依赖的模块会被影响到。</p><p><strong>坏:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">UserSettings</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$user</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params">User <span class="variable">$user</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->user = <span class="variable">$user</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">changeSettings</span>(<span class="params"><span class="keyword">array</span> <span class="variable">$settings</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">$this</span>->verifyCredentials()) {</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="function"><span class="keyword">function</span> <span class="title">verifyCredentials</span>(<span class="params"></span>): <span class="title">bool</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>好:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">UserAuth</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$user</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params">User <span class="variable">$user</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->user = <span class="variable">$user</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">verifyCredentials</span>(<span class="params"></span>): <span class="title">bool</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">UserSettings</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$user</span>;</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$auth</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params">User <span class="variable">$user</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->user = <span class="variable">$user</span>;</span><br><span class="line"> <span class="keyword">$this</span>->auth = <span class="keyword">new</span> UserAuth(<span class="variable">$user</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">changeSettings</span>(<span class="params"><span class="keyword">array</span> <span class="variable">$settings</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">$this</span>->auth->verifyCredentials()) {</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong><a href="#%E7%9B%AE%E5%BD%95">⬆ 返回顶部</a></strong></p><h3 id="开闭原则"><a href="#开闭原则" class="headerlink" title="开闭原则"></a>开闭原则</h3><p>Open/Closed Principle (OCP)</p><p>正如Bertrand Meyer所述,”软件的工件( classes, modules, functions 等)<br>应该对扩展开放,对修改关闭。” 然而这句话意味着什么呢?这个原则大体上表示你<br>应该允许在不改变已有代码的情况下增加新的功能</p><p><strong>坏:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">Adapter</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">protected</span> <span class="variable">$name</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">getName</span>(<span class="params"></span>): <span class="title">string</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->name;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">AjaxAdapter</span> <span class="keyword">extends</span> <span class="title">Adapter</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="built_in">parent</span>::__construct();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">$this</span>->name = <span class="string">'ajaxAdapter'</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">NodeAdapter</span> <span class="keyword">extends</span> <span class="title">Adapter</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="built_in">parent</span>::__construct();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">$this</span>->name = <span class="string">'nodeAdapter'</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">HttpRequester</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$adapter</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params">Adapter <span class="variable">$adapter</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->adapter = <span class="variable">$adapter</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">fetch</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$url</span></span>): <span class="title">Promise</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="variable">$adapterName</span> = <span class="keyword">$this</span>->adapter->getName();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$adapterName</span> === <span class="string">'ajaxAdapter'</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->makeAjaxCall(<span class="variable">$url</span>);</span><br><span class="line"> } <span class="keyword">elseif</span> (<span class="variable">$adapterName</span> === <span class="string">'httpNodeAdapter'</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->makeHttpCall(<span class="variable">$url</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="function"><span class="keyword">function</span> <span class="title">makeAjaxCall</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$url</span></span>): <span class="title">Promise</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">// request and return promise</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="function"><span class="keyword">function</span> <span class="title">makeHttpCall</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$url</span></span>): <span class="title">Promise</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">// request and return promise</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>好:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">interface</span> <span class="title">Adapter</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">request</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$url</span></span>): <span class="title">Promise</span></span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">AjaxAdapter</span> <span class="keyword">implements</span> <span class="title">Adapter</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">request</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$url</span></span>): <span class="title">Promise</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">// request and return promise</span></span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">NodeAdapter</span> <span class="keyword">implements</span> <span class="title">Adapter</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">request</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$url</span></span>): <span class="title">Promise</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">// request and return promise</span></span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">HttpRequester</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$adapter</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params">Adapter <span class="variable">$adapter</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->adapter = <span class="variable">$adapter</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">fetch</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$url</span></span>): <span class="title">Promise</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->adapter->request(<span class="variable">$url</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong><a href="#%E7%9B%AE%E5%BD%95">⬆ 返回顶部</a></strong></p><h3 id="里氏替换原则"><a href="#里氏替换原则" class="headerlink" title="里氏替换原则"></a>里氏替换原则</h3><p>Liskov Substitution Principle (LSP)</p><p>这是一个简单的原则,却用了一个不好理解的术语。它的正式定义是<br>“如果S是T的子类型,那么在不改变程序原有既定属性(检查、执行<br>任务等)的前提下,任何T类型的对象都可以使用S类型的对象替代<br>(例如,使用S的对象可以替代T的对象)” 这个定义更难理解:-)。</p><p>对这个概念最好的解释是:如果你有一个父类和一个子类,在不改变<br>原有结果正确性的前提下父类和子类可以互换。这个听起来依旧让人<br>有些迷惑,所以让我们来看一个经典的正方形-长方形的例子。从数学<br>上讲,正方形是一种长方形,但是当你的模型通过继承使用了”is-a”<br>的关系时,就不对了。</p><p><strong>坏:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Rectangle</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">protected</span> <span class="variable">$width</span> = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">protected</span> <span class="variable">$height</span> = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">setWidth</span>(<span class="params"><span class="keyword">int</span> <span class="variable">$width</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->width = <span class="variable">$width</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">setHeight</span>(<span class="params"><span class="keyword">int</span> <span class="variable">$height</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->height = <span class="variable">$height</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">getArea</span>(<span class="params"></span>): <span class="title">int</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->width * <span class="keyword">$this</span>->height;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Square</span> <span class="keyword">extends</span> <span class="title">Rectangle</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">setWidth</span>(<span class="params"><span class="keyword">int</span> <span class="variable">$width</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->width = <span class="keyword">$this</span>->height = <span class="variable">$width</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">setHeight</span>(<span class="params"><span class="keyword">int</span> <span class="variable">$height</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->width = <span class="keyword">$this</span>->height = <span class="variable">$height</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">printArea</span>(<span class="params">Rectangle <span class="variable">$rectangle</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="variable">$rectangle</span>->setWidth(<span class="number">4</span>);</span><br><span class="line"> <span class="variable">$rectangle</span>->setHeight(<span class="number">5</span>);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// BAD: Will return 25 for Square. Should be 20.</span></span><br><span class="line"> <span class="keyword">echo</span> sprintf(<span class="string">'%s has area %d.'</span>, get_class(<span class="variable">$rectangle</span>), <span class="variable">$rectangle</span>->getArea()).PHP_EOL;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="variable">$rectangles</span> = [<span class="keyword">new</span> Rectangle(), <span class="keyword">new</span> Square()];</span><br><span class="line"></span><br><span class="line"><span class="keyword">foreach</span> (<span class="variable">$rectangles</span> <span class="keyword">as</span> <span class="variable">$rectangle</span>) {</span><br><span class="line"> printArea(<span class="variable">$rectangle</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>好:</strong></p><p>最好是将这两种四边形分别对待,用一个适合两种类型的更通用子类型来代替。</p><p>尽管正方形和长方形看起来很相似,但他们是不同的。<br>正方形更接近菱形,而长方形更接近平行四边形。但他们不是子类型。<br>尽管相似,正方形、长方形、菱形、平行四边形都是有自己属性的不同形状。</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">interface</span> <span class="title">Shape</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">getArea</span>(<span class="params"></span>): <span class="title">int</span></span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Rectangle</span> <span class="keyword">implements</span> <span class="title">Shape</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$width</span> = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$height</span> = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"><span class="keyword">int</span> <span class="variable">$width</span>, <span class="keyword">int</span> <span class="variable">$height</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->width = <span class="variable">$width</span>;</span><br><span class="line"> <span class="keyword">$this</span>->height = <span class="variable">$height</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">getArea</span>(<span class="params"></span>): <span class="title">int</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->width * <span class="keyword">$this</span>->height;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Square</span> <span class="keyword">implements</span> <span class="title">Shape</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$length</span> = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"><span class="keyword">int</span> <span class="variable">$length</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->length = <span class="variable">$length</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">getArea</span>(<span class="params"></span>): <span class="title">int</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->length ** <span class="number">2</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">printArea</span>(<span class="params">Shape <span class="variable">$shape</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">echo</span> sprintf(<span class="string">'%s has area %d.'</span>, get_class(<span class="variable">$shape</span>), <span class="variable">$shape</span>->getArea()).PHP_EOL;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="variable">$shapes</span> = [<span class="keyword">new</span> Rectangle(<span class="number">4</span>, <span class="number">5</span>), <span class="keyword">new</span> Square(<span class="number">5</span>)];</span><br><span class="line"></span><br><span class="line"><span class="keyword">foreach</span> (<span class="variable">$shapes</span> <span class="keyword">as</span> <span class="variable">$shape</span>) {</span><br><span class="line"> printArea(<span class="variable">$shape</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong><a href="#%E7%9B%AE%E5%BD%95">⬆ 返回顶部</a></strong></p><h3 id="接口隔离原则"><a href="#接口隔离原则" class="headerlink" title="接口隔离原则"></a>接口隔离原则</h3><p>Interface Segregation Principle (ISP)</p><p>接口隔离原则表示:”调用方不应该被强制依赖于他不需要的接口”</p><p>有一个清晰的例子来说明示范这条原则。当一个类需要一个大量的设置项,<br>为了方便不会要求调用方去设置大量的选项,因为在通常他们不需要所有的<br>设置项。使设置项可选有助于我们避免产生”胖接口”</p><p><strong>坏:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">interface</span> <span class="title">Employee</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">work</span>(<span class="params"></span>): <span class="title">void</span></span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">eat</span>(<span class="params"></span>): <span class="title">void</span></span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">HumanEmployee</span> <span class="keyword">implements</span> <span class="title">Employee</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">work</span>(<span class="params"></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">// ....working</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">eat</span>(<span class="params"></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">// ...... eating in lunch break</span></span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">RobotEmployee</span> <span class="keyword">implements</span> <span class="title">Employee</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">work</span>(<span class="params"></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">//.... working much more</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">eat</span>(<span class="params"></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">//.... robot can't eat, but it must implement this method</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>好:</strong></p><p>不是每一个工人都是雇员,但是每一个雇员都是一个工人</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">interface</span> <span class="title">Workable</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">work</span>(<span class="params"></span>): <span class="title">void</span></span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">interface</span> <span class="title">Feedable</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">eat</span>(<span class="params"></span>): <span class="title">void</span></span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">interface</span> <span class="title">Employee</span> <span class="keyword">extends</span> <span class="title">Feedable</span>, <span class="title">Workable</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">HumanEmployee</span> <span class="keyword">implements</span> <span class="title">Employee</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">work</span>(<span class="params"></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">// ....working</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">eat</span>(<span class="params"></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">//.... eating in lunch break</span></span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// robot can only work</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">RobotEmployee</span> <span class="keyword">implements</span> <span class="title">Workable</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">work</span>(<span class="params"></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">// ....working</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong><a href="#%E7%9B%AE%E5%BD%95">⬆ 返回顶部</a></strong></p><h3 id="依赖倒置原则"><a href="#依赖倒置原则" class="headerlink" title="依赖倒置原则"></a>依赖倒置原则</h3><p>Dependency Inversion Principle (DIP)</p><p>这条原则说明两个基本的要点:</p><ol><li>高阶的模块不应该依赖低阶的模块,它们都应该依赖于抽象</li><li>抽象不应该依赖于实现,实现应该依赖于抽象</li></ol><p>这条起初看起来有点晦涩难懂,但是如果你使用过 PHP 框架(例如 Symfony),你应该见过<br>依赖注入(DI),它是对这个概念的实现。虽然它们不是完全相等的概念,依赖倒置原则使高阶模块<br>与低阶模块的实现细节和创建分离。可以使用依赖注入(DI)这种方式来实现它。最大的好处<br>是它使模块之间解耦。耦合会导致你难于重构,它是一种非常糟糕的的开发模式。</p><p><strong>坏:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Employee</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">work</span>(<span class="params"></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">// ....working</span></span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Robot</span> <span class="keyword">extends</span> <span class="title">Employee</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">work</span>(<span class="params"></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">//.... working much more</span></span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Manager</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$employee</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params">Employee <span class="variable">$employee</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->employee = <span class="variable">$employee</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">manage</span>(<span class="params"></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->employee->work();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>好:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">interface</span> <span class="title">Employee</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">work</span>(<span class="params"></span>): <span class="title">void</span></span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Human</span> <span class="keyword">implements</span> <span class="title">Employee</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">work</span>(<span class="params"></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">// ....working</span></span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Robot</span> <span class="keyword">implements</span> <span class="title">Employee</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">work</span>(<span class="params"></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">//.... working much more</span></span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Manager</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$employee</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params">Employee <span class="variable">$employee</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->employee = <span class="variable">$employee</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">manage</span>(<span class="params"></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->employee->work();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong><a href="#%E7%9B%AE%E5%BD%95">⬆ 返回顶部</a></strong></p><h2 id="别写重复代码-DRY"><a href="#别写重复代码-DRY" class="headerlink" title="别写重复代码 (DRY)"></a>别写重复代码 (DRY)</h2><p>试着去遵循<a href="https://en.wikipedia.org/wiki/Don%27t_repeat_yourself">DRY</a> 原则.</p><p>尽你最大的努力去避免复制代码,它是一种非常糟糕的行为,复制代码<br>通常意味着当你需要变更一些逻辑时,你需要修改不止一处。</p><p>试想一下,如果你在经营一家餐厅并且你在记录你仓库的进销记录:所有<br>的土豆,洋葱,大蒜,辣椒等。如果你有多个列表来管理进销记录,当你<br>用其中一些土豆做菜时你需要更新所有的列表。如果你只有一个列表的话<br>只有一个地方需要更新。</p><p>通常情况下你复制代码是应该有两个或者多个略微不同的逻辑,它们大多数<br>都是一样的,但是由于它们的区别致使你必须有两个或者多个隔离的但大部<br>分相同的方法,移除重复的代码意味着用一个function/module/class创<br>建一个能处理差异的抽象。</p><p>用对抽象非常关键,这正是为什么你必须学习遵守在<a href="#%E7%B1%BB">类</a>章节写<br>的SOLID原则,不合理的抽象比复制代码更糟糕,所以务必谨慎!说了这么多,<br>如果你能设计一个合理的抽象,那就这么干!别写重复代码,否则你会发现<br>任何时候当你想修改一个逻辑时你必须修改多个地方。</p><p><strong>坏:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">showDeveloperList</span>(<span class="params"><span class="keyword">array</span> <span class="variable">$developers</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable">$developers</span> <span class="keyword">as</span> <span class="variable">$developer</span>) {</span><br><span class="line"> <span class="variable">$expectedSalary</span> = <span class="variable">$developer</span>->calculateExpectedSalary();</span><br><span class="line"> <span class="variable">$experience</span> = <span class="variable">$developer</span>->getExperience();</span><br><span class="line"> <span class="variable">$githubLink</span> = <span class="variable">$developer</span>->getGithubLink();</span><br><span class="line"> <span class="variable">$data</span> = [</span><br><span class="line"> <span class="variable">$expectedSalary</span>,</span><br><span class="line"> <span class="variable">$experience</span>,</span><br><span class="line"> <span class="variable">$githubLink</span></span><br><span class="line"> ];</span><br><span class="line"></span><br><span class="line"> render(<span class="variable">$data</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">showManagerList</span>(<span class="params"><span class="keyword">array</span> <span class="variable">$managers</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable">$managers</span> <span class="keyword">as</span> <span class="variable">$manager</span>) {</span><br><span class="line"> <span class="variable">$expectedSalary</span> = <span class="variable">$manager</span>->calculateExpectedSalary();</span><br><span class="line"> <span class="variable">$experience</span> = <span class="variable">$manager</span>->getExperience();</span><br><span class="line"> <span class="variable">$githubLink</span> = <span class="variable">$manager</span>->getGithubLink();</span><br><span class="line"> <span class="variable">$data</span> = [</span><br><span class="line"> <span class="variable">$expectedSalary</span>,</span><br><span class="line"> <span class="variable">$experience</span>,</span><br><span class="line"> <span class="variable">$githubLink</span></span><br><span class="line"> ];</span><br><span class="line"></span><br><span class="line"> render(<span class="variable">$data</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>好:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">showList</span>(<span class="params"><span class="keyword">array</span> <span class="variable">$employees</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable">$employees</span> <span class="keyword">as</span> <span class="variable">$employee</span>) {</span><br><span class="line"> <span class="variable">$expectedSalary</span> = <span class="variable">$employee</span>->calculateExpectedSalary();</span><br><span class="line"> <span class="variable">$experience</span> = <span class="variable">$employee</span>->getExperience();</span><br><span class="line"> <span class="variable">$githubLink</span> = <span class="variable">$employee</span>->getGithubLink();</span><br><span class="line"> <span class="variable">$data</span> = [</span><br><span class="line"> <span class="variable">$expectedSalary</span>,</span><br><span class="line"> <span class="variable">$experience</span>,</span><br><span class="line"> <span class="variable">$githubLink</span></span><br><span class="line"> ];</span><br><span class="line"></span><br><span class="line"> render(<span class="variable">$data</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>极好:</strong></p><p>最好让代码紧凑一点</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">showList</span>(<span class="params"><span class="keyword">array</span> <span class="variable">$employees</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable">$employees</span> <span class="keyword">as</span> <span class="variable">$employee</span>) {</span><br><span class="line"> render([</span><br><span class="line"> <span class="variable">$employee</span>->calculateExpectedSalary(),</span><br><span class="line"> <span class="variable">$employee</span>->getExperience(),</span><br><span class="line"> <span class="variable">$employee</span>->getGithubLink()</span><br><span class="line"> ]);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong><a href="#%E7%9B%AE%E5%BD%95">⬆ 返回顶部</a></strong></p><h2 id="翻译"><a href="#翻译" class="headerlink" title="翻译"></a>翻译</h2><p>其他语言的翻译:</p><ul><li>:cn: <strong>Chinese:</strong><ul><li><a href="https://github.com/php-cpm/clean-code-php">php-cpm/clean-code-php</a></li></ul></li><li>:ru: <strong>Russian:</strong><ul><li><a href="https://github.com/peter-gribanov/clean-code-php">peter-gribanov/clean-code-php</a></li></ul></li><li>:es: <strong>Spanish:</strong><ul><li><a href="https://github.com/fikoborquez/clean-code-php">fikoborquez/clean-code-php</a></li></ul></li><li>:brazil: <strong>Portuguese:</strong><ul><li><a href="https://github.com/fabioars/clean-code-php">fabioars/clean-code-php</a></li><li><a href="https://github.com/jeanjar/clean-code-php/tree/pt-br">jeanjar/clean-code-php</a></li></ul></li><li>:thailand: <strong>Thai:</strong><ul><li><a href="https://github.com/panuwizzle/clean-code-php">panuwizzle/clean-code-php</a></li></ul></li><li>:fr: <strong>French:</strong><ul><li><a href="https://github.com/errorname/clean-code-php">errorname/clean-code-php</a></li></ul></li><li>:vietnam: <strong>Vietnamese</strong><ul><li><a href="https://github.com/viethuongdev/clean-code-php">viethuongdev/clean-code-php</a></li></ul></li><li>:kr: <strong>Korean:</strong><ul><li><a href="https://github.com/yujineeee/clean-code-php">yujineeee/clean-code-php</a></li></ul></li><li>:tr: <strong>Turkish:</strong><ul><li><a href="https://github.com/anilozmen/clean-code-php">anilozmen/clean-code-php</a></li></ul></li></ul><p><strong><a href="#%E7%9B%AE%E5%BD%95">⬆ 返回顶部</a></strong></p>]]></content>
<categories>
<category> PHP </category>
</categories>
<tags>
<tag> PHP </tag>
<tag> 规范 </tag>
</tags>
</entry>
<entry>
<title>ThinkPHP5.1 实现 ThinkPHP3.1 的 SessionDB 类</title>
<link href="/2021/11/2fdcec466251/"/>
<url>/2021/11/2fdcec466251/</url>
<content type="html"><![CDATA[<p><code>ThinkPHP5.1</code> 实现 <code>ThinkPHP3.1</code> 的 <code>SessionDB</code> 类,完成 <code>Session</code> 写入到 <code>MySQL</code> 的操作</p><span id="more"></span><h1 id="第一种实现"><a href="#第一种实现" class="headerlink" title="第一种实现"></a>第一种实现</h1><h2 id="建表语句"><a href="#建表语句" class="headerlink" title="建表语句"></a>建表语句</h2><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">CREATE</span> <span class="keyword">TABLE</span> think_session (</span><br><span class="line"> session_id <span class="type">varchar</span>(<span class="number">255</span>) <span class="keyword">NOT</span> <span class="keyword">NULL</span>,</span><br><span class="line"> session_expire <span class="type">int</span>(<span class="number">11</span>) UNSIGNED <span class="keyword">NOT</span> <span class="keyword">NULL</span>,</span><br><span class="line"> session_data <span class="type">blob</span>,</span><br><span class="line"> <span class="keyword">UNIQUE</span> KEY `session_id` (`session_id`)</span><br><span class="line">);</span><br></pre></td></tr></table></figure><h2 id="建立数据库驱动扩展类-extend-driver-session-Mysql-php"><a href="#建立数据库驱动扩展类-extend-driver-session-Mysql-php" class="headerlink" title="建立数据库驱动扩展类 /extend/driver/session/Mysql.php"></a>建立数据库驱动扩展类 /extend/driver/session/Mysql.php</h2><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta"><?php</span></span><br><span class="line"> </span><br><span class="line"><span class="keyword">namespace</span> <span class="title">driver</span>\<span class="title">session</span>;</span><br><span class="line"> </span><br><span class="line"><span class="keyword">use</span> <span class="title">SessionHandler</span>;</span><br><span class="line"><span class="keyword">use</span> <span class="title">think</span>\<span class="title">Db</span>;</span><br><span class="line"><span class="keyword">use</span> <span class="title">think</span>\<span class="title">Config</span>;</span><br><span class="line"><span class="keyword">use</span> <span class="title">think</span>\<span class="title">Exception</span>;</span><br><span class="line"> </span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Class Mysql</span></span><br><span class="line"><span class="comment"> * session 数据库驱动</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@package</span> driver\session</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Mysql</span> <span class="keyword">extends</span> <span class="title">SessionHandler</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">protected</span> <span class="variable">$handler</span> = <span class="literal">null</span>;</span><br><span class="line"> <span class="keyword">protected</span> <span class="variable">$table_name</span> = <span class="literal">null</span>;</span><br><span class="line"> <span class="keyword">protected</span> <span class="variable">$config</span> = [</span><br><span class="line"> <span class="string">'session_expire'</span> => <span class="number">3600</span>, <span class="comment">// Session有效期 单位:秒</span></span><br><span class="line"> <span class="string">'session_prefix'</span> => <span class="string">'think_'</span>, <span class="comment">// Session前缀</span></span><br><span class="line"> <span class="string">'table_name'</span> => <span class="string">'session'</span>, <span class="comment">// 表名(不包含表前缀)</span></span><br><span class="line"> ];</span><br><span class="line"> <span class="keyword">protected</span> <span class="variable">$database</span> = [</span><br><span class="line"> <span class="string">'type'</span> => <span class="string">'mysql'</span>, <span class="comment">// 数据库类型</span></span><br><span class="line"> <span class="string">'hostname'</span> => <span class="string">'127.0.0.1'</span>, <span class="comment">// 服务器地址</span></span><br><span class="line"> <span class="string">'database'</span> => <span class="string">'my_test'</span>, <span class="comment">// 数据库名</span></span><br><span class="line"> <span class="string">'username'</span> => <span class="string">'root'</span>, <span class="comment">// 用户名</span></span><br><span class="line"> <span class="string">'password'</span> => <span class="string">''</span>, <span class="comment">// 密码</span></span><br><span class="line"> <span class="string">'hostport'</span> => <span class="string">'3306'</span>, <span class="comment">// 端口</span></span><br><span class="line"> <span class="string">'prefix'</span> => <span class="string">''</span>, <span class="comment">// 表前缀</span></span><br><span class="line"> <span class="string">'charset'</span> => <span class="string">'utf8'</span>, <span class="comment">// 数据库编码</span></span><br><span class="line"> <span class="string">'debug'</span> => <span class="literal">true</span>, <span class="comment">// 数据库调试模式</span></span><br><span class="line"> ];</span><br><span class="line"> </span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Mysql constructor.</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> array $config</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> Exception</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"><span class="variable">$config</span> = []</span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">// 获取数据库配置</span></span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">isset</span>(<span class="variable">$config</span>[<span class="string">'database'</span>]) && !<span class="keyword">empty</span>(<span class="variable">$config</span>[<span class="string">'database'</span>])) {</span><br><span class="line"> <span class="keyword">if</span> (is_array(<span class="variable">$config</span>[<span class="string">'database'</span>])) {</span><br><span class="line"> <span class="variable">$database</span> = <span class="variable">$config</span>[<span class="string">'database'</span>];</span><br><span class="line"> } <span class="keyword">elseif</span> (is_string(<span class="variable">$config</span>[<span class="string">'database'</span>])) {</span><br><span class="line"> <span class="variable">$database</span> = Config::get(<span class="variable">$config</span>[<span class="string">'database'</span>]);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="built_in">Exception</span>(<span class="string">'session error:database'</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">unset</span>(<span class="variable">$config</span>[<span class="string">'database'</span>]);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="comment">// 使用默认的数据库配置</span></span><br><span class="line"> <span class="variable">$database</span> = Config::get(<span class="string">'database'</span>);</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">$this</span>->config = array_merge(<span class="keyword">$this</span>->config, <span class="variable">$config</span>);</span><br><span class="line"> <span class="keyword">$this</span>->database = array_merge(<span class="keyword">$this</span>->database, <span class="variable">$database</span>);</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 打开Session</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@access</span> public</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> string $save_path</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> mixed $session_name</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> bool</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> Exception</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">open</span>(<span class="params"><span class="variable">$save_path</span>, <span class="variable">$session_name</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">// 判断数据库配置是否可用</span></span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">empty</span>(<span class="keyword">$this</span>->database)) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="built_in">Exception</span>(<span class="string">'session error:database empty'</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">$this</span>->handler = Db::connect(<span class="keyword">$this</span>->database);</span><br><span class="line"> <span class="keyword">$this</span>->table_name = <span class="keyword">$this</span>->database[<span class="string">'prefix'</span>] . <span class="keyword">$this</span>->config[<span class="string">'table_name'</span>];</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 关闭Session</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@access</span> public</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">close</span>(<span class="params"></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->gc(ini_get(<span class="string">'session.gc_maxlifetime'</span>));</span><br><span class="line"> <span class="keyword">$this</span>->handler = <span class="literal">null</span>;</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 读取Session</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@access</span> public</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> string $session_id</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> bool|string</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">read</span>(<span class="params"><span class="variable">$session_id</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="variable">$where</span> = [</span><br><span class="line"> <span class="string">'session_id'</span> => <span class="keyword">$this</span>->config[<span class="string">'session_prefix'</span>] . <span class="variable">$session_id</span>,</span><br><span class="line"> <span class="string">'session_expire'</span> => time()</span><br><span class="line"> ];</span><br><span class="line"> <span class="variable">$sql</span> = <span class="string">'SELECT session_data FROM '</span> . <span class="keyword">$this</span>->table_name . <span class="string">' WHERE session_id = :session_id AND session_expire > :session_expire'</span>;</span><br><span class="line"> <span class="variable">$result</span> = <span class="keyword">$this</span>->handler->query(<span class="variable">$sql</span>, <span class="variable">$where</span>);</span><br><span class="line"> <span class="keyword">if</span> (!<span class="keyword">empty</span>(<span class="variable">$result</span>)) {</span><br><span class="line"> <span class="keyword">return</span> <span class="variable">$result</span>[<span class="number">0</span>][<span class="string">'session_data'</span>];</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="string">''</span>;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 写入Session</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@access</span> public</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> string $session_id</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> String $session_data</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> bool</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">write</span>(<span class="params"><span class="variable">$session_id</span>, <span class="variable">$session_data</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="variable">$params</span> = [</span><br><span class="line"> <span class="string">'session_id'</span> => <span class="keyword">$this</span>->config[<span class="string">'session_prefix'</span>] . <span class="variable">$session_id</span>,</span><br><span class="line"> <span class="string">'session_expire'</span> => <span class="keyword">$this</span>->config[<span class="string">'session_expire'</span>] + time(),</span><br><span class="line"> <span class="string">'session_data'</span> => <span class="variable">$session_data</span></span><br><span class="line"> ];</span><br><span class="line"> <span class="variable">$sql</span> = <span class="string">'REPLACE INTO '</span> . <span class="keyword">$this</span>->table_name . <span class="string">' (session_id, session_expire, session_data) VALUES (:session_id, :session_expire, :session_data)'</span>;</span><br><span class="line"> <span class="variable">$result</span> = <span class="keyword">$this</span>->handler->execute(<span class="variable">$sql</span>, <span class="variable">$params</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="variable">$result</span> ? <span class="literal">true</span> : <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 删除Session</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@access</span> public</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> string $session_id</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> bool|void</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">destroy</span>(<span class="params"><span class="variable">$session_id</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="variable">$where</span> = [</span><br><span class="line"> <span class="string">'session_id'</span> => <span class="keyword">$this</span>->config[<span class="string">'session_prefix'</span>] . <span class="variable">$session_id</span></span><br><span class="line"> ];</span><br><span class="line"> <span class="variable">$sql</span> = <span class="string">'DELETE FROM '</span> . <span class="keyword">$this</span>->table_name . <span class="string">' WHERE session_id = :session_id'</span>;</span><br><span class="line"> <span class="variable">$result</span> = <span class="keyword">$this</span>->handler->execute(<span class="variable">$sql</span>, <span class="variable">$where</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="variable">$result</span> ? <span class="literal">true</span> : <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Session 垃圾回收</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@access</span> public</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> string $sessMaxLifeTime</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> bool</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">gc</span>(<span class="params"><span class="variable">$sessMaxLifeTime</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="variable">$sql</span> = <span class="string">'DELETE FROM '</span> . <span class="keyword">$this</span>->table_name . <span class="string">' WHERE session_expire < :session_expire'</span>;</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->handler->execute(<span class="variable">$sql</span>, [<span class="string">'session_expire'</span> => time()]);</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="Session-的配置"><a href="#Session-的配置" class="headerlink" title="Session 的配置"></a>Session 的配置</h2><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">'session'</span> => [</span><br><span class="line"> <span class="string">'type'</span> => <span class="string">'driver\session\Mysql'</span>,</span><br><span class="line"> <span class="string">'auto_start'</span> => <span class="literal">true</span>,</span><br><span class="line"> <span class="string">'session_expire'</span> => <span class="number">3600</span>,</span><br><span class="line"> <span class="string">'session_prefix'</span> => <span class="string">'think_'</span>,</span><br><span class="line"> <span class="string">'table_name'</span> => <span class="string">'think_session'</span>,</span><br><span class="line"> <span class="string">'database'</span> => [</span><br><span class="line"> <span class="string">'hostname'</span> => <span class="string">'127.0.0.1'</span>,</span><br><span class="line"> <span class="string">'database'</span> => <span class="string">''</span>,</span><br><span class="line"> <span class="string">'username'</span> => <span class="string">'root'</span>,</span><br><span class="line"> <span class="string">'password'</span> => <span class="string">''</span>,</span><br><span class="line"> <span class="string">'hostport'</span> => <span class="string">'3306'</span>,</span><br><span class="line"> <span class="string">'prefix'</span> => <span class="string">''</span>,</span><br><span class="line"> <span class="string">'charset'</span> => <span class="string">'utf8'</span>,</span><br><span class="line"> ]</span><br><span class="line">],</span><br></pre></td></tr></table></figure><h1 id="第二种实现"><a href="#第二种实现" class="headerlink" title="第二种实现"></a>第二种实现</h1><h2 id="建表语句-1"><a href="#建表语句-1" class="headerlink" title="建表语句"></a>建表语句</h2><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">CREATE</span> <span class="keyword">TABLE</span> `think_session` (</span><br><span class="line"> `session_id` <span class="type">varchar</span>(<span class="number">255</span>) <span class="type">CHARACTER</span> <span class="keyword">SET</span> utf8 <span class="keyword">NOT</span> <span class="keyword">NULL</span>,</span><br><span class="line"> `session_expire` <span class="type">int</span>(<span class="number">11</span>) <span class="keyword">NOT</span> <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="string">'0'</span> COMMENT <span class="string">'SESSION的过期时间'</span>,</span><br><span class="line"> `session_data` <span class="type">blob</span> COMMENT <span class="string">'SESSION的数据内容'</span>,</span><br><span class="line"> `user_name` <span class="type">varchar</span>(<span class="number">255</span>) <span class="type">CHARACTER</span> <span class="keyword">SET</span> utf8 <span class="keyword">COLLATE</span> utf8_general_ci <span class="keyword">NOT</span> <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="string">''</span>,</span><br><span class="line"> `ip` <span class="type">varchar</span>(<span class="number">255</span>) <span class="type">CHARACTER</span> <span class="keyword">SET</span> utf8 <span class="keyword">COLLATE</span> utf8_general_ci <span class="keyword">NOT</span> <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="string">''</span>,</span><br><span class="line"> <span class="keyword">UNIQUE</span> KEY `session_id` (`session_id`),</span><br><span class="line"> KEY `NewIndex1` (`session_expire`),</span><br><span class="line"> KEY `Uname` (`user_name`)</span><br><span class="line">) ENGINE<span class="operator">=</span>InnoDB <span class="keyword">DEFAULT</span> CHARSET<span class="operator">=</span>utf8mb4 <span class="keyword">COLLATE</span><span class="operator">=</span>utf8mb4_unicode_ci</span><br></pre></td></tr></table></figure><h2 id="Mysql-类"><a href="#Mysql-类" class="headerlink" title="Mysql 类"></a><code>Mysql</code> 类</h2><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">namespace</span> <span class="title">think</span>\<span class="title">session</span>\<span class="title">driver</span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">use</span> <span class="title">SessionHandlerInterface</span>; <span class="comment">//PHP实现预留session接口</span></span><br><span class="line"><span class="keyword">use</span> <span class="title">think</span>\<span class="title">Db</span>;</span><br><span class="line"><span class="keyword">use</span> <span class="title">think</span>\<span class="title">Exception</span>;</span><br><span class="line"><span class="keyword">use</span> <span class="title">think</span>\<span class="title">facade</span>\<span class="title">Config</span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Mysql</span> <span class="keyword">implements</span> <span class="title">SessionHandlerInterface</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">protected</span> <span class="variable">$handler</span> = <span class="literal">null</span>;</span><br><span class="line"> <span class="keyword">protected</span> <span class="variable">$config</span> = [</span><br><span class="line"> <span class="string">'hostname'</span> => <span class="string">''</span>,<span class="comment">// 服务器地址</span></span><br><span class="line"> <span class="string">'database'</span> => <span class="string">''</span>,<span class="comment">// 数据库名</span></span><br><span class="line"> <span class="string">'username'</span> => <span class="string">''</span>,<span class="comment">// 用户名</span></span><br><span class="line"> <span class="string">'password'</span> => <span class="string">''</span>,<span class="comment">// 密码</span></span><br><span class="line"> <span class="string">'hostport'</span> => <span class="string">''</span>,<span class="comment">// 端口</span></span><br><span class="line"> <span class="string">'charset'</span> => <span class="string">''</span>, <span class="comment">// 数据库编码默认采用utf8</span></span><br><span class="line"> <span class="string">'expire'</span> => <span class="number">3600</span>, <span class="comment">// session有效期</span></span><br><span class="line"> <span class="string">'session_name'</span> => <span class="string">''</span>, <span class="comment">// sessionkey前缀</span></span><br><span class="line"> <span class="string">'session_table'</span> => <span class="string">''</span>, <span class="comment">// session存储的数据表名称</span></span><br><span class="line"> ];</span><br><span class="line"> <span class="keyword">protected</span> <span class="variable">$table_name</span> = <span class="literal">null</span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"><span class="variable">$config</span> = []</span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">//获取数据库配置,将数据库配置更新</span></span><br><span class="line"> <span class="keyword">$this</span>->config = array_merge(<span class="keyword">$this</span>->config, Config::get(<span class="string">'database.'</span>), <span class="variable">$config</span>);</span><br><span class="line"> <span class="keyword">$this</span>->table_name = <span class="keyword">empty</span>(<span class="keyword">$this</span>->config[<span class="string">'session_table'</span>]) ? <span class="keyword">$this</span>->config[<span class="string">'prefix'</span>] . <span class="string">'_session'</span> : <span class="keyword">$this</span>->config[<span class="string">'session_table'</span>];</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 打开Session</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@access</span> public</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> string $savePath</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> mixed $sessName</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">open</span>(<span class="params"><span class="variable">$savePath</span>, <span class="variable">$sessName</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">empty</span>(<span class="keyword">$this</span>->config[<span class="string">'hostname'</span>])) <span class="keyword">throw</span> <span class="keyword">new</span> <span class="built_in">Exception</span>(<span class="string">'database config error'</span>);</span><br><span class="line"> <span class="keyword">$this</span>->handler = Db::connect(<span class="keyword">$this</span>->config);</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 关闭Session</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@access</span> public</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">close</span>(<span class="params"></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->gc(ini_get(<span class="string">'session.gc_maxlifetime'</span>));</span><br><span class="line"> <span class="keyword">$this</span>->handler = <span class="literal">null</span>;</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 读取Session</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@access</span> public</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> string $sessID</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">read</span>(<span class="params"><span class="variable">$sessID</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">return</span> (<span class="keyword">string</span>)Db::table(<span class="keyword">$this</span>->table_name)->where([[<span class="string">'session_id'</span>, <span class="string">'='</span>, <span class="keyword">$this</span>->config[<span class="string">'session_name'</span>] . <span class="variable">$sessID</span>], [<span class="string">'session_expire'</span>, <span class="string">'>='</span>, time()]])->value(<span class="string">'session_data'</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 写入Session</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@access</span> public</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> string $sessID</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> string $sessData</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> bool</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">write</span>(<span class="params"><span class="variable">$sessID</span>, <span class="variable">$sessData</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">//获取通过session传入的隐藏参数,用于其他操作</span></span><br><span class="line"> <span class="variable">$unserialize_session_data</span> = unserialize(explode(<span class="string">'|'</span>, <span class="variable">$sessData</span>)[<span class="number">1</span>]);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="comment">//构建存入数据库的数据</span></span><br><span class="line"> <span class="variable">$params</span> = [</span><br><span class="line"> <span class="string">'session_id'</span> => <span class="keyword">$this</span>->config[<span class="string">'session_name'</span>] . <span class="variable">$sessID</span>,</span><br><span class="line"> <span class="string">'session_expire'</span> => <span class="keyword">$this</span>->config[<span class="string">'expire'</span>] + time(),</span><br><span class="line"> <span class="string">'session_data'</span> => <span class="variable">$sessData</span>, </span><br><span class="line"> <span class="string">'user_name'</span> => <span class="variable">$user_name</span>,</span><br><span class="line"> <span class="string">'ip'</span> => get_ip(),</span><br><span class="line"> </span><br><span class="line"> ];</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="variable">$sql</span> = <span class="string">"REPLACE INTO <span class="subst">{$this->table_name}</span> (session_id,session_expire,session_data,user_name,ip) VALUES (:session_id, :session_expire, :session_data,:user_name,:ip)"</span>;</span><br><span class="line"> <span class="variable">$result</span> = <span class="keyword">$this</span>->handler->execute(<span class="variable">$sql</span>, <span class="variable">$params</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="variable">$result</span> ? <span class="literal">true</span> : <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 删除Session</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@access</span> public</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> string $sessID</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> bool</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">destroy</span>(<span class="params"><span class="variable">$sessID</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="variable">$result</span> = <span class="keyword">$this</span>->handler->execute(<span class="string">"DELETE FROM <span class="subst">{$this->table_name}</span> WHERE session_id = :session_id"</span>, [<span class="string">'session_id'</span> => <span class="keyword">$this</span>->config[<span class="string">'session_name'</span>] . <span class="variable">$sessID</span>]);</span><br><span class="line"> <span class="keyword">return</span> <span class="variable">$result</span> ? <span class="literal">true</span> : <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Session 垃圾回收</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@access</span> public</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> string $sessMaxLifeTime</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> true</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">gc</span>(<span class="params"><span class="variable">$sessMaxLifeTime</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="variable">$result</span> = <span class="keyword">$this</span>->handler->execute(<span class="string">"DELETE FROM <span class="subst">{$this->table_name}</span> WHERE session_expire < :session_expire"</span>, [<span class="string">'session_expire'</span> => time()]);</span><br><span class="line"> <span class="keyword">return</span> <span class="variable">$result</span> ? <span class="literal">true</span> : <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category> PHP </category>
</categories>
<tags>
<tag> PHP </tag>
<tag> ThinkPHP </tag>
</tags>
</entry>
<entry>
<title>Clean Code PHP</title>
<link href="/2021/11/fb9e3928c774/"/>
<url>/2021/11/fb9e3928c774/</url>
<content type="html"><![CDATA[<h1 id="Clean-Code-PHP"><a href="#Clean-Code-PHP" class="headerlink" title="Clean Code PHP"></a>Clean Code PHP</h1><h2 id="Introduction"><a href="#Introduction" class="headerlink" title="Introduction"></a>Introduction</h2><p>Software engineering principles, from Robert C. Martin’s book<br><a href="https://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882"><em>Clean Code</em></a>,<br>adapted for PHP. This is not a style guide. It’s a guide to producing<br>readable, reusable, and refactorable software in PHP.</p><span id="more"></span><p>Not every principle herein has to be strictly followed, and even fewer will be universally<br>agreed upon. These are guidelines and nothing more, but they are ones codified over many<br>years of collective experience by the authors of <em>Clean Code</em>.</p><p>Inspired from <a href="https://github.com/ryanmcdermott/clean-code-javascript">clean-code-javascript</a>.</p><p>Although many developers still use PHP 5, most of the examples in this article only work with PHP 7.1+.</p><h2 id="Variables"><a href="#Variables" class="headerlink" title="Variables"></a>Variables</h2><h3 id="Use-meaningful-and-pronounceable-variable-names"><a href="#Use-meaningful-and-pronounceable-variable-names" class="headerlink" title="Use meaningful and pronounceable variable names"></a>Use meaningful and pronounceable variable names</h3><p><strong>Bad:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$ymdstr</span> = <span class="variable">$moment</span>->format(<span class="string">'y-m-d'</span>);</span><br></pre></td></tr></table></figure><p><strong>Good:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$currentDate</span> = <span class="variable">$moment</span>->format(<span class="string">'y-m-d'</span>);</span><br></pre></td></tr></table></figure><p><strong><a href="#table-of-contents">⬆ back to top</a></strong></p><h3 id="Use-the-same-vocabulary-for-the-same-type-of-variable"><a href="#Use-the-same-vocabulary-for-the-same-type-of-variable" class="headerlink" title="Use the same vocabulary for the same type of variable"></a>Use the same vocabulary for the same type of variable</h3><p><strong>Bad:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">getUserInfo();</span><br><span class="line">getUserData();</span><br><span class="line">getUserRecord();</span><br><span class="line">getUserProfile();</span><br></pre></td></tr></table></figure><p><strong>Good:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">getUser();</span><br></pre></td></tr></table></figure><p><strong><a href="#table-of-contents">⬆ back to top</a></strong></p><h3 id="Use-searchable-names-part-1"><a href="#Use-searchable-names-part-1" class="headerlink" title="Use searchable names (part 1)"></a>Use searchable names (part 1)</h3><p>We will read more code than we will ever write. It’s important that the code we do write is<br>readable and searchable. By <em>not</em> naming variables that end up being meaningful for<br>understanding our program, we hurt our readers.<br>Make your names searchable.</p><p><strong>Bad:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// What the heck is 448 for?</span></span><br><span class="line"><span class="variable">$result</span> = <span class="variable">$serializer</span>->serialize(<span class="variable">$data</span>, <span class="number">448</span>);</span><br></pre></td></tr></table></figure><p><strong>Good:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$json</span> = <span class="variable">$serializer</span>->serialize(<span class="variable">$data</span>, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);</span><br></pre></td></tr></table></figure><h3 id="Use-searchable-names-part-2"><a href="#Use-searchable-names-part-2" class="headerlink" title="Use searchable names (part 2)"></a>Use searchable names (part 2)</h3><p><strong>Bad:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">User</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="comment">// What the heck is 7 for?</span></span><br><span class="line"> <span class="keyword">public</span> <span class="variable">$access</span> = <span class="number">7</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// What the heck is 4 for?</span></span><br><span class="line"><span class="keyword">if</span> (<span class="variable">$user</span>->access & <span class="number">4</span>) {</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// What's going on here?</span></span><br><span class="line"><span class="variable">$user</span>->access ^= <span class="number">2</span>;</span><br></pre></td></tr></table></figure><p><strong>Good:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">User</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">const</span> ACCESS_READ = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">const</span> ACCESS_CREATE = <span class="number">2</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">const</span> ACCESS_UPDATE = <span class="number">4</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">const</span> ACCESS_DELETE = <span class="number">8</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// User as default can read, create and update something</span></span><br><span class="line"> <span class="keyword">public</span> <span class="variable">$access</span> = <span class="built_in">self</span>::ACCESS_READ | <span class="built_in">self</span>::ACCESS_CREATE | <span class="built_in">self</span>::ACCESS_UPDATE;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (<span class="variable">$user</span>->access & User::ACCESS_UPDATE) {</span><br><span class="line"> <span class="comment">// do edit ...</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// Deny access rights to create something</span></span><br><span class="line"><span class="variable">$user</span>->access ^= User::ACCESS_CREATE;</span><br></pre></td></tr></table></figure><p><strong><a href="#table-of-contents">⬆ back to top</a></strong></p><h3 id="Use-explanatory-variables"><a href="#Use-explanatory-variables" class="headerlink" title="Use explanatory variables"></a>Use explanatory variables</h3><p><strong>Bad:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$address</span> = <span class="string">'One Infinite Loop, Cupertino 95014'</span>;</span><br><span class="line"><span class="variable">$cityZipCodeRegex</span> = <span class="string">'/^[^,]+,\s*(.+?)\s*(\d{5})$/'</span>;</span><br><span class="line">preg_match(<span class="variable">$cityZipCodeRegex</span>, <span class="variable">$address</span>, <span class="variable">$matches</span>);</span><br><span class="line"></span><br><span class="line">saveCityZipCode(<span class="variable">$matches</span>[<span class="number">1</span>], <span class="variable">$matches</span>[<span class="number">2</span>]);</span><br></pre></td></tr></table></figure><p><strong>Not bad:</strong></p><p>It’s better, but we are still heavily dependent on regex.</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$address</span> = <span class="string">'One Infinite Loop, Cupertino 95014'</span>;</span><br><span class="line"><span class="variable">$cityZipCodeRegex</span> = <span class="string">'/^[^,]+,\s*(.+?)\s*(\d{5})$/'</span>;</span><br><span class="line">preg_match(<span class="variable">$cityZipCodeRegex</span>, <span class="variable">$address</span>, <span class="variable">$matches</span>);</span><br><span class="line"></span><br><span class="line">[, <span class="variable">$city</span>, <span class="variable">$zipCode</span>] = <span class="variable">$matches</span>;</span><br><span class="line">saveCityZipCode(<span class="variable">$city</span>, <span class="variable">$zipCode</span>);</span><br></pre></td></tr></table></figure><p><strong>Good:</strong></p><p>Decrease dependence on regex by naming subpatterns.</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$address</span> = <span class="string">'One Infinite Loop, Cupertino 95014'</span>;</span><br><span class="line"><span class="variable">$cityZipCodeRegex</span> = <span class="string">'/^[^,]+,\s*(?<city>.+?)\s*(?<zipCode>\d{5})$/'</span>;</span><br><span class="line">preg_match(<span class="variable">$cityZipCodeRegex</span>, <span class="variable">$address</span>, <span class="variable">$matches</span>);</span><br><span class="line"></span><br><span class="line">saveCityZipCode(<span class="variable">$matches</span>[<span class="string">'city'</span>], <span class="variable">$matches</span>[<span class="string">'zipCode'</span>]);</span><br></pre></td></tr></table></figure><p><strong><a href="#table-of-contents">⬆ back to top</a></strong></p><h3 id="Avoid-nesting-too-deeply-and-return-early-part-1"><a href="#Avoid-nesting-too-deeply-and-return-early-part-1" class="headerlink" title="Avoid nesting too deeply and return early (part 1)"></a>Avoid nesting too deeply and return early (part 1)</h3><p>Too many if-else statements can make your code hard to follow. Explicit is better<br>than implicit.</p><p><strong>Bad:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">isShopOpen</span>(<span class="params"><span class="variable">$day</span></span>): <span class="title">bool</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$day</span>) {</span><br><span class="line"> <span class="keyword">if</span> (is_string(<span class="variable">$day</span>)) {</span><br><span class="line"> <span class="variable">$day</span> = strtolower(<span class="variable">$day</span>);</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$day</span> === <span class="string">'friday'</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line"> } <span class="keyword">elseif</span> (<span class="variable">$day</span> === <span class="string">'saturday'</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line"> } <span class="keyword">elseif</span> (<span class="variable">$day</span> === <span class="string">'sunday'</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>Good:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">isShopOpen</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$day</span></span>): <span class="title">bool</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">empty</span>(<span class="variable">$day</span>)) {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="variable">$openingDays</span> = [<span class="string">'friday'</span>, <span class="string">'saturday'</span>, <span class="string">'sunday'</span>];</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> in_array(strtolower(<span class="variable">$day</span>), <span class="variable">$openingDays</span>, <span class="literal">true</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong><a href="#table-of-contents">⬆ back to top</a></strong></p><h3 id="Avoid-nesting-too-deeply-and-return-early-part-2"><a href="#Avoid-nesting-too-deeply-and-return-early-part-2" class="headerlink" title="Avoid nesting too deeply and return early (part 2)"></a>Avoid nesting too deeply and return early (part 2)</h3><p><strong>Bad:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">fibonacci</span>(<span class="params"><span class="keyword">int</span> <span class="variable">$n</span></span>)</span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$n</span> < <span class="number">50</span>) {</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$n</span> !== <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$n</span> !== <span class="number">1</span>) {</span><br><span class="line"> <span class="keyword">return</span> fibonacci(<span class="variable">$n</span> - <span class="number">1</span>) + fibonacci(<span class="variable">$n</span> - <span class="number">2</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="string">'Not supported'</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>Good:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">fibonacci</span>(<span class="params"><span class="keyword">int</span> <span class="variable">$n</span></span>): <span class="title">int</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$n</span> === <span class="number">0</span> || <span class="variable">$n</span> === <span class="number">1</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="variable">$n</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$n</span> >= <span class="number">50</span>) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="built_in">Exception</span>(<span class="string">'Not supported'</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> fibonacci(<span class="variable">$n</span> - <span class="number">1</span>) + fibonacci(<span class="variable">$n</span> - <span class="number">2</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong><a href="#table-of-contents">⬆ back to top</a></strong></p><h3 id="Avoid-Mental-Mapping"><a href="#Avoid-Mental-Mapping" class="headerlink" title="Avoid Mental Mapping"></a>Avoid Mental Mapping</h3><p>Don’t force the reader of your code to translate what the variable means.<br>Explicit is better than implicit.</p><p><strong>Bad:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$l</span> = [<span class="string">'Austin'</span>, <span class="string">'New York'</span>, <span class="string">'San Francisco'</span>];</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (<span class="variable">$i</span> = <span class="number">0</span>; <span class="variable">$i</span> < count(<span class="variable">$l</span>); <span class="variable">$i</span>++) {</span><br><span class="line"> <span class="variable">$li</span> = <span class="variable">$l</span>[<span class="variable">$i</span>];</span><br><span class="line"> doStuff();</span><br><span class="line"> doSomeOtherStuff();</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> <span class="comment">// Wait, what is `$li` for again?</span></span><br><span class="line"> dispatch(<span class="variable">$li</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>Good:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$locations</span> = [<span class="string">'Austin'</span>, <span class="string">'New York'</span>, <span class="string">'San Francisco'</span>];</span><br><span class="line"></span><br><span class="line"><span class="keyword">foreach</span> (<span class="variable">$locations</span> <span class="keyword">as</span> <span class="variable">$location</span>) {</span><br><span class="line"> doStuff();</span><br><span class="line"> doSomeOtherStuff();</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> dispatch(<span class="variable">$location</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong><a href="#table-of-contents">⬆ back to top</a></strong></p><h3 id="Don’t-add-unneeded-context"><a href="#Don’t-add-unneeded-context" class="headerlink" title="Don’t add unneeded context"></a>Don’t add unneeded context</h3><p>If your class/object name tells you something, don’t repeat that in your<br>variable name.</p><p><strong>Bad:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Car</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="variable">$carMake</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="variable">$carModel</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="variable">$carColor</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">//...</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>Good:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Car</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="variable">$make</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="variable">$model</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="variable">$color</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">//...</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong><a href="#table-of-contents">⬆ back to top</a></strong></p><h2 id="Comparison"><a href="#Comparison" class="headerlink" title="Comparison"></a>Comparison</h2><h3 id="Use-identical-comparison"><a href="#Use-identical-comparison" class="headerlink" title="Use identical comparison"></a>Use <a href="http://php.net/manual/en/language.operators.comparison.php">identical comparison</a></h3><p><strong>Not good:</strong></p><p>The simple comparison will convert the string in an integer.</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$a</span> = <span class="string">'42'</span>;</span><br><span class="line"><span class="variable">$b</span> = <span class="number">42</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (<span class="variable">$a</span> != <span class="variable">$b</span>) {</span><br><span class="line"> <span class="comment">// The expression will always pass</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>The comparison <code>$a != $b</code> returns <code>FALSE</code> but in fact it’s <code>TRUE</code>!<br>The string <code>42</code> is different than the integer <code>42</code>.</p><p><strong>Good:</strong></p><p>The identical comparison will compare type and value.</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$a</span> = <span class="string">'42'</span>;</span><br><span class="line"><span class="variable">$b</span> = <span class="number">42</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (<span class="variable">$a</span> !== <span class="variable">$b</span>) {</span><br><span class="line"> <span class="comment">// The expression is verified</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>The comparison <code>$a !== $b</code> returns <code>TRUE</code>.</p><p><strong><a href="#table-of-contents">⬆ back to top</a></strong></p><h3 id="Null-coalescing-operator"><a href="#Null-coalescing-operator" class="headerlink" title="Null coalescing operator"></a>Null coalescing operator</h3><p>Null coalescing is a new operator <a href="https://www.php.net/manual/en/migration70.new-features.php">introduced in PHP 7</a>. The null coalescing operator <code>??</code> has been added as syntactic sugar for the common case of needing to use a ternary in conjunction with <code>isset()</code>. It returns its first operand if it exists and is not <code>null</code>; otherwise it returns its second operand.</p><p><strong>Bad:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (<span class="keyword">isset</span>(<span class="variable">$_GET</span>[<span class="string">'name'</span>])) {</span><br><span class="line"> <span class="variable">$name</span> = <span class="variable">$_GET</span>[<span class="string">'name'</span>];</span><br><span class="line">} <span class="keyword">elseif</span> (<span class="keyword">isset</span>(<span class="variable">$_POST</span>[<span class="string">'name'</span>])) {</span><br><span class="line"> <span class="variable">$name</span> = <span class="variable">$_POST</span>[<span class="string">'name'</span>];</span><br><span class="line">} <span class="keyword">else</span> {</span><br><span class="line"> <span class="variable">$name</span> = <span class="string">'nobody'</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>Good:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$name</span> = <span class="variable">$_GET</span>[<span class="string">'name'</span>] ?? <span class="variable">$_POST</span>[<span class="string">'name'</span>] ?? <span class="string">'nobody'</span>;</span><br></pre></td></tr></table></figure><p><strong><a href="#table-of-contents">⬆ back to top</a></strong></p><h2 id="Functions"><a href="#Functions" class="headerlink" title="Functions"></a>Functions</h2><h3 id="Use-default-arguments-instead-of-short-circuiting-or-conditionals"><a href="#Use-default-arguments-instead-of-short-circuiting-or-conditionals" class="headerlink" title="Use default arguments instead of short circuiting or conditionals"></a>Use default arguments instead of short circuiting or conditionals</h3><p><strong>Not good:</strong></p><p>This is not good because <code>$breweryName</code> can be <code>NULL</code>.</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">createMicrobrewery</span>(<span class="params"><span class="variable">$breweryName</span> = <span class="string">'Hipster Brew Co.'</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>Not bad:</strong></p><p>This opinion is more understandable than the previous version, but it better controls the value of the variable.</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">createMicrobrewery</span>(<span class="params"><span class="variable">$name</span> = <span class="literal">null</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="variable">$breweryName</span> = <span class="variable">$name</span> ?: <span class="string">'Hipster Brew Co.'</span>;</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>Good:</strong></p><p> You can use <a href="http://php.net/manual/en/functions.arguments.php#functions.arguments.type-declaration">type hinting</a> and be sure that the <code>$breweryName</code> will not be <code>NULL</code>.</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">createMicrobrewery</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$breweryName</span> = <span class="string">'Hipster Brew Co.'</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong><a href="#table-of-contents">⬆ back to top</a></strong></p><h3 id="Function-arguments-2-or-fewer-ideally"><a href="#Function-arguments-2-or-fewer-ideally" class="headerlink" title="Function arguments (2 or fewer ideally)"></a>Function arguments (2 or fewer ideally)</h3><p>Limiting the amount of function parameters is incredibly important because it makes<br>testing your function easier. Having more than three leads to a combinatorial explosion<br>where you have to test tons of different cases with each separate argument.</p><p>Zero arguments is the ideal case. One or two arguments is ok, and three should be avoided.<br>Anything more than that should be consolidated. Usually, if you have more than two<br>arguments then your function is trying to do too much. In cases where it’s not, most<br>of the time a higher-level object will suffice as an argument.</p><p><strong>Bad:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Questionnaire</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"></span></span></span><br><span class="line"><span class="params"><span class="function"> <span class="keyword">string</span> <span class="variable">$firstname</span>,</span></span></span><br><span class="line"><span class="params"><span class="function"> <span class="keyword">string</span> <span class="variable">$lastname</span>,</span></span></span><br><span class="line"><span class="params"><span class="function"> <span class="keyword">string</span> <span class="variable">$patronymic</span>,</span></span></span><br><span class="line"><span class="params"><span class="function"> <span class="keyword">string</span> <span class="variable">$region</span>,</span></span></span><br><span class="line"><span class="params"><span class="function"> <span class="keyword">string</span> <span class="variable">$district</span>,</span></span></span><br><span class="line"><span class="params"><span class="function"> <span class="keyword">string</span> <span class="variable">$city</span>,</span></span></span><br><span class="line"><span class="params"><span class="function"> <span class="keyword">string</span> <span class="variable">$phone</span>,</span></span></span><br><span class="line"><span class="params"><span class="function"> <span class="keyword">string</span> <span class="variable">$email</span></span></span></span><br><span class="line"><span class="params"><span class="function"> </span>) </span>{</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>Good:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Name</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$firstname</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$lastname</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$patronymic</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$firstname</span>, <span class="keyword">string</span> <span class="variable">$lastname</span>, <span class="keyword">string</span> <span class="variable">$patronymic</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->firstname = <span class="variable">$firstname</span>;</span><br><span class="line"> <span class="keyword">$this</span>->lastname = <span class="variable">$lastname</span>;</span><br><span class="line"> <span class="keyword">$this</span>->patronymic = <span class="variable">$patronymic</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// getters ...</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">City</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$region</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$district</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$city</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$region</span>, <span class="keyword">string</span> <span class="variable">$district</span>, <span class="keyword">string</span> <span class="variable">$city</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->region = <span class="variable">$region</span>;</span><br><span class="line"> <span class="keyword">$this</span>->district = <span class="variable">$district</span>;</span><br><span class="line"> <span class="keyword">$this</span>->city = <span class="variable">$city</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// getters ...</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Contact</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$phone</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$email</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$phone</span>, <span class="keyword">string</span> <span class="variable">$email</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->phone = <span class="variable">$phone</span>;</span><br><span class="line"> <span class="keyword">$this</span>->email = <span class="variable">$email</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// getters ...</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Questionnaire</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params">Name <span class="variable">$name</span>, City <span class="variable">$city</span>, Contact <span class="variable">$contact</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong><a href="#table-of-contents">⬆ back to top</a></strong></p><h3 id="Function-names-should-say-what-they-do"><a href="#Function-names-should-say-what-they-do" class="headerlink" title="Function names should say what they do"></a>Function names should say what they do</h3><p><strong>Bad:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Email</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="comment">//...</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">handle</span>(<span class="params"></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> mail(<span class="keyword">$this</span>->to, <span class="keyword">$this</span>->subject, <span class="keyword">$this</span>->body);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="variable">$message</span> = <span class="keyword">new</span> Email(...);</span><br><span class="line"><span class="comment">// What is this? A handle for the message? Are we writing to a file now?</span></span><br><span class="line"><span class="variable">$message</span>->handle();</span><br></pre></td></tr></table></figure><p><strong>Good:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Email</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="comment">//...</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">send</span>(<span class="params"></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> mail(<span class="keyword">$this</span>->to, <span class="keyword">$this</span>->subject, <span class="keyword">$this</span>->body);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="variable">$message</span> = <span class="keyword">new</span> Email(...);</span><br><span class="line"><span class="comment">// Clear and obvious</span></span><br><span class="line"><span class="variable">$message</span>->send();</span><br></pre></td></tr></table></figure><p><strong><a href="#table-of-contents">⬆ back to top</a></strong></p><h3 id="Functions-should-only-be-one-level-of-abstraction"><a href="#Functions-should-only-be-one-level-of-abstraction" class="headerlink" title="Functions should only be one level of abstraction"></a>Functions should only be one level of abstraction</h3><p>When you have more than one level of abstraction your function is usually<br>doing too much. Splitting up functions leads to reusability and easier<br>testing.</p><p><strong>Bad:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">parseBetterPHPAlternative</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$code</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="variable">$regexes</span> = [</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> ];</span><br><span class="line"></span><br><span class="line"> <span class="variable">$statements</span> = explode(<span class="string">' '</span>, <span class="variable">$code</span>);</span><br><span class="line"> <span class="variable">$tokens</span> = [];</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable">$regexes</span> <span class="keyword">as</span> <span class="variable">$regex</span>) {</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable">$statements</span> <span class="keyword">as</span> <span class="variable">$statement</span>) {</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="variable">$ast</span> = [];</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable">$tokens</span> <span class="keyword">as</span> <span class="variable">$token</span>) {</span><br><span class="line"> <span class="comment">// lex...</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable">$ast</span> <span class="keyword">as</span> <span class="variable">$node</span>) {</span><br><span class="line"> <span class="comment">// parse...</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>Bad too:</strong></p><p>We have carried out some of the functionality, but the <code>parseBetterPHPAlternative()</code> function is still very complex and not testable.</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">tokenize</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$code</span></span>): <span class="title">array</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="variable">$regexes</span> = [</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> ];</span><br><span class="line"></span><br><span class="line"> <span class="variable">$statements</span> = explode(<span class="string">' '</span>, <span class="variable">$code</span>);</span><br><span class="line"> <span class="variable">$tokens</span> = [];</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable">$regexes</span> <span class="keyword">as</span> <span class="variable">$regex</span>) {</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable">$statements</span> <span class="keyword">as</span> <span class="variable">$statement</span>) {</span><br><span class="line"> <span class="variable">$tokens</span>[] = <span class="comment">/* ... */</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="variable">$tokens</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">lexer</span>(<span class="params"><span class="keyword">array</span> <span class="variable">$tokens</span></span>): <span class="title">array</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="variable">$ast</span> = [];</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable">$tokens</span> <span class="keyword">as</span> <span class="variable">$token</span>) {</span><br><span class="line"> <span class="variable">$ast</span>[] = <span class="comment">/* ... */</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="variable">$ast</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">parseBetterPHPAlternative</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$code</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="variable">$tokens</span> = tokenize(<span class="variable">$code</span>);</span><br><span class="line"> <span class="variable">$ast</span> = lexer(<span class="variable">$tokens</span>);</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable">$ast</span> <span class="keyword">as</span> <span class="variable">$node</span>) {</span><br><span class="line"> <span class="comment">// parse...</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>Good:</strong></p><p>The best solution is move out the dependencies of <code>parseBetterPHPAlternative()</code> function.</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Tokenizer</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">tokenize</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$code</span></span>): <span class="title">array</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="variable">$regexes</span> = [</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> ];</span><br><span class="line"></span><br><span class="line"> <span class="variable">$statements</span> = explode(<span class="string">' '</span>, <span class="variable">$code</span>);</span><br><span class="line"> <span class="variable">$tokens</span> = [];</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable">$regexes</span> <span class="keyword">as</span> <span class="variable">$regex</span>) {</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable">$statements</span> <span class="keyword">as</span> <span class="variable">$statement</span>) {</span><br><span class="line"> <span class="variable">$tokens</span>[] = <span class="comment">/* ... */</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="variable">$tokens</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Lexer</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">lexify</span>(<span class="params"><span class="keyword">array</span> <span class="variable">$tokens</span></span>): <span class="title">array</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="variable">$ast</span> = [];</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable">$tokens</span> <span class="keyword">as</span> <span class="variable">$token</span>) {</span><br><span class="line"> <span class="variable">$ast</span>[] = <span class="comment">/* ... */</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="variable">$ast</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">BetterPHPAlternative</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$tokenizer</span>;</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$lexer</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params">Tokenizer <span class="variable">$tokenizer</span>, Lexer <span class="variable">$lexer</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->tokenizer = <span class="variable">$tokenizer</span>;</span><br><span class="line"> <span class="keyword">$this</span>->lexer = <span class="variable">$lexer</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">parse</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$code</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="variable">$tokens</span> = <span class="keyword">$this</span>->tokenizer->tokenize(<span class="variable">$code</span>);</span><br><span class="line"> <span class="variable">$ast</span> = <span class="keyword">$this</span>->lexer->lexify(<span class="variable">$tokens</span>);</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable">$ast</span> <span class="keyword">as</span> <span class="variable">$node</span>) {</span><br><span class="line"> <span class="comment">// parse...</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong><a href="#table-of-contents">⬆ back to top</a></strong></p><h3 id="Don’t-use-flags-as-function-parameters"><a href="#Don’t-use-flags-as-function-parameters" class="headerlink" title="Don’t use flags as function parameters"></a>Don’t use flags as function parameters</h3><p>Flags tell your user that this function does more than one thing. Functions should<br>do one thing. Split out your functions if they are following different code paths<br>based on a boolean.</p><p><strong>Bad:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">createFile</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$name</span>, <span class="keyword">bool</span> <span class="variable">$temp</span> = <span class="literal">false</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$temp</span>) {</span><br><span class="line"> touch(<span class="string">'./temp/'</span> . <span class="variable">$name</span>);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> touch(<span class="variable">$name</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>Good:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">createFile</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$name</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> touch(<span class="variable">$name</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">createTempFile</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$name</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> touch(<span class="string">'./temp/'</span> . <span class="variable">$name</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong><a href="#table-of-contents">⬆ back to top</a></strong></p><h3 id="Avoid-Side-Effects"><a href="#Avoid-Side-Effects" class="headerlink" title="Avoid Side Effects"></a>Avoid Side Effects</h3><p>A function produces a side effect if it does anything other than take a value in and<br>return another value or values. A side effect could be writing to a file, modifying<br>some global variable, or accidentally wiring all your money to a stranger.</p><p>Now, you do need to have side effects in a program on occasion. Like the previous<br>example, you might need to write to a file. What you want to do is to centralize where<br>you are doing this. Don’t have several functions and classes that write to a particular<br>file. Have one service that does it. One and only one.</p><p>The main point is to avoid common pitfalls like sharing state between objects without<br>any structure, using mutable data types that can be written to by anything, and not<br>centralizing where your side effects occur. If you can do this, you will be happier<br>than the vast majority of other programmers.</p><p><strong>Bad:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Global variable referenced by following function.</span></span><br><span class="line"><span class="comment">// If we had another function that used this name, now it'd be an array and it could break it.</span></span><br><span class="line"><span class="variable">$name</span> = <span class="string">'Ryan McDermott'</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">splitIntoFirstAndLastName</span>(<span class="params"></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">global</span> <span class="variable">$name</span>;</span><br><span class="line"></span><br><span class="line"> <span class="variable">$name</span> = explode(<span class="string">' '</span>, <span class="variable">$name</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">splitIntoFirstAndLastName();</span><br><span class="line"></span><br><span class="line">var_dump(<span class="variable">$name</span>);</span><br><span class="line"><span class="comment">// ['Ryan', 'McDermott'];</span></span><br></pre></td></tr></table></figure><p><strong>Good:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">splitIntoFirstAndLastName</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$name</span></span>): <span class="title">array</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">return</span> explode(<span class="string">' '</span>, <span class="variable">$name</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="variable">$name</span> = <span class="string">'Ryan McDermott'</span>;</span><br><span class="line"><span class="variable">$newName</span> = splitIntoFirstAndLastName(<span class="variable">$name</span>);</span><br><span class="line"></span><br><span class="line">var_dump(<span class="variable">$name</span>);</span><br><span class="line"><span class="comment">// 'Ryan McDermott';</span></span><br><span class="line"></span><br><span class="line">var_dump(<span class="variable">$newName</span>);</span><br><span class="line"><span class="comment">// ['Ryan', 'McDermott'];</span></span><br></pre></td></tr></table></figure><p><strong><a href="#table-of-contents">⬆ back to top</a></strong></p><h3 id="Don’t-write-to-global-functions"><a href="#Don’t-write-to-global-functions" class="headerlink" title="Don’t write to global functions"></a>Don’t write to global functions</h3><p>Polluting globals is a bad practice in many languages because you could clash with another<br>library and the user of your API would be none-the-wiser until they get an exception in<br>production. Let’s think about an example: what if you wanted to have configuration array?<br>You could write global function like <code>config()</code>, but it could clash with another library<br>that tried to do the same thing.</p><p><strong>Bad:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">config</span>(<span class="params"></span>): <span class="title">array</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">return</span> [</span><br><span class="line"> <span class="string">'foo'</span> => <span class="string">'bar'</span>,</span><br><span class="line"> ];</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>Good:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Configuration</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$configuration</span> = [];</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"><span class="keyword">array</span> <span class="variable">$configuration</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->configuration = <span class="variable">$configuration</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">get</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$key</span></span>): ?<span class="title">string</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">// null coalescing operator</span></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->configuration[<span class="variable">$key</span>] ?? <span class="literal">null</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>Load configuration and create instance of <code>Configuration</code> class</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$configuration</span> = <span class="keyword">new</span> Configuration([</span><br><span class="line"> <span class="string">'foo'</span> => <span class="string">'bar'</span>,</span><br><span class="line">]);</span><br></pre></td></tr></table></figure><p>And now you must use instance of <code>Configuration</code> in your application.</p><p><strong><a href="#table-of-contents">⬆ back to top</a></strong></p><h3 id="Don’t-use-a-Singleton-pattern"><a href="#Don’t-use-a-Singleton-pattern" class="headerlink" title="Don’t use a Singleton pattern"></a>Don’t use a Singleton pattern</h3><p>Singleton is an <a href="https://en.wikipedia.org/wiki/Singleton_pattern">anti-pattern</a>. Paraphrased from Brian Button:</p><ol><li>They are generally used as a <strong>global instance</strong>, why is that so bad? Because <strong>you hide the dependencies</strong> of your application in your code, instead of exposing them through the interfaces. Making something global to avoid passing it around is a <a href="https://en.wikipedia.org/wiki/Code_smell">code smell</a>.</li><li>They violate the <a href="#single-responsibility-principle-srp">single responsibility principle</a>: by virtue of the fact that <strong>they control their own creation and lifecycle</strong>.</li><li>They inherently cause code to be tightly <a href="https://en.wikipedia.org/wiki/Coupling_%28computer_programming%29">coupled</a>. This makes faking them out under <strong>test rather difficult</strong> in many cases.</li><li>They carry state around for the lifetime of the application. Another hit to testing since <strong>you can end up with a situation where tests need to be ordered</strong> which is a big no for unit tests. Why? Because each unit test should be independent from the other.</li></ol><p>There is also very good thoughts by <a href="http://misko.hevery.com/about/">Misko Hevery</a> about the <a href="http://misko.hevery.com/2008/08/25/root-cause-of-singletons/">root of problem</a>.</p><p><strong>Bad:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">DBConnection</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="built_in">static</span> <span class="variable">$instance</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$dsn</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="built_in">static</span> <span class="function"><span class="keyword">function</span> <span class="title">getInstance</span>(<span class="params"></span>): <span class="title">self</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">self</span>::<span class="variable">$instance</span> === <span class="literal">null</span>) {</span><br><span class="line"> <span class="built_in">self</span>::<span class="variable">$instance</span> = <span class="keyword">new</span> <span class="built_in">self</span>();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">self</span>::<span class="variable">$instance</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="variable">$singleton</span> = DBConnection::getInstance();</span><br></pre></td></tr></table></figure><p><strong>Good:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">DBConnection</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$dsn</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>Create instance of <code>DBConnection</code> class and configure it with <a href="http://php.net/manual/en/pdo.construct.php#refsect1-pdo.construct-parameters">DSN</a>.</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$connection</span> = <span class="keyword">new</span> DBConnection(<span class="variable">$dsn</span>);</span><br></pre></td></tr></table></figure><p>And now you must use instance of <code>DBConnection</code> in your application.</p><p><strong><a href="#table-of-contents">⬆ back to top</a></strong></p><h3 id="Encapsulate-conditionals"><a href="#Encapsulate-conditionals" class="headerlink" title="Encapsulate conditionals"></a>Encapsulate conditionals</h3><p><strong>Bad:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (<span class="variable">$article</span>->state === <span class="string">'published'</span>) {</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>Good:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (<span class="variable">$article</span>->isPublished()) {</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong><a href="#table-of-contents">⬆ back to top</a></strong></p><h3 id="Avoid-negative-conditionals"><a href="#Avoid-negative-conditionals" class="headerlink" title="Avoid negative conditionals"></a>Avoid negative conditionals</h3><p><strong>Bad:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">isDOMNodeNotPresent</span>(<span class="params">DOMNode <span class="variable">$node</span></span>): <span class="title">bool</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (! isDOMNodeNotPresent(<span class="variable">$node</span>)) {</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>Good:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">isDOMNodePresent</span>(<span class="params">DOMNode <span class="variable">$node</span></span>): <span class="title">bool</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (isDOMNodePresent(<span class="variable">$node</span>)) {</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong><a href="#table-of-contents">⬆ back to top</a></strong></p><h3 id="Avoid-conditionals"><a href="#Avoid-conditionals" class="headerlink" title="Avoid conditionals"></a>Avoid conditionals</h3><p>This seems like an impossible task. Upon first hearing this, most people say,<br>“how am I supposed to do anything without an <code>if</code> statement?” The answer is that<br>you can use polymorphism to achieve the same task in many cases. The second<br>question is usually, “well that’s great but why would I want to do that?” The<br>answer is a previous clean code concept we learned: a function should only do<br>one thing. When you have classes and functions that have <code>if</code> statements, you<br>are telling your user that your function does more than one thing. Remember,<br>just do one thing.</p><p><strong>Bad:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Airplane</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">getCruisingAltitude</span>(<span class="params"></span>): <span class="title">int</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">switch</span> (<span class="keyword">$this</span>->type) {</span><br><span class="line"> <span class="keyword">case</span> <span class="string">'777'</span>:</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->getMaxAltitude() - <span class="keyword">$this</span>->getPassengerCount();</span><br><span class="line"> <span class="keyword">case</span> <span class="string">'Air Force One'</span>:</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->getMaxAltitude();</span><br><span class="line"> <span class="keyword">case</span> <span class="string">'Cessna'</span>:</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->getMaxAltitude() - <span class="keyword">$this</span>->getFuelExpenditure();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>Good:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">interface</span> <span class="title">Airplane</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">getCruisingAltitude</span>(<span class="params"></span>): <span class="title">int</span></span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Boeing777</span> <span class="keyword">implements</span> <span class="title">Airplane</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">getCruisingAltitude</span>(<span class="params"></span>): <span class="title">int</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->getMaxAltitude() - <span class="keyword">$this</span>->getPassengerCount();</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">AirForceOne</span> <span class="keyword">implements</span> <span class="title">Airplane</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">getCruisingAltitude</span>(<span class="params"></span>): <span class="title">int</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->getMaxAltitude();</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Cessna</span> <span class="keyword">implements</span> <span class="title">Airplane</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">getCruisingAltitude</span>(<span class="params"></span>): <span class="title">int</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->getMaxAltitude() - <span class="keyword">$this</span>->getFuelExpenditure();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong><a href="#table-of-contents">⬆ back to top</a></strong></p><h3 id="Avoid-type-checking-part-1"><a href="#Avoid-type-checking-part-1" class="headerlink" title="Avoid type-checking (part 1)"></a>Avoid type-checking (part 1)</h3><p>PHP is untyped, which means your functions can take any type of argument.<br>Sometimes you are bitten by this freedom and it becomes tempting to do<br>type-checking in your functions. There are many ways to avoid having to do this.<br>The first thing to consider is consistent APIs.</p><p><strong>Bad:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">travelToTexas</span>(<span class="params"><span class="variable">$vehicle</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$vehicle</span> <span class="keyword">instanceof</span> Bicycle) {</span><br><span class="line"> <span class="variable">$vehicle</span>->pedalTo(<span class="keyword">new</span> Location(<span class="string">'texas'</span>));</span><br><span class="line"> } <span class="keyword">elseif</span> (<span class="variable">$vehicle</span> <span class="keyword">instanceof</span> Car) {</span><br><span class="line"> <span class="variable">$vehicle</span>->driveTo(<span class="keyword">new</span> Location(<span class="string">'texas'</span>));</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>Good:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">travelToTexas</span>(<span class="params">Vehicle <span class="variable">$vehicle</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="variable">$vehicle</span>->travelTo(<span class="keyword">new</span> Location(<span class="string">'texas'</span>));</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong><a href="#table-of-contents">⬆ back to top</a></strong></p><h3 id="Avoid-type-checking-part-2"><a href="#Avoid-type-checking-part-2" class="headerlink" title="Avoid type-checking (part 2)"></a>Avoid type-checking (part 2)</h3><p>If you are working with basic primitive values like strings, integers, and arrays,<br>and you use PHP 7+ and you can’t use polymorphism but you still feel the need to<br>type-check, you should consider<br><a href="http://php.net/manual/en/functions.arguments.php#functions.arguments.type-declaration">type declaration</a><br>or strict mode. It provides you with static typing on top of standard PHP syntax.<br>The problem with manually type-checking is that doing it will require so much<br>extra verbiage that the faux “type-safety” you get doesn’t make up for the lost<br>readability. Keep your PHP clean, write good tests, and have good code reviews.<br>Otherwise, do all of that but with PHP strict type declaration or strict mode.</p><p><strong>Bad:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">combine</span>(<span class="params"><span class="variable">$val1</span>, <span class="variable">$val2</span></span>): <span class="title">int</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (! is_numeric(<span class="variable">$val1</span>) || ! is_numeric(<span class="variable">$val2</span>)) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="built_in">Exception</span>(<span class="string">'Must be of type Number'</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="variable">$val1</span> + <span class="variable">$val2</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>Good:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">combine</span>(<span class="params"><span class="keyword">int</span> <span class="variable">$val1</span>, <span class="keyword">int</span> <span class="variable">$val2</span></span>): <span class="title">int</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="variable">$val1</span> + <span class="variable">$val2</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong><a href="#table-of-contents">⬆ back to top</a></strong></p><h3 id="Remove-dead-code"><a href="#Remove-dead-code" class="headerlink" title="Remove dead code"></a>Remove dead code</h3><p>Dead code is just as bad as duplicate code. There’s no reason to keep it in<br>your codebase. If it’s not being called, get rid of it! It will still be safe<br>in your version history if you still need it.</p><p><strong>Bad:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">oldRequestModule</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$url</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">newRequestModule</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$url</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="variable">$request</span> = newRequestModule(<span class="variable">$requestUrl</span>);</span><br><span class="line">inventoryTracker(<span class="string">'apples'</span>, <span class="variable">$request</span>, <span class="string">'www.inventory-awesome.io'</span>);</span><br></pre></td></tr></table></figure><p><strong>Good:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">requestModule</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$url</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="variable">$request</span> = requestModule(<span class="variable">$requestUrl</span>);</span><br><span class="line">inventoryTracker(<span class="string">'apples'</span>, <span class="variable">$request</span>, <span class="string">'www.inventory-awesome.io'</span>);</span><br></pre></td></tr></table></figure><p><strong><a href="#table-of-contents">⬆ back to top</a></strong></p><h2 id="Objects-and-Data-Structures"><a href="#Objects-and-Data-Structures" class="headerlink" title="Objects and Data Structures"></a>Objects and Data Structures</h2><h3 id="Use-object-encapsulation"><a href="#Use-object-encapsulation" class="headerlink" title="Use object encapsulation"></a>Use object encapsulation</h3><p>In PHP you can set <code>public</code>, <code>protected</code> and <code>private</code> keywords for methods.<br>Using it, you can control properties modification on an object.</p><ul><li>When you want to do more beyond getting an object property, you don’t have<br>to look up and change every accessor in your codebase.</li><li>Makes adding validation simple when doing a <code>set</code>.</li><li>Encapsulates the internal representation.</li><li>Easy to add logging and error handling when getting and setting.</li><li>Inheriting this class, you can override default functionality.</li><li>You can lazy load your object’s properties, let’s say getting it from a<br>server.</li></ul><p>Additionally, this is part of <a href="#openclosed-principle-ocp">Open/Closed</a> principle.</p><p><strong>Bad:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">BankAccount</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="variable">$balance</span> = <span class="number">1000</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="variable">$bankAccount</span> = <span class="keyword">new</span> BankAccount();</span><br><span class="line"></span><br><span class="line"><span class="comment">// Buy shoes...</span></span><br><span class="line"><span class="variable">$bankAccount</span>->balance -= <span class="number">100</span>;</span><br></pre></td></tr></table></figure><p><strong>Good:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">BankAccount</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$balance</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"><span class="keyword">int</span> <span class="variable">$balance</span> = <span class="number">1000</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->balance = <span class="variable">$balance</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">withdraw</span>(<span class="params"><span class="keyword">int</span> <span class="variable">$amount</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$amount</span> > <span class="keyword">$this</span>->balance) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> \<span class="built_in">Exception</span>(<span class="string">'Amount greater than available balance.'</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">$this</span>->balance -= <span class="variable">$amount</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">deposit</span>(<span class="params"><span class="keyword">int</span> <span class="variable">$amount</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->balance += <span class="variable">$amount</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">getBalance</span>(<span class="params"></span>): <span class="title">int</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->balance;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="variable">$bankAccount</span> = <span class="keyword">new</span> BankAccount();</span><br><span class="line"></span><br><span class="line"><span class="comment">// Buy shoes...</span></span><br><span class="line"><span class="variable">$bankAccount</span>->withdraw(<span class="variable">$shoesPrice</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// Get balance</span></span><br><span class="line"><span class="variable">$balance</span> = <span class="variable">$bankAccount</span>->getBalance();</span><br></pre></td></tr></table></figure><p><strong><a href="#table-of-contents">⬆ back to top</a></strong></p><h3 id="Make-objects-have-private-protected-members"><a href="#Make-objects-have-private-protected-members" class="headerlink" title="Make objects have private/protected members"></a>Make objects have private/protected members</h3><ul><li><code>public</code> methods and properties are most dangerous for changes, because some outside code may easily rely on them and you can’t control what code relies on them. <strong>Modifications in class are dangerous for all users of class.</strong></li><li><code>protected</code> modifier are as dangerous as public, because they are available in scope of any child class. This effectively means that difference between public and protected is only in access mechanism, but encapsulation guarantee remains the same. <strong>Modifications in class are dangerous for all descendant classes.</strong></li><li><code>private</code> modifier guarantees that code is <strong>dangerous to modify only in boundaries of single class</strong> (you are safe for modifications and you won’t have <a href="http://www.urbandictionary.com/define.php?term=Jengaphobia&defid=2494196">Jenga effect</a>).</li></ul><p>Therefore, use <code>private</code> by default and <code>public/protected</code> when you need to provide access for external classes.</p><p>For more information you can read the <a href="http://fabien.potencier.org/pragmatism-over-theory-protected-vs-private.html">blog post</a> on this topic written by <a href="https://github.com/fabpot">Fabien Potencier</a>.</p><p><strong>Bad:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Employee</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="variable">$name</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$name</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->name = <span class="variable">$name</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="variable">$employee</span> = <span class="keyword">new</span> Employee(<span class="string">'John Doe'</span>);</span><br><span class="line"><span class="comment">// Employee name: John Doe</span></span><br><span class="line"><span class="keyword">echo</span> <span class="string">'Employee name: '</span> . <span class="variable">$employee</span>->name;</span><br></pre></td></tr></table></figure><p><strong>Good:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Employee</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$name</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$name</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->name = <span class="variable">$name</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">getName</span>(<span class="params"></span>): <span class="title">string</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->name;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="variable">$employee</span> = <span class="keyword">new</span> Employee(<span class="string">'John Doe'</span>);</span><br><span class="line"><span class="comment">// Employee name: John Doe</span></span><br><span class="line"><span class="keyword">echo</span> <span class="string">'Employee name: '</span> . <span class="variable">$employee</span>->getName();</span><br></pre></td></tr></table></figure><p><strong><a href="#table-of-contents">⬆ back to top</a></strong></p><h2 id="Classes"><a href="#Classes" class="headerlink" title="Classes"></a>Classes</h2><h3 id="Prefer-composition-over-inheritance"><a href="#Prefer-composition-over-inheritance" class="headerlink" title="Prefer composition over inheritance"></a>Prefer composition over inheritance</h3><p>As stated famously in <a href="https://en.wikipedia.org/wiki/Design_Patterns"><em>Design Patterns</em></a> by the Gang of Four,<br>you should prefer composition over inheritance where you can. There are lots of<br>good reasons to use inheritance and lots of good reasons to use composition.<br>The main point for this maxim is that if your mind instinctively goes for<br>inheritance, try to think if composition could model your problem better. In some<br>cases it can.</p><p>You might be wondering then, “when should I use inheritance?” It<br>depends on your problem at hand, but this is a decent list of when inheritance<br>makes more sense than composition:</p><ol><li>Your inheritance represents an “is-a” relationship and not a “has-a”<br>relationship (Human->Animal vs. User->UserDetails).</li><li>You can reuse code from the base classes (Humans can move like all animals).</li><li>You want to make global changes to derived classes by changing a base class.<br>(Change the caloric expenditure of all animals when they move).</li></ol><p><strong>Bad:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Employee</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$name</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$email</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$name</span>, <span class="keyword">string</span> <span class="variable">$email</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->name = <span class="variable">$name</span>;</span><br><span class="line"> <span class="keyword">$this</span>->email = <span class="variable">$email</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// Bad because Employees "have" tax data.</span></span><br><span class="line"><span class="comment">// EmployeeTaxData is not a type of Employee</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">EmployeeTaxData</span> <span class="keyword">extends</span> <span class="title">Employee</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$ssn</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$salary</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$name</span>, <span class="keyword">string</span> <span class="variable">$email</span>, <span class="keyword">string</span> <span class="variable">$ssn</span>, <span class="keyword">string</span> <span class="variable">$salary</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="built_in">parent</span>::__construct(<span class="variable">$name</span>, <span class="variable">$email</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">$this</span>->ssn = <span class="variable">$ssn</span>;</span><br><span class="line"> <span class="keyword">$this</span>->salary = <span class="variable">$salary</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>Good:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">EmployeeTaxData</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$ssn</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$salary</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$ssn</span>, <span class="keyword">string</span> <span class="variable">$salary</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->ssn = <span class="variable">$ssn</span>;</span><br><span class="line"> <span class="keyword">$this</span>->salary = <span class="variable">$salary</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Employee</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$name</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$email</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$taxData</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$name</span>, <span class="keyword">string</span> <span class="variable">$email</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->name = <span class="variable">$name</span>;</span><br><span class="line"> <span class="keyword">$this</span>->email = <span class="variable">$email</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">setTaxData</span>(<span class="params">EmployeeTaxData <span class="variable">$taxData</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->taxData = <span class="variable">$taxData</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong><a href="#table-of-contents">⬆ back to top</a></strong></p><h3 id="Avoid-fluent-interfaces"><a href="#Avoid-fluent-interfaces" class="headerlink" title="Avoid fluent interfaces"></a>Avoid fluent interfaces</h3><p>A <a href="https://en.wikipedia.org/wiki/Fluent_interface">Fluent interface</a> is an object<br>oriented API that aims to improve the readability of the source code by using<br><a href="https://en.wikipedia.org/wiki/Method_chaining">Method chaining</a>.</p><p>While there can be some contexts, frequently builder objects, where this<br>pattern reduces the verbosity of the code (for example the <a href="https://phpunit.de/manual/current/en/test-doubles.html">PHPUnit Mock Builder</a><br>or the <a href="http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/query-builder.html">Doctrine Query Builder</a>),<br>more often it comes at some costs:</p><ol><li>Breaks <a href="https://en.wikipedia.org/wiki/Encapsulation_%28object-oriented_programming%29">Encapsulation</a>.</li><li>Breaks <a href="https://en.wikipedia.org/wiki/Decorator_pattern">Decorators</a>.</li><li>Is harder to <a href="https://en.wikipedia.org/wiki/Mock_object">mock</a> in a test suite.</li><li>Makes diffs of commits harder to read.</li></ol><p>For more information you can read the full <a href="https://ocramius.github.io/blog/fluent-interfaces-are-evil/">blog post</a><br>on this topic written by <a href="https://github.com/Ocramius">Marco Pivetta</a>.</p><p><strong>Bad:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Car</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$make</span> = <span class="string">'Honda'</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$model</span> = <span class="string">'Accord'</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$color</span> = <span class="string">'white'</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">setMake</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$make</span></span>): <span class="title">self</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->make = <span class="variable">$make</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// <span class="doctag">NOTE:</span> Returning this for chaining</span></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">setModel</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$model</span></span>): <span class="title">self</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->model = <span class="variable">$model</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// <span class="doctag">NOTE:</span> Returning this for chaining</span></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">setColor</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$color</span></span>): <span class="title">self</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->color = <span class="variable">$color</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// <span class="doctag">NOTE:</span> Returning this for chaining</span></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">dump</span>(<span class="params"></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> var_dump(<span class="keyword">$this</span>->make, <span class="keyword">$this</span>->model, <span class="keyword">$this</span>->color);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="variable">$car</span> = (<span class="keyword">new</span> Car())</span><br><span class="line"> ->setColor(<span class="string">'pink'</span>)</span><br><span class="line"> ->setMake(<span class="string">'Ford'</span>)</span><br><span class="line"> ->setModel(<span class="string">'F-150'</span>)</span><br><span class="line"> ->dump();</span><br></pre></td></tr></table></figure><p><strong>Good:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Car</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$make</span> = <span class="string">'Honda'</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$model</span> = <span class="string">'Accord'</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$color</span> = <span class="string">'white'</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">setMake</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$make</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->make = <span class="variable">$make</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">setModel</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$model</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->model = <span class="variable">$model</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">setColor</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$color</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->color = <span class="variable">$color</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">dump</span>(<span class="params"></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> var_dump(<span class="keyword">$this</span>->make, <span class="keyword">$this</span>->model, <span class="keyword">$this</span>->color);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="variable">$car</span> = <span class="keyword">new</span> Car();</span><br><span class="line"><span class="variable">$car</span>->setColor(<span class="string">'pink'</span>);</span><br><span class="line"><span class="variable">$car</span>->setMake(<span class="string">'Ford'</span>);</span><br><span class="line"><span class="variable">$car</span>->setModel(<span class="string">'F-150'</span>);</span><br><span class="line"><span class="variable">$car</span>->dump();</span><br></pre></td></tr></table></figure><p><strong><a href="#table-of-contents">⬆ back to top</a></strong></p><h3 id="Prefer-final-classes"><a href="#Prefer-final-classes" class="headerlink" title="Prefer final classes"></a>Prefer final classes</h3><p>The <code>final</code> keyword should be used whenever possible:</p><ol><li>It prevents an uncontrolled inheritance chain.</li><li>It encourages <a href="#prefer-composition-over-inheritance">composition</a>.</li><li>It encourages the <a href="#single-responsibility-principle-srp">Single Responsibility Pattern</a>.</li><li>It encourages developers to use your public methods instead of extending the class to get access to protected ones.</li><li>It allows you to change your code without breaking applications that use your class.</li></ol><p>The only condition is that your class should implement an interface and no other public methods are defined.</p><p>For more informations you can read <a href="https://ocramius.github.io/blog/when-to-declare-classes-final/">the blog post</a> on this topic written by <a href="https://ocramius.github.io/">Marco Pivetta (Ocramius)</a>.</p><p><strong>Bad:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">final</span> <span class="class"><span class="keyword">class</span> <span class="title">Car</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$color</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"><span class="variable">$color</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->color = <span class="variable">$color</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> string The color of the vehicle</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">getColor</span>(<span class="params"></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->color;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>Good:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">interface</span> <span class="title">Vehicle</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> string The color of the vehicle</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">getColor</span>(<span class="params"></span>)</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">final</span> <span class="class"><span class="keyword">class</span> <span class="title">Car</span> <span class="keyword">implements</span> <span class="title">Vehicle</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$color</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"><span class="variable">$color</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->color = <span class="variable">$color</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">getColor</span>(<span class="params"></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->color;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong><a href="#table-of-contents">⬆ back to top</a></strong></p><h2 id="SOLID"><a href="#SOLID" class="headerlink" title="SOLID"></a>SOLID</h2><p><strong>SOLID</strong> is the mnemonic acronym introduced by Michael Feathers for the first five principles named by Robert Martin, which meant five basic principles of object-oriented programming and design.</p><ul><li><a href="#single-responsibility-principle-srp">S: Single Responsibility Principle (SRP)</a></li><li><a href="#openclosed-principle-ocp">O: Open/Closed Principle (OCP)</a></li><li><a href="#liskov-substitution-principle-lsp">L: Liskov Substitution Principle (LSP)</a></li><li><a href="#interface-segregation-principle-isp">I: Interface Segregation Principle (ISP)</a></li><li><a href="#dependency-inversion-principle-dip">D: Dependency Inversion Principle (DIP)</a></li></ul><h3 id="Single-Responsibility-Principle-SRP"><a href="#Single-Responsibility-Principle-SRP" class="headerlink" title="Single Responsibility Principle (SRP)"></a>Single Responsibility Principle (SRP)</h3><p>As stated in Clean Code, “There should never be more than one reason for a class<br>to change”. It’s tempting to jam-pack a class with a lot of functionality, like<br>when you can only take one suitcase on your flight. The issue with this is<br>that your class won’t be conceptually cohesive and it will give it many reasons<br>to change. Minimizing the amount of times you need to change a class is important.<br>It’s important because if too much functionality is in one class and you modify a piece of it,<br>it can be difficult to understand how that will affect other dependent modules in<br>your codebase.</p><p><strong>Bad:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">UserSettings</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$user</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params">User <span class="variable">$user</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->user = <span class="variable">$user</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">changeSettings</span>(<span class="params"><span class="keyword">array</span> <span class="variable">$settings</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">$this</span>->verifyCredentials()) {</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="function"><span class="keyword">function</span> <span class="title">verifyCredentials</span>(<span class="params"></span>): <span class="title">bool</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>Good:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">UserAuth</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$user</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params">User <span class="variable">$user</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->user = <span class="variable">$user</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">verifyCredentials</span>(<span class="params"></span>): <span class="title">bool</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">UserSettings</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$user</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$auth</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params">User <span class="variable">$user</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->user = <span class="variable">$user</span>;</span><br><span class="line"> <span class="keyword">$this</span>->auth = <span class="keyword">new</span> UserAuth(<span class="variable">$user</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">changeSettings</span>(<span class="params"><span class="keyword">array</span> <span class="variable">$settings</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">$this</span>->auth->verifyCredentials()) {</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong><a href="#table-of-contents">⬆ back to top</a></strong></p><h3 id="Open-Closed-Principle-OCP"><a href="#Open-Closed-Principle-OCP" class="headerlink" title="Open/Closed Principle (OCP)"></a>Open/Closed Principle (OCP)</h3><p>As stated by Bertrand Meyer, “software entities (classes, modules, functions,<br>etc.) should be open for extension, but closed for modification.” What does that<br>mean though? This principle basically states that you should allow users to<br>add new functionalities without changing existing code.</p><p><strong>Bad:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">Adapter</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">protected</span> <span class="variable">$name</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">getName</span>(<span class="params"></span>): <span class="title">string</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->name;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">AjaxAdapter</span> <span class="keyword">extends</span> <span class="title">Adapter</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="built_in">parent</span>::__construct();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">$this</span>->name = <span class="string">'ajaxAdapter'</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">NodeAdapter</span> <span class="keyword">extends</span> <span class="title">Adapter</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="built_in">parent</span>::__construct();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">$this</span>->name = <span class="string">'nodeAdapter'</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">HttpRequester</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$adapter</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params">Adapter <span class="variable">$adapter</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->adapter = <span class="variable">$adapter</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">fetch</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$url</span></span>): <span class="title">Promise</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="variable">$adapterName</span> = <span class="keyword">$this</span>->adapter->getName();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$adapterName</span> === <span class="string">'ajaxAdapter'</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->makeAjaxCall(<span class="variable">$url</span>);</span><br><span class="line"> } <span class="keyword">elseif</span> (<span class="variable">$adapterName</span> === <span class="string">'httpNodeAdapter'</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->makeHttpCall(<span class="variable">$url</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="function"><span class="keyword">function</span> <span class="title">makeAjaxCall</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$url</span></span>): <span class="title">Promise</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">// request and return promise</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="function"><span class="keyword">function</span> <span class="title">makeHttpCall</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$url</span></span>): <span class="title">Promise</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">// request and return promise</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>Good:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">interface</span> <span class="title">Adapter</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">request</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$url</span></span>): <span class="title">Promise</span></span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">AjaxAdapter</span> <span class="keyword">implements</span> <span class="title">Adapter</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">request</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$url</span></span>): <span class="title">Promise</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">// request and return promise</span></span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">NodeAdapter</span> <span class="keyword">implements</span> <span class="title">Adapter</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">request</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$url</span></span>): <span class="title">Promise</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">// request and return promise</span></span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">HttpRequester</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$adapter</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params">Adapter <span class="variable">$adapter</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->adapter = <span class="variable">$adapter</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">fetch</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$url</span></span>): <span class="title">Promise</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->adapter->request(<span class="variable">$url</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong><a href="#table-of-contents">⬆ back to top</a></strong></p><h3 id="Liskov-Substitution-Principle-LSP"><a href="#Liskov-Substitution-Principle-LSP" class="headerlink" title="Liskov Substitution Principle (LSP)"></a>Liskov Substitution Principle (LSP)</h3><p>This is a scary term for a very simple concept. It’s formally defined as “If S<br>is a subtype of T, then objects of type T may be replaced with objects of type S<br>(i.e., objects of type S may substitute objects of type T) without altering any<br>of the desirable properties of that program (correctness, task performed,<br>etc.).” That’s an even scarier definition.</p><p>The best explanation for this is if you have a parent class and a child class,<br>then the base class and child class can be used interchangeably without getting<br>incorrect results. This might still be confusing, so let’s take a look at the<br>classic Square-Rectangle example. Mathematically, a square is a rectangle, but<br>if you model it using the “is-a” relationship via inheritance, you quickly<br>get into trouble.</p><p><strong>Bad:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Rectangle</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">protected</span> <span class="variable">$width</span> = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">protected</span> <span class="variable">$height</span> = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">setWidth</span>(<span class="params"><span class="keyword">int</span> <span class="variable">$width</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->width = <span class="variable">$width</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">setHeight</span>(<span class="params"><span class="keyword">int</span> <span class="variable">$height</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->height = <span class="variable">$height</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">getArea</span>(<span class="params"></span>): <span class="title">int</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->width * <span class="keyword">$this</span>->height;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Square</span> <span class="keyword">extends</span> <span class="title">Rectangle</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">setWidth</span>(<span class="params"><span class="keyword">int</span> <span class="variable">$width</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->width = <span class="keyword">$this</span>->height = <span class="variable">$width</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">setHeight</span>(<span class="params"><span class="keyword">int</span> <span class="variable">$height</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->width = <span class="keyword">$this</span>->height = <span class="variable">$height</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">printArea</span>(<span class="params">Rectangle <span class="variable">$rectangle</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="variable">$rectangle</span>->setWidth(<span class="number">4</span>);</span><br><span class="line"> <span class="variable">$rectangle</span>->setHeight(<span class="number">5</span>);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// BAD: Will return 25 for Square. Should be 20.</span></span><br><span class="line"> <span class="keyword">echo</span> sprintf(<span class="string">'%s has area %d.'</span>, get_class(<span class="variable">$rectangle</span>), <span class="variable">$rectangle</span>->getArea()) . PHP_EOL;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="variable">$rectangles</span> = [<span class="keyword">new</span> Rectangle(), <span class="keyword">new</span> Square()];</span><br><span class="line"></span><br><span class="line"><span class="keyword">foreach</span> (<span class="variable">$rectangles</span> <span class="keyword">as</span> <span class="variable">$rectangle</span>) {</span><br><span class="line"> printArea(<span class="variable">$rectangle</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>Good:</strong></p><p>The best way is separate the quadrangles and allocation of a more general subtype for both shapes.</p><p>Despite the apparent similarity of the square and the rectangle, they are different.<br>A square has much in common with a rhombus, and a rectangle with a parallelogram, but they are not subtypes.<br>A square, a rectangle, a rhombus and a parallelogram are separate shapes with their own properties, albeit similar.</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">interface</span> <span class="title">Shape</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">getArea</span>(<span class="params"></span>): <span class="title">int</span></span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Rectangle</span> <span class="keyword">implements</span> <span class="title">Shape</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$width</span> = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$height</span> = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"><span class="keyword">int</span> <span class="variable">$width</span>, <span class="keyword">int</span> <span class="variable">$height</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->width = <span class="variable">$width</span>;</span><br><span class="line"> <span class="keyword">$this</span>->height = <span class="variable">$height</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">getArea</span>(<span class="params"></span>): <span class="title">int</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->width * <span class="keyword">$this</span>->height;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Square</span> <span class="keyword">implements</span> <span class="title">Shape</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$length</span> = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"><span class="keyword">int</span> <span class="variable">$length</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->length = <span class="variable">$length</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">getArea</span>(<span class="params"></span>): <span class="title">int</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->length ** <span class="number">2</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">printArea</span>(<span class="params">Shape <span class="variable">$shape</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">echo</span> sprintf(<span class="string">'%s has area %d.'</span>, get_class(<span class="variable">$shape</span>), <span class="variable">$shape</span>->getArea()).PHP_EOL;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="variable">$shapes</span> = [<span class="keyword">new</span> Rectangle(<span class="number">4</span>, <span class="number">5</span>), <span class="keyword">new</span> Square(<span class="number">5</span>)];</span><br><span class="line"></span><br><span class="line"><span class="keyword">foreach</span> (<span class="variable">$shapes</span> <span class="keyword">as</span> <span class="variable">$shape</span>) {</span><br><span class="line"> printArea(<span class="variable">$shape</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong><a href="#table-of-contents">⬆ back to top</a></strong></p><h3 id="Interface-Segregation-Principle-ISP"><a href="#Interface-Segregation-Principle-ISP" class="headerlink" title="Interface Segregation Principle (ISP)"></a>Interface Segregation Principle (ISP)</h3><p>ISP states that “Clients should not be forced to depend upon interfaces that<br>they do not use.”</p><p>A good example to look at that demonstrates this principle is for<br>classes that require large settings objects. Not requiring clients to set up<br>huge amounts of options is beneficial, because most of the time they won’t need<br>all of the settings. Making them optional helps prevent having a “fat interface”.</p><p><strong>Bad:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">interface</span> <span class="title">Employee</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">work</span>(<span class="params"></span>): <span class="title">void</span></span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">eat</span>(<span class="params"></span>): <span class="title">void</span></span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">HumanEmployee</span> <span class="keyword">implements</span> <span class="title">Employee</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">work</span>(<span class="params"></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">// ....working</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">eat</span>(<span class="params"></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">// ...... eating in lunch break</span></span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">RobotEmployee</span> <span class="keyword">implements</span> <span class="title">Employee</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">work</span>(<span class="params"></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">//.... working much more</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">eat</span>(<span class="params"></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">//.... robot can't eat, but it must implement this method</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>Good:</strong></p><p>Not every worker is an employee, but every employee is a worker.</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">interface</span> <span class="title">Workable</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">work</span>(<span class="params"></span>): <span class="title">void</span></span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">interface</span> <span class="title">Feedable</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">eat</span>(<span class="params"></span>): <span class="title">void</span></span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">interface</span> <span class="title">Employee</span> <span class="keyword">extends</span> <span class="title">Feedable</span>, <span class="title">Workable</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">HumanEmployee</span> <span class="keyword">implements</span> <span class="title">Employee</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">work</span>(<span class="params"></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">// ....working</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">eat</span>(<span class="params"></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">//.... eating in lunch break</span></span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// robot can only work</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">RobotEmployee</span> <span class="keyword">implements</span> <span class="title">Workable</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">work</span>(<span class="params"></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">// ....working</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong><a href="#table-of-contents">⬆ back to top</a></strong></p><h3 id="Dependency-Inversion-Principle-DIP"><a href="#Dependency-Inversion-Principle-DIP" class="headerlink" title="Dependency Inversion Principle (DIP)"></a>Dependency Inversion Principle (DIP)</h3><p>This principle states two essential things:</p><ol><li>High-level modules should not depend on low-level modules. Both should<br>depend on abstractions.</li><li>Abstractions should not depend upon details. Details should depend on<br>abstractions.</li></ol><p>This can be hard to understand at first, but if you’ve worked with PHP frameworks (like Symfony), you’ve seen an implementation of this principle in the form of Dependency<br>Injection (DI). While they are not identical concepts, DIP keeps high-level<br>modules from knowing the details of its low-level modules and setting them up.<br>It can accomplish this through DI. A huge benefit of this is that it reduces<br>the coupling between modules. Coupling is a very bad development pattern because<br>it makes your code hard to refactor.</p><p><strong>Bad:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Employee</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">work</span>(<span class="params"></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">// ....working</span></span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Robot</span> <span class="keyword">extends</span> <span class="title">Employee</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">work</span>(<span class="params"></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">//.... working much more</span></span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Manager</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$employee</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params">Employee <span class="variable">$employee</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->employee = <span class="variable">$employee</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">manage</span>(<span class="params"></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->employee->work();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>Good:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">interface</span> <span class="title">Employee</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">work</span>(<span class="params"></span>): <span class="title">void</span></span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Human</span> <span class="keyword">implements</span> <span class="title">Employee</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">work</span>(<span class="params"></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">// ....working</span></span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Robot</span> <span class="keyword">implements</span> <span class="title">Employee</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">work</span>(<span class="params"></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">//.... working much more</span></span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Manager</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$employee</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params">Employee <span class="variable">$employee</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->employee = <span class="variable">$employee</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">manage</span>(<span class="params"></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->employee->work();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong><a href="#table-of-contents">⬆ back to top</a></strong></p><h2 id="Don’t-repeat-yourself-DRY"><a href="#Don’t-repeat-yourself-DRY" class="headerlink" title="Don’t repeat yourself (DRY)"></a>Don’t repeat yourself (DRY)</h2><p>Try to observe the <a href="https://en.wikipedia.org/wiki/Don%27t_repeat_yourself">DRY</a> principle.</p><p>Do your absolute best to avoid duplicate code. Duplicate code is bad because<br>it means that there’s more than one place to alter something if you need to<br>change some logic.</p><p>Imagine if you run a restaurant and you keep track of your inventory: all your<br>tomatoes, onions, garlic, spices, etc. If you have multiple lists that<br>you keep this on, then all have to be updated when you serve a dish with<br>tomatoes in them. If you only have one list, there’s only one place to update!</p><p>Often you have duplicate code because you have two or more slightly<br>different things, that share a lot in common, but their differences force you<br>to have two or more separate functions that do much of the same things. Removing<br>duplicate code means creating an abstraction that can handle this set of different<br>things with just one function/module/class.</p><p>Getting the abstraction right is critical, that’s why you should follow the<br>SOLID principles laid out in the <a href="#classes">Classes</a> section. Bad abstractions can be<br>worse than duplicate code, so be careful! Having said this, if you can make<br>a good abstraction, do it! Don’t repeat yourself, otherwise you’ll find yourself<br>updating multiple places any time you want to change one thing.</p><p><strong>Bad:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">showDeveloperList</span>(<span class="params"><span class="keyword">array</span> <span class="variable">$developers</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable">$developers</span> <span class="keyword">as</span> <span class="variable">$developer</span>) {</span><br><span class="line"> <span class="variable">$expectedSalary</span> = <span class="variable">$developer</span>->calculateExpectedSalary();</span><br><span class="line"> <span class="variable">$experience</span> = <span class="variable">$developer</span>->getExperience();</span><br><span class="line"> <span class="variable">$githubLink</span> = <span class="variable">$developer</span>->getGithubLink();</span><br><span class="line"> <span class="variable">$data</span> = [<span class="variable">$expectedSalary</span>, <span class="variable">$experience</span>, <span class="variable">$githubLink</span>];</span><br><span class="line"></span><br><span class="line"> render(<span class="variable">$data</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">showManagerList</span>(<span class="params"><span class="keyword">array</span> <span class="variable">$managers</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable">$managers</span> <span class="keyword">as</span> <span class="variable">$manager</span>) {</span><br><span class="line"> <span class="variable">$expectedSalary</span> = <span class="variable">$manager</span>->calculateExpectedSalary();</span><br><span class="line"> <span class="variable">$experience</span> = <span class="variable">$manager</span>->getExperience();</span><br><span class="line"> <span class="variable">$githubLink</span> = <span class="variable">$manager</span>->getGithubLink();</span><br><span class="line"> <span class="variable">$data</span> = [<span class="variable">$expectedSalary</span>, <span class="variable">$experience</span>, <span class="variable">$githubLink</span>];</span><br><span class="line"></span><br><span class="line"> render(<span class="variable">$data</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>Good:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">showList</span>(<span class="params"><span class="keyword">array</span> <span class="variable">$employees</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable">$employees</span> <span class="keyword">as</span> <span class="variable">$employee</span>) {</span><br><span class="line"> <span class="variable">$expectedSalary</span> = <span class="variable">$employee</span>->calculateExpectedSalary();</span><br><span class="line"> <span class="variable">$experience</span> = <span class="variable">$employee</span>->getExperience();</span><br><span class="line"> <span class="variable">$githubLink</span> = <span class="variable">$employee</span>->getGithubLink();</span><br><span class="line"> <span class="variable">$data</span> = [<span class="variable">$expectedSalary</span>, <span class="variable">$experience</span>, <span class="variable">$githubLink</span>];</span><br><span class="line"></span><br><span class="line"> render(<span class="variable">$data</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>Very good:</strong></p><p>It is better to use a compact version of the code.</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">showList</span>(<span class="params"><span class="keyword">array</span> <span class="variable">$employees</span></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable">$employees</span> <span class="keyword">as</span> <span class="variable">$employee</span>) {</span><br><span class="line"> render([<span class="variable">$employee</span>->calculateExpectedSalary(), <span class="variable">$employee</span>->getExperience(), <span class="variable">$employee</span>->getGithubLink()]);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong><a href="#table-of-contents">⬆ back to top</a></strong></p><h2 id="Translations"><a href="#Translations" class="headerlink" title="Translations"></a>Translations</h2><p>This is also available in other languages:</p><ul><li>:cn: <strong>Chinese:</strong><ul><li><a href="https://github.com/php-cpm/clean-code-php">php-cpm/clean-code-php</a></li></ul></li><li>:ru: <strong>Russian:</strong><ul><li><a href="https://github.com/peter-gribanov/clean-code-php">peter-gribanov/clean-code-php</a></li></ul></li><li>:es: <strong>Spanish:</strong><ul><li><a href="https://github.com/fikoborquez/clean-code-php">fikoborquez/clean-code-php</a></li></ul></li><li>:brazil: <strong>Portuguese:</strong><ul><li><a href="https://github.com/fabioars/clean-code-php">fabioars/clean-code-php</a></li><li><a href="https://github.com/jeanjar/clean-code-php/tree/pt-br">jeanjar/clean-code-php</a></li></ul></li><li>:thailand: <strong>Thai:</strong><ul><li><a href="https://github.com/panuwizzle/clean-code-php">panuwizzle/clean-code-php</a></li></ul></li><li>:fr: <strong>French:</strong><ul><li><a href="https://github.com/errorname/clean-code-php">errorname/clean-code-php</a></li></ul></li><li>:vietnam: <strong>Vietnamese</strong><ul><li><a href="https://github.com/viethuongdev/clean-code-php">viethuongdev/clean-code-php</a></li></ul></li><li>:kr: <strong>Korean:</strong><ul><li><a href="https://github.com/yujineeee/clean-code-php">yujineeee/clean-code-php</a></li></ul></li><li>:tr: <strong>Turkish:</strong><ul><li><a href="https://github.com/anilozmen/clean-code-php">anilozmen/clean-code-php</a></li></ul></li><li>:iran: <strong>Persian:</strong><ul><li><a href="https://github.com/amirshnll/clean-code-php">amirshnll/clean-code-php</a></li></ul></li><li>:bangladesh: <strong>Bangla:</strong><ul><li><a href="https://github.com/nayeemdev/clean-code-php">nayeemdev/clean-code-php</a></li></ul></li></ul><p><strong><a href="#table-of-contents">⬆ back to top</a></strong></p>]]></content>
<categories>
<category> PHP </category>
</categories>
<tags>
<tag> PHP </tag>
<tag> 规范 </tag>
</tags>
</entry>
<entry>
<title>Linux 常用命令</title>
<link href="/2021/11/e531c1bc325a/"/>
<url>/2021/11/e531c1bc325a/</url>
<content type="html"><![CDATA[<h3 id="解压缩"><a href="#解压缩" class="headerlink" title="解压缩"></a>解压缩</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta"></span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 压缩</span></span><br><span class="line">tar -zcvf [压缩包名字].tgz [要压缩的文件或路径]</span><br><span class="line"><span class="meta">#</span><span class="bash"> 解压</span></span><br><span class="line">tar -zxvf [文件名]</span><br><span class="line"></span><br></pre></td></tr></table></figure><span id="more"></span><h3 id="软连接"><a href="#软连接" class="headerlink" title="软连接"></a>软连接</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 创建软连接</span></span><br><span class="line">ln -s [源文件或目录] [目标文件或目录]</span><br><span class="line"><span class="meta">#</span><span class="bash"> 修改软连接</span></span><br><span class="line">ln –snf [新的源文件或目录] [目标文件或目录]</span><br></pre></td></tr></table></figure><h3 id="检查是否安装了某个软件"><a href="#检查是否安装了某个软件" class="headerlink" title="检查是否安装了某个软件"></a>检查是否安装了某个软件</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yum list installed | grep "软件名或者包名"</span><br></pre></td></tr></table></figure><h3 id="列出目录文件"><a href="#列出目录文件" class="headerlink" title="列出目录文件"></a>列出目录文件</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">ls -a #列出目录所有文件,包含以.开始的隐藏文件</span><br><span class="line">ls -A #列出除.及..的其它文件</span><br><span class="line">ls -l #除了文件名之外,还将文件的权限、所有者、文件大小等信息详细列出来</span><br><span class="line">ls -t #以文件修改时间排序</span><br><span class="line">ls -S #以文件大小排序</span><br><span class="line">ls -h #以易读大小显示</span><br></pre></td></tr></table></figure><h3 id="创建文件夹"><a href="#创建文件夹" class="headerlink" title="创建文件夹"></a>创建文件夹</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 创建文件夹t</span></span><br><span class="line">mkdir t</span><br><span class="line"><span class="meta">#</span><span class="bash"> 在 tmp 目录下创建路径为 <span class="built_in">test</span>/t1/t 的目录,若不存在,则创建:</span></span><br><span class="line">mkdir -p /tmp/test/t1/t</span><br></pre></td></tr></table></figure><h3 id="cat-命令"><a href="#cat-命令" class="headerlink" title="cat 命令"></a>cat 命令</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 一次显示整个文件</span></span><br><span class="line">cat filename</span><br><span class="line"><span class="meta">#</span><span class="bash"> 从键盘创建一个文件 只能创建新文件,不能编辑已有文件</span></span><br><span class="line">cat > filename</span><br><span class="line"><span class="meta">#</span><span class="bash"> 将几个文件合并为一个文件</span></span><br><span class="line">cat file1 file2 > file</span><br></pre></td></tr></table></figure><h3 id="df-命令"><a href="#df-命令" class="headerlink" title="df 命令"></a>df 命令</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">df -a # 全部文件系统列表</span><br><span class="line">df -h # 以方便阅读的方式显示信息</span><br><span class="line">df -l # 只显示本地磁盘</span><br><span class="line">df -T # 列出文件系统类型</span><br></pre></td></tr></table></figure><h3 id="查看当前运行的进程状态"><a href="#查看当前运行的进程状态" class="headerlink" title="查看当前运行的进程状态"></a>查看当前运行的进程状态</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">ps -A # 显示所有进程</span><br><span class="line">ps -a # 显示同一终端下所有进程</span><br><span class="line">ps c # 显示进程真实名称</span><br><span class="line">ps e # 显示环境变量</span><br><span class="line">ps f # 显示进程间的关系</span><br><span class="line">ps r # 显示当前终端运行的进程</span><br><span class="line">ps -aux # 显示所有包含其它使用的进程</span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category> Linux </category>
</categories>
<tags>
<tag> Linux </tag>
</tags>
</entry>
<entry>
<title>解决 Nginx 下 ThinkPHP 路由失效</title>
<link href="/2021/11/f6b4d2e93f74/"/>
<url>/2021/11/f6b4d2e93f74/</url>
<content type="html"><![CDATA[<p>在 <code>Nginx</code> 对应的站点配置中添加下列配置,<code>Laravel</code>框架有此问题也是类似的解决方案</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">location / { </span><br><span class="line">if (!-e $request_filename) {</span><br><span class="line">rewrite ^(.*)$ /index.php?s=/$1 last; break; </span><br><span class="line">} </span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category> PHP </category>
</categories>
<tags>
<tag> PHP </tag>
<tag> ThinkPHP </tag>
</tags>
</entry>
<entry>
<title>CentOS 切换国内源</title>
<link href="/2021/11/56931a4b4a96/"/>
<url>/2021/11/56931a4b4a96/</url>
<content type="html"><![CDATA[<h3 id="备份现有源"><a href="#备份现有源" class="headerlink" title="备份现有源"></a>备份现有源</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup</span><br></pre></td></tr></table></figure><h3 id="下载新的-CentOS-Base-repo-到-etc-yum-repos-d"><a href="#下载新的-CentOS-Base-repo-到-etc-yum-repos-d" class="headerlink" title="下载新的 CentOS-Base.repo 到 /etc/yum.repos.d/"></a>下载新的 CentOS-Base.repo 到 /etc/yum.repos.d/</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> CentOS 6</span></span><br><span class="line">wget -O /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-6.repo</span><br><span class="line"><span class="meta">#</span><span class="bash"> 或者</span></span><br><span class="line">curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-6.repo</span><br><span class="line"><span class="meta"></span></span><br><span class="line"><span class="meta"></span></span><br><span class="line"><span class="meta">#</span><span class="bash"> CentOS 7</span></span><br><span class="line">wget -O /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo</span><br><span class="line"><span class="meta">#</span><span class="bash"> 或者</span></span><br><span class="line">curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo</span><br><span class="line"><span class="meta"></span></span><br><span class="line"><span class="meta">#</span><span class="bash"> CentOS 8</span></span><br><span class="line">wget -O /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-8.repo</span><br><span class="line"><span class="meta">#</span><span class="bash"> 或者</span></span><br><span class="line">curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-8.repo</span><br></pre></td></tr></table></figure><h3 id="缓存刷新"><a href="#缓存刷新" class="headerlink" title="缓存刷新"></a>缓存刷新</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yum makecache</span><br></pre></td></tr></table></figure><p>附:<a href="https://developer.aliyun.com/mirror/">常用的开源镜像</a></p>]]></content>
<categories>
<category> Linux </category>
</categories>
<tags>
<tag> Linux </tag>
</tags>
</entry>
<entry>
<title>PHP实现常见算法</title>
<link href="/2021/11/174b54c388cb/"/>
<url>/2021/11/174b54c388cb/</url>
<content type="html"><![CDATA[<h1 id="冒泡排序"><a href="#冒泡排序" class="headerlink" title="冒泡排序"></a>冒泡排序</h1><blockquote><p>比较相邻的元素。如果第一个比第二个大,就交换他们两个。对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。针对所有的元素重复以上的步骤,除了最后一个</p></blockquote><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">bubbleSort</span>(<span class="params"><span class="variable">$arr</span></span>)</span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">for</span>(<span class="variable">$i</span>=<span class="number">0</span>;<span class="variable">$i</span><count(<span class="variable">$arr</span>);<span class="variable">$i</span>++) {</span><br><span class="line"> <span class="keyword">for</span>(<span class="variable">$j</span>=<span class="variable">$i</span>+<span class="number">1</span>;<span class="variable">$j</span><count(<span class="variable">$arr</span>); <span class="variable">$j</span>++) {</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$arr</span>[<span class="variable">$j</span>] > <span class="variable">$arr</span>[<span class="variable">$i</span>]) {</span><br><span class="line"> <span class="variable">$arr</span>[<span class="variable">$j</span>] = <span class="variable">$arr</span>[<span class="variable">$j</span>] + <span class="variable">$arr</span>[<span class="variable">$i</span>];</span><br><span class="line"> <span class="variable">$arr</span>[<span class="variable">$i</span>] = <span class="variable">$arr</span>[<span class="variable">$j</span>] - <span class="variable">$arr</span>[<span class="variable">$i</span>];</span><br><span class="line"> <span class="variable">$arr</span>[<span class="variable">$j</span>] = <span class="variable">$arr</span>[<span class="variable">$j</span>] - <span class="variable">$arr</span>[<span class="variable">$i</span>];</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="variable">$arr</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h1 id="快速排序"><a href="#快速排序" class="headerlink" title="快速排序"></a>快速排序</h1><blockquote><p>从数列中挑出一个元素,作为基准;重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。递归地把小于基准值元素的子数列和大于基准值元素的子数列排序;</p></blockquote><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">quickSort</span>(<span class="params"><span class="variable">$arr</span></span>)</span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="variable">$arrLength</span> = count(<span class="variable">$arr</span>);</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$arrLength</span> <= <span class="number">1</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="variable">$arr</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="variable">$divider</span> = <span class="variable">$arr</span>[<span class="number">0</span>]; <span class="comment">// 获取中间值</span></span><br><span class="line"> <span class="variable">$left</span> = [];</span><br><span class="line"> <span class="variable">$right</span> = [];</span><br><span class="line"> <span class="keyword">for</span> (<span class="variable">$i</span>=<span class="number">1</span>; <span class="variable">$i</span><<span class="variable">$arrLength</span>; <span class="variable">$i</span>++) {</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$divider</span> < <span class="variable">$arr</span>[<span class="variable">$i</span>]) {</span><br><span class="line"> <span class="variable">$right</span>[] = <span class="variable">$arr</span>[<span class="variable">$i</span>]; <span class="comment">// 小于中间值的放右边</span></span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="variable">$left</span>[] = <span class="variable">$arr</span>[<span class="variable">$i</span>]; <span class="comment">// 大于中间值的放左边</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 递归排好另外两侧</span></span><br><span class="line"> <span class="variable">$left</span> = quickSort(<span class="variable">$left</span>);</span><br><span class="line"> <span class="variable">$right</span> = quickSort(<span class="variable">$right</span>);</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">return</span> array_merge(<span class="variable">$left</span>, [<span class="variable">$divider</span>], <span class="variable">$right</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h1 id="选择排序"><a href="#选择排序" class="headerlink" title="选择排序"></a>选择排序</h1><blockquote><p>首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。重复第二步,直到所有元素均排序完毕。</p></blockquote><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">selectSort</span>(<span class="params"><span class="variable">$arr</span></span>)</span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="variable">$len</span> = count(<span class="variable">$arr</span>);</span><br><span class="line"> <span class="keyword">for</span> (<span class="variable">$i</span> = <span class="number">0</span>; <span class="variable">$i</span> < <span class="variable">$len</span> - <span class="number">1</span>; <span class="variable">$i</span>++) {</span><br><span class="line"> <span class="variable">$minIndex</span> = <span class="variable">$i</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="variable">$j</span> = <span class="variable">$i</span> + <span class="number">1</span>; <span class="variable">$j</span> < <span class="variable">$len</span>; <span class="variable">$j</span>++) {</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$arr</span>[<span class="variable">$j</span>] < <span class="variable">$arr</span>[<span class="variable">$minIndex</span>]) {</span><br><span class="line"> <span class="variable">$minIndex</span> = <span class="variable">$j</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="variable">$temp</span> = <span class="variable">$arr</span>[<span class="variable">$i</span>];</span><br><span class="line"> <span class="variable">$arr</span>[<span class="variable">$i</span>] = <span class="variable">$arr</span>[<span class="variable">$minIndex</span>];</span><br><span class="line"> <span class="variable">$arr</span>[<span class="variable">$minIndex</span>] = <span class="variable">$temp</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="variable">$arr</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h1 id="二维数组根据某个值来排序"><a href="#二维数组根据某个值来排序" class="headerlink" title="二维数组根据某个值来排序"></a>二维数组根据某个值来排序</h1><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$arr</span>=[</span><br><span class="line"> [</span><br><span class="line"> <span class="string">'name'</span>=><span class="string">'StuA'</span>,</span><br><span class="line"> <span class="string">'age'</span>=><span class="number">28</span></span><br><span class="line"> ],</span><br><span class="line"> [</span><br><span class="line"> <span class="string">'name'</span>=><span class="string">'StuB'</span>,</span><br><span class="line"> <span class="string">'age'</span>=><span class="number">14</span></span><br><span class="line"> ],</span><br><span class="line"> [</span><br><span class="line"> <span class="string">'name'</span>=><span class="string">'StuC'</span>,</span><br><span class="line"> <span class="string">'age'</span>=><span class="number">59</span></span><br><span class="line"> ],</span><br><span class="line"> [</span><br><span class="line"> <span class="string">'name'</span>=><span class="string">'StuD'</span>,</span><br><span class="line"> <span class="string">'age'</span>=><span class="number">23</span></span><br><span class="line"> ],</span><br><span class="line"> [</span><br><span class="line"> <span class="string">'name'</span>=><span class="string">'StuE'</span>,</span><br><span class="line"> <span class="string">'age'</span>=><span class="number">23</span></span><br><span class="line"> ],</span><br><span class="line"> [</span><br><span class="line"> <span class="string">'name'</span>=><span class="string">'StuF'</span>,</span><br><span class="line"> <span class="string">'age'</span>=><span class="number">21</span></span><br><span class="line"> ],</span><br><span class="line">];</span><br><span class="line"><span class="comment">// 根据 age 键来排序</span></span><br><span class="line">array_multisort(array_column(<span class="variable">$arr</span>,<span class="string">'age'</span>),SORT_DESC,<span class="variable">$arr</span>);</span><br><span class="line">print_r(<span class="variable">$arr</span>);</span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category> PHP </category>
</categories>
<tags>
<tag> PHP </tag>
<tag> 算法 </tag>
</tags>
</entry>
<entry>
<title>PHP常用代码片段</title>
<link href="/2021/11/96370c182df6/"/>
<url>/2021/11/96370c182df6/</url>
<content type="html"><![CDATA[<h3 id="1-获取上一周-上月-前几天时间"><a href="#1-获取上一周-上月-前几天时间" class="headerlink" title="1.获取上一周/上月/前几天时间"></a>1.获取上一周/上月/前几天时间</h3><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">date(<span class="string">"Y-m-d"</span>,strtotime(<span class="string">"-1 week"</span>)); </span><br><span class="line">date(<span class="string">"Y-m-d"</span>,strtotime(<span class="string">"-1 month"</span>));</span><br><span class="line">date(<span class="string">"Y-m-d"</span>,strtotime(<span class="string">"-1 day"</span>));</span><br></pre></td></tr></table></figure><h3 id="2-二维数组去重"><a href="#2-二维数组去重" class="headerlink" title="2.二维数组去重"></a>2.二维数组去重</h3><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">remove_duplicate</span>(<span class="params"><span class="variable">$arr</span>,<span class="variable">$key</span></span>)</span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="comment">// 建立一个目标数组 </span></span><br><span class="line"><span class="variable">$result</span> = []; </span><br><span class="line"><span class="keyword">foreach</span> (<span class="variable">$arr</span> <span class="keyword">as</span> <span class="variable">$value</span>){ </span><br><span class="line"><span class="comment">// 查看有没有重复项 </span></span><br><span class="line"><span class="variable">$if_exit</span> = <span class="keyword">isset</span>(<span class="variable">$result</span>[<span class="variable">$value</span>[<span class="variable">$key</span>]]); </span><br><span class="line"><span class="keyword">if</span> (<span class="variable">$if_exit</span>) { </span><br><span class="line"><span class="keyword">unset</span>(<span class="variable">$value</span>[<span class="variable">$key</span>]); </span><br><span class="line">} <span class="keyword">else</span> { </span><br><span class="line"><span class="variable">$result</span>[<span class="variable">$value</span>[<span class="variable">$key</span>]] = <span class="variable">$value</span>; </span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="keyword">foreach</span>(<span class="variable">$result</span> <span class="keyword">as</span> <span class="variable">$key</span> => <span class="variable">$row</span>) {</span><br><span class="line"><span class="variable">$result</span>[] = <span class="variable">$row</span>; </span><br><span class="line"><span class="keyword">unset</span>(<span class="variable">$result</span>[<span class="variable">$key</span>]); </span><br><span class="line">}</span><br><span class="line"><span class="keyword">return</span> <span class="variable">$result</span>; </span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="3-多维数组中按-7-个分成一组"><a href="#3-多维数组中按-7-个分成一组" class="headerlink" title="3.多维数组中按 7 个分成一组"></a>3.多维数组中按 7 个分成一组</h3><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$memberList</span> = []; </span><br><span class="line"><span class="variable">$length</span> = ceil(count(<span class="variable">$allMember</span>));</span><br><span class="line"><span class="keyword">for</span> (<span class="variable">$i</span> = <span class="number">0</span>; <span class="variable">$i</span> < <span class="variable">$length</span>; <span class="variable">$i</span>++) {</span><br><span class="line"><span class="variable">$memberList</span>[] = array_slice(<span class="variable">$allMember</span>, <span class="variable">$i</span> * <span class="number">7</span>, <span class="number">7</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="4-二维数组按特定值排序"><a href="#4-二维数组按特定值排序" class="headerlink" title="4.二维数组按特定值排序"></a>4.二维数组按特定值排序</h3><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$data</span> = [</span><br><span class="line">[ <span class="string">'id'</span> => <span class="number">5698</span>, <span class="string">'first_name'</span> => <span class="string">'Bill'</span>, <span class="string">'last_name'</span> => <span class="string">'Gates'</span>], </span><br><span class="line">[ <span class="string">'id'</span> => <span class="number">4767</span>, <span class="string">'first_name'</span> => <span class="string">'Steve'</span>, <span class="string">'last_name'</span> => <span class="string">'Aobs'</span>],</span><br><span class="line">[ <span class="string">'id'</span> => <span class="number">3809</span>, <span class="string">'first_name'</span> => <span class="string">'Mark'</span>, <span class="string">'last_name'</span> => <span class="string">'Zuckerberg'</span>]</span><br><span class="line">]; </span><br><span class="line"><span class="comment">//根据字段last_name对数组$data进行降序排列 </span></span><br><span class="line"><span class="variable">$last_names</span> = array_column(<span class="variable">$data</span>,<span class="string">'last_name'</span>); </span><br><span class="line">array_multisort(<span class="variable">$last_names</span>,SORT_DESC,<span class="variable">$data</span>);</span><br><span class="line">var_dump(<span class="variable">$data</span>);</span><br></pre></td></tr></table></figure><h3 id="5-将中文拆分成数组"><a href="#5-将中文拆分成数组" class="headerlink" title="5.将中文拆分成数组"></a>5.将中文拆分成数组</h3><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">mb_str_split</span>(<span class="params"><span class="variable">$str</span></span>) </span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">return</span> preg_split(<span class="string">'/(?<!^)(?!$)/u'</span>, <span class="variable">$str</span>); </span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="6-模拟发送-POST-请求"><a href="#6-模拟发送-POST-请求" class="headerlink" title="6.模拟发送 POST 请求"></a>6.模拟发送 POST 请求</h3><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">curl_post</span>(<span class="params"><span class="variable">$url</span> , <span class="variable">$data</span>=[]</span>)</span></span><br><span class="line"><span class="function"></span>{ </span><br><span class="line"><span class="variable">$ch</span> = curl_init(); </span><br><span class="line">curl_setopt(<span class="variable">$ch</span>, CURLOPT_URL, <span class="variable">$url</span>); <span class="comment">// 要访问的地址</span></span><br><span class="line">curl_setopt(<span class="variable">$ch</span>, CURLOPT_RETURNTRANSFER, <span class="number">1</span>); <span class="comment">// 获取的信息以文件流的形式返回</span></span><br><span class="line">curl_setopt(<span class="variable">$ch</span>, CURLOPT_SSL_VERIFYPEER, <span class="literal">FALSE</span>); <span class="comment">// 对认证证书来源的检查</span></span><br><span class="line">curl_setopt(<span class="variable">$ch</span>, CURLOPT_SSL_VERIFYHOST, <span class="literal">FALSE</span>); <span class="comment">// 从证书中检查SSL加密算法是否存在</span></span><br><span class="line"><span class="comment">// POST数据 </span></span><br><span class="line">curl_setopt(<span class="variable">$ch</span>, CURLOPT_POST, <span class="number">1</span>); </span><br><span class="line"><span class="comment">// 把post的变量加上 </span></span><br><span class="line">curl_setopt(<span class="variable">$ch</span>, CURLOPT_POSTFIELDS, <span class="variable">$data</span>); </span><br><span class="line"><span class="variable">$output</span> = curl_exec(<span class="variable">$ch</span>); </span><br><span class="line">curl_close(<span class="variable">$ch</span>); </span><br><span class="line"><span class="keyword">return</span> <span class="variable">$output</span>; </span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="7-美化输出变量"><a href="#7-美化输出变量" class="headerlink" title="7.美化输出变量"></a>7.美化输出变量</h3><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">p</span>(<span class="params"><span class="variable">$data</span></span>)</span>{</span><br><span class="line"> <span class="comment">// 定义样式</span></span><br><span class="line"> <span class="variable">$str</span> = <span class="string">'<pre style="display: block;padding: 9.5px;margin: 44px 0 0 0;font-size: 13px;line-height: 1.42857;color: #333;word-break: break-all;word-wrap: break-word;background-color: #F5F5F5;border: 1px solid #CCC;border-radius: 4px;">'</span>;</span><br><span class="line"> <span class="comment">// 如果是boolean或者null直接显示文字;否则print</span></span><br><span class="line"> <span class="keyword">if</span> (is_bool(<span class="variable">$data</span>)) {</span><br><span class="line"> <span class="variable">$show_data</span> = <span class="variable">$data</span> ? <span class="string">'true'</span> : <span class="string">'false'</span>;</span><br><span class="line"> } <span class="keyword">elseif</span>(is_null(<span class="variable">$data</span>)) {</span><br><span class="line"> <span class="variable">$show_data</span> = <span class="string">'null'</span>;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="variable">$show_data</span> = print_r(<span class="variable">$data</span>,<span class="literal">true</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="variable">$str</span> .= <span class="variable">$show_data</span>;</span><br><span class="line"> <span class="variable">$str</span> .= <span class="string">'</pre>'</span>;</span><br><span class="line"> <span class="keyword">echo</span> <span class="variable">$str</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="8-支持中文的字符串截取"><a href="#8-支持中文的字符串截取" class="headerlink" title="8.支持中文的字符串截取"></a>8.支持中文的字符串截取</h3><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 字符串截取,支持中文和其他编码</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> string $str 需要转换的字符串</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> string $start 开始位置</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> string $length 截取长度</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> string $suffix 截断显示字符</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> string $charset 编码格式</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> string</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">re_substr</span>(<span class="params"><span class="variable">$str</span>, <span class="variable">$start</span>=<span class="number">0</span>, <span class="variable">$length</span>, <span class="variable">$suffix</span>=<span class="literal">true</span>, <span class="variable">$charset</span>=<span class="string">"utf-8"</span></span>)</span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span>(function_exists(<span class="string">"mb_substr"</span>)) {</span><br><span class="line"><span class="variable">$slice</span> = mb_substr(<span class="variable">$str</span>, <span class="variable">$start</span>, <span class="variable">$length</span>, <span class="variable">$charset</span>);</span><br><span class="line">} <span class="keyword">elseif</span>(function_exists(<span class="string">'iconv_substr'</span>)) {</span><br><span class="line"> <span class="variable">$slice</span> = iconv_substr(<span class="variable">$str</span>,<span class="variable">$start</span>,<span class="variable">$length</span>,<span class="variable">$charset</span>);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="variable">$re</span>[<span class="string">'utf-8'</span>] = <span class="string">"/[\x01-\x7f]|[\xc2-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xff][\x80-\xbf]{3}/"</span>;</span><br><span class="line"> <span class="variable">$re</span>[<span class="string">'gb2312'</span>] = <span class="string">"/[\x01-\x7f]|[\xb0-\xf7][\xa0-\xfe]/"</span>;</span><br><span class="line"> <span class="variable">$re</span>[<span class="string">'gbk'</span>] = <span class="string">"/[\x01-\x7f]|[\x81-\xfe][\x40-\xfe]/"</span>;</span><br><span class="line"> <span class="variable">$re</span>[<span class="string">'big5'</span>] = <span class="string">"/[\x01-\x7f]|[\x81-\xfe]([\x40-\x7e]|\xa1-\xfe])/"</span>;</span><br><span class="line"> preg_match_all(<span class="variable">$re</span>[<span class="variable">$charset</span>], <span class="variable">$str</span>, <span class="variable">$match</span>);</span><br><span class="line"> <span class="variable">$slice</span> = join(<span class="string">""</span>,array_slice(<span class="variable">$match</span>[<span class="number">0</span>], <span class="variable">$start</span>, <span class="variable">$length</span>));</span><br><span class="line"> }</span><br><span class="line"> <span class="variable">$omit</span> = mb_strlen(<span class="variable">$str</span>) >= <span class="variable">$length</span> ? <span class="string">'...'</span> : <span class="string">''</span>;</span><br><span class="line"> <span class="keyword">return</span> <span class="variable">$suffix</span> ? <span class="variable">$slice</span>.<span class="variable">$omit</span> : <span class="variable">$slice</span>;</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="9-获取一定范围内的随机数字"><a href="#9-获取一定范围内的随机数字" class="headerlink" title="9.获取一定范围内的随机数字"></a>9.获取一定范围内的随机数字</h3><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 获取一定范围内的随机数字</span></span><br><span class="line"><span class="comment"> * 跟rand()函数的区别是 位数不足补零 例如</span></span><br><span class="line"><span class="comment"> * rand(1,9999)可能会得到 465</span></span><br><span class="line"><span class="comment"> * rand_number(1,9999)可能会得到 0465 保证是4位的</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> integer $min 最小值</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> integer $max 最大值</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> string</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">rand_number</span> (<span class="params"><span class="variable">$min</span>=<span class="number">1</span>, <span class="variable">$max</span>=<span class="number">9999</span></span>) </span>{</span><br><span class="line"><span class="variable">$strlen</span> = strlen(<span class="variable">$max</span>);</span><br><span class="line"> <span class="keyword">return</span> sprintf(<span class="string">"%0"</span> . <span class="variable">$strlen</span> . <span class="string">"d"</span>, mt_rand(<span class="variable">$min</span>, <span class="variable">$max</span>));</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="10-生成一定数量的随机数,并且不重复"><a href="#10-生成一定数量的随机数,并且不重复" class="headerlink" title="10.生成一定数量的随机数,并且不重复"></a>10.生成一定数量的随机数,并且不重复</h3><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 生成一定数量的随机数,并且不重复</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> integer $number 数量</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> string $len 长度</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> string $type 字串类型</span></span><br><span class="line"><span class="comment"> * 0 字母 1 数字 其它 混合</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> string</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">build_count_rand</span> (<span class="params"><span class="variable">$number</span>, <span class="variable">$length</span>=<span class="number">4</span>, <span class="variable">$mode</span>=<span class="number">1</span></span>)</span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span>(<span class="variable">$mode</span> == <span class="number">1</span> && <span class="variable">$length</span> < strlen(<span class="variable">$number</span>)) {</span><br><span class="line"> <span class="comment">//不足以生成一定数量的不重复数字</span></span><br><span class="line"> <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="variable">$rand</span> = [];</span><br><span class="line"> <span class="keyword">for</span>(<span class="variable">$i</span> = <span class="number">0</span>; <span class="variable">$i</span> < <span class="variable">$number</span>; <span class="variable">$i</span>++) {</span><br><span class="line"> <span class="variable">$rand</span>[] = rand_string(<span class="variable">$length</span>, <span class="variable">$mode</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="variable">$unqiue</span> = array_unique(<span class="variable">$rand</span>);</span><br><span class="line"> <span class="keyword">if</span>(count(<span class="variable">$unqiue</span>) == count(<span class="variable">$rand</span>)) {</span><br><span class="line"> <span class="keyword">return</span> <span class="variable">$rand</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="variable">$count</span> = count(<span class="variable">$rand</span>) - count(<span class="variable">$unqiue</span>);</span><br><span class="line"> <span class="keyword">for</span>(<span class="variable">$i</span> = <span class="number">0</span>; <span class="variable">$i</span> < <span class="variable">$count</span>*<span class="number">3</span>; <span class="variable">$i</span>++) {</span><br><span class="line"> <span class="variable">$rand</span>[] = rand_string(<span class="variable">$length</span>, <span class="variable">$mode</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="variable">$rand</span> = array_slice(array_unique(<span class="variable">$rand</span>), <span class="number">0</span>, <span class="variable">$number</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="variable">$rand</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="11-生成不重复的随机数"><a href="#11-生成不重复的随机数" class="headerlink" title="11.生成不重复的随机数"></a>11.生成不重复的随机数</h3><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 生成不重复的随机数</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> int $start 需要生成的数字开始范围</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> int $end 结束范围</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> int $length 需要生成的随机数个数</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> array 生成的随机数</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">get_rand_number</span>(<span class="params"><span class="variable">$start</span> = <span class="number">1</span>, <span class="variable">$end</span> = <span class="number">10</span>, <span class="variable">$length</span> = <span class="number">4</span></span>)</span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="variable">$connt</span> = <span class="number">0</span>;</span><br><span class="line"> <span class="variable">$temp</span> = [];</span><br><span class="line"> <span class="keyword">while</span>(<span class="variable">$connt</span> < <span class="variable">$length</span>){</span><br><span class="line"> <span class="variable">$temp</span>[] = rand(<span class="variable">$start</span>, <span class="variable">$end</span>);</span><br><span class="line"> <span class="variable">$data</span> = array_unique(<span class="variable">$temp</span>);</span><br><span class="line"> <span class="variable">$connt</span> = count(<span class="variable">$data</span>);</span><br><span class="line"> }</span><br><span class="line"> sort(<span class="variable">$data</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="variable">$data</span>;</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="12-curl-获取远程数据"><a href="#12-curl-获取远程数据" class="headerlink" title="12.curl 获取远程数据"></a>12.curl 获取远程数据</h3><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 使用curl获取远程数据</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> string $url url连接</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> string 获取到的数据</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">curl_get_contents</span>(<span class="params"><span class="variable">$url</span></span>)</span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="variable">$ch</span> = curl_init();</span><br><span class="line"> curl_setopt(<span class="variable">$ch</span>, CURLOPT_URL, <span class="variable">$url</span>); <span class="comment">//设置访问的url地址</span></span><br><span class="line"> <span class="comment">// curl_setopt($ch,CURLOPT_HEADER,1); //是否显示头部信息</span></span><br><span class="line"> curl_setopt(<span class="variable">$ch</span>, CURLOPT_TIMEOUT, <span class="number">5</span>); <span class="comment">//设置超时</span></span><br><span class="line"> curl_setopt(<span class="variable">$ch</span>, CURLOPT_USERAGENT, <span class="variable">$_SERVER</span>[<span class="string">'HTTP_USER_AGENT'</span>]); <span class="comment">//用户访问代理 User-Agent</span></span><br><span class="line"> curl_setopt(<span class="variable">$ch</span>, CURLOPT_REFERER,<span class="variable">$_SERVER</span>[<span class="string">'HTTP_HOST'</span>]); <span class="comment">//设置 referer</span></span><br><span class="line"> curl_setopt(<span class="variable">$ch</span>,CURLOPT_FOLLOWLOCATION,<span class="number">1</span>); <span class="comment">//跟踪301</span></span><br><span class="line"> curl_setopt(<span class="variable">$ch</span>, CURLOPT_RETURNTRANSFER, <span class="number">1</span>); <span class="comment">//返回结果</span></span><br><span class="line"> <span class="variable">$r</span> = curl_exec(<span class="variable">$ch</span>);</span><br><span class="line"> curl_close(<span class="variable">$ch</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="variable">$r</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="13-不区分大小写的-in-array"><a href="#13-不区分大小写的-in-array" class="headerlink" title="13.不区分大小写的 in_array"></a>13.不区分大小写的 in_array</h3><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 不区分大小写的in_array()</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> string $str 检测的字符</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> array $array 数组</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> boolear 是否in_array</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">in_iarray</span>(<span class="params"><span class="variable">$str</span>,<span class="variable">$array</span></span>)</span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="variable">$str</span> = strtolower(<span class="variable">$str</span>);</span><br><span class="line"> <span class="variable">$array</span> = array_map(<span class="string">'strtolower'</span>, <span class="variable">$array</span>);</span><br><span class="line"> <span class="keyword">if</span> (in_array(<span class="variable">$str</span>, <span class="variable">$array</span>)) {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="14-根据时间戳计算距离现在的时间"><a href="#14-根据时间戳计算距离现在的时间" class="headerlink" title="14.根据时间戳计算距离现在的时间"></a>14.根据时间戳计算距离现在的时间</h3><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 传入时间戳,计算距离现在的时间</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> number $time 时间戳</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> string 返回多少以前</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">word_time</span>(<span class="params"><span class="variable">$time</span></span>) </span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="variable">$time</span> = (<span class="keyword">int</span>) substr(<span class="variable">$time</span>, <span class="number">0</span>, <span class="number">10</span>);</span><br><span class="line"> <span class="variable">$int</span> = time() - <span class="variable">$time</span>;</span><br><span class="line"> <span class="variable">$str</span> = <span class="string">''</span>;</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$int</span> <= <span class="number">2</span>){</span><br><span class="line"> <span class="variable">$str</span> = sprintf(<span class="string">'刚刚'</span>, <span class="variable">$int</span>);</span><br><span class="line"> } <span class="keyword">elseif</span> (<span class="variable">$int</span> < <span class="number">60</span>){</span><br><span class="line"> <span class="variable">$str</span> = sprintf(<span class="string">'%d秒前'</span>, <span class="variable">$int</span>);</span><br><span class="line"> }<span class="keyword">elseif</span> (<span class="variable">$int</span> < <span class="number">3600</span>){</span><br><span class="line"> <span class="variable">$str</span> = sprintf(<span class="string">'%d分钟前'</span>, floor(<span class="variable">$int</span> / <span class="number">60</span>));</span><br><span class="line"> }<span class="keyword">elseif</span> (<span class="variable">$int</span> < <span class="number">86400</span>){</span><br><span class="line"> <span class="variable">$str</span> = sprintf(<span class="string">'%d小时前'</span>, floor(<span class="variable">$int</span> / <span class="number">3600</span>));</span><br><span class="line"> }<span class="keyword">elseif</span> (<span class="variable">$int</span> < <span class="number">1728000</span>){</span><br><span class="line"> <span class="variable">$str</span> = sprintf(<span class="string">'%d天前'</span>, floor(<span class="variable">$int</span> / <span class="number">86400</span>));</span><br><span class="line"> }<span class="keyword">else</span>{</span><br><span class="line"> <span class="variable">$str</span> = date(<span class="string">'Y-m-d H:i:s'</span>, <span class="variable">$time</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="variable">$str</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="15-获取访问设备的类型"><a href="#15-获取访问设备的类型" class="headerlink" title="15.获取访问设备的类型"></a>15.获取访问设备的类型</h3><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 获取当前访问的设备类型</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> integer 1:其他 2:iOS 3:Android</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">get_device_type</span>(<span class="params"></span>)</span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="comment">//全部变成小写字母</span></span><br><span class="line"> <span class="variable">$agent</span> = strtolower(<span class="variable">$_SERVER</span>[<span class="string">'HTTP_USER_AGENT'</span>]);</span><br><span class="line"> <span class="variable">$type</span> = <span class="number">1</span>;</span><br><span class="line"> <span class="comment">//分别进行判断</span></span><br><span class="line"> <span class="keyword">if</span>(strpos(<span class="variable">$agent</span>, <span class="string">'iphone'</span>) !== <span class="literal">false</span> || strpos(<span class="variable">$agent</span>, <span class="string">'ipad'</span>) !== <span class="literal">false</span>){</span><br><span class="line"> <span class="variable">$type</span> = <span class="number">2</span>;</span><br><span class="line"> } </span><br><span class="line"> <span class="keyword">if</span>(strpos(<span class="variable">$agent</span>, <span class="string">'android'</span>) !== <span class="literal">false</span>){</span><br><span class="line"> <span class="variable">$type</span> = <span class="number">3</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="variable">$type</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="16-下载文件"><a href="#16-下载文件" class="headerlink" title="16.下载文件"></a>16.下载文件</h3><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">download</span>(<span class="params"><span class="variable">$file_url</span>, <span class="variable">$new_name</span> = <span class="string">''</span></span>)</span></span><br><span class="line"><span class="function"></span>{ </span><br><span class="line"><span class="keyword">if</span>(!<span class="keyword">isset</span>(<span class="variable">$file_url</span>) || trim(<span class="variable">$file_url</span>) == <span class="string">''</span>){ </span><br><span class="line"><span class="keyword">return</span> <span class="string">'500'</span>; </span><br><span class="line">}</span><br><span class="line"><span class="keyword">if</span>(!file_exists(<span class="variable">$file_url</span>)){ </span><br><span class="line"><span class="comment">//检查文件是否存在 </span></span><br><span class="line"><span class="keyword">return</span> <span class="string">'404'</span>; </span><br><span class="line">}</span><br><span class="line"><span class="variable">$file_name</span> = basename(<span class="variable">$file_url</span>); </span><br><span class="line"><span class="variable">$file_type</span> = explode(<span class="string">'.'</span>, <span class="variable">$file_url</span>); </span><br><span class="line"><span class="variable">$file_type</span> = <span class="variable">$file_type</span>[count(<span class="variable">$file_type</span>) - <span class="number">1</span>]; </span><br><span class="line"><span class="variable">$file_name</span> = trim(<span class="variable">$new_name</span> == <span class="string">''</span>) ? <span class="variable">$file_name</span> : urlencode(<span class="variable">$new_name</span>) .<span class="string">'.'</span>. <span class="variable">$file_type</span>; </span><br><span class="line"><span class="variable">$file_type</span> = fopen(<span class="variable">$file_url</span>, <span class="string">'r'</span>); <span class="comment">//打开文件 </span></span><br><span class="line"><span class="comment">//输入文件标签 </span></span><br><span class="line">header(<span class="string">"Content-type: application/octet-stream"</span>); </span><br><span class="line">header(<span class="string">"Accept-Ranges: bytes"</span>); </span><br><span class="line">header(<span class="string">"Accept-Length: "</span>.filesize(<span class="variable">$file_url</span>)); </span><br><span class="line">header(<span class="string">"Content-Disposition: attachment; filename="</span>.<span class="variable">$file_name</span>); </span><br><span class="line"><span class="comment">//输出文件内容 </span></span><br><span class="line"><span class="keyword">echo</span> fread(<span class="variable">$file_type</span>, filesize(<span class="variable">$file_url</span>)); </span><br><span class="line">fclose(<span class="variable">$file_type</span>); </span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category> PHP </category>
</categories>
<tags>
<tag> PHP </tag>
</tags>
</entry>
<entry>
<title>ThinkPHP 3.2 字母函数指南</title>
<link href="/2021/11/be55dc4abd4f/"/>
<url>/2021/11/be55dc4abd4f/</url>
<content type="html"><![CDATA[<h1 id="A-方法"><a href="#A-方法" class="headerlink" title="A 方法"></a>A 方法</h1><p>用于在内部实例化控制器,调用格式:</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// A('[项目://][分组/]模块','控制器层名称')</span></span><br><span class="line"><span class="variable">$User</span> = A(<span class="string">'User'</span>);</span><br><span class="line"><span class="variable">$User</span> = A(<span class="string">'Admin://User'</span>);</span><br></pre></td></tr></table></figure><span id="more"></span><p>实例化控制器后,就可以调用该控制器中的方法,不过需要注意的情况是,在跨项目调用的情况下,如果你的操作方法 有针对当前控制器的特殊变量操作,会有一些未知的问题,所以,一般来说,官方建议需要公共调用的控制器层单独开发,不要有太多的依赖关系。</p><h1 id="B-方法"><a href="#B-方法" class="headerlink" title="B 方法"></a>B 方法</h1><p>这是随着行为应运而生的新生函数,可以执行某个行为,例如</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">B(<span class="string">'app_begin'</span>);</span><br></pre></td></tr></table></figure><p>就是在项目开始之前,执行这个行为定义的所有函数。支持 2 个参数,第二个参数支持需要接受一个数组,例如</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">B(<span class="string">'app_begin'</span>, [<span class="string">"name"</span> => <span class="string">"tdweb"</span>,<span class="string">"time"</span>=>time()]);</span><br></pre></td></tr></table></figure><h1 id="C-方法"><a href="#C-方法" class="headerlink" title="C 方法"></a>C 方法</h1><p>C 方法是 Think 用于设置、获取,以及保存配置参数的方法,使用频率较高。</p><p>动态设置配置参数,配置参数不区分大小写,但是建议保持统一大写的配置定义规范。</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">C(<span class="string">'DB_NAME'</span>,<span class="string">'think'</span>);</span><br></pre></td></tr></table></figure><p>支持二级配置参数的设置,配置参数不建议超过二级。例如:</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">C(<span class="string">'USER.USER_ID'</span>,<span class="number">8</span>);</span><br></pre></td></tr></table></figure><p>如果要设置多个参数,可以使用批量设置,例如:</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$config</span>[<span class="string">'user_id'</span>] = <span class="number">1</span>;</span><br><span class="line"><span class="variable">$config</span>[<span class="string">'user_type'</span>] = <span class="number">1</span>;</span><br><span class="line">C(<span class="variable">$config</span>);</span><br></pre></td></tr></table></figure><p>如果传入的配置参数为空,表示获取全部的参数:</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$config</span> = C();</span><br></pre></td></tr></table></figure><h1 id="D-方法"><a href="#D-方法" class="headerlink" title="D 方法"></a>D 方法</h1><p>D 方法应该是用的比较多的方法了,用于实例化自定义模型类,是 Think 框架对 Model 类实例化的一种封装,并实现了单例模式,支持跨项目和分组调用,调用格式如下:</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">D(<span class="string">'[项目://][分组/]模型'</span>,<span class="string">'模型层名称'</span>)</span><br></pre></td></tr></table></figure><p>方法的返回值是实例化的模型对象。</p><p>D 方法可以自动检测模型类,如果存在自定义的模型类,则实例化自定义模型类,如果不存在,则会实例化 Model 基类,同时对于已实例化过的模型,不会重复去实例化。</p><p>D 方法最常用的用法就是实例化当前项目的某个自定义模型,例如:</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 实例化 User 模型</span></span><br><span class="line"><span class="variable">$User</span> = D(<span class="string">'User'</span>);</span><br></pre></td></tr></table></figure><h1 id="F-方法"><a href="#F-方法" class="headerlink" title="F 方法"></a>F 方法</h1><p>F 方法其实是 S 方法的一个子集功能,仅用于简单数据缓存,并且只能支持文件形式,不支持缓存有效期,因为采用的是返回方式,所以其效率较 S 方法较高,因此我们也称之为快速缓存方法。</p><p>F 方法的特点是:</p><ul><li>简单数据缓存;</li><li>文件形式保存;</li><li>采用返回数据方式加载缓存;</li><li>支持子目录缓存以及自动创建;</li><li>支持删除缓存和批量删除;</li></ul><p>写入和读取缓存</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">F(<span class="string">'data'</span>,<span class="string">'test data'</span>);</span><br></pre></td></tr></table></figure><p>默认的保存起始路径是 <em>DATA_PATH</em>(该常量在默认配置位于 <em>RUNTIME_PATH.’Data/‘</em> 下面),也就是说会生成文件名为 <em>DATA_PATH.’data.’</em> 的缓存文件。</p><p>注意:确保你的缓存标识的唯一,避免数据覆盖和冲突。</p><p>下次读取缓存数据的时候,使用:</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$Data</span> = F(<span class="string">'data'</span>);</span><br></pre></td></tr></table></figure><p>我们可以采用子目录方式保存,例如:</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">F(<span class="string">'user/data'</span>,<span class="variable">$data</span>); <span class="comment">// 缓存写入</span></span><br><span class="line">F(<span class="string">'user/data'</span>); <span class="comment">// 读取缓存</span></span><br></pre></td></tr></table></figure><p>就会生成 <em>DATA_PATH.’user/data.’</em> 缓存文件,如果 user 子目录不存在的话,则会自动创建,也可以支持多级子目录,例如:</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">F(<span class="string">'level1/level2/data'</span>,<span class="variable">$data</span>);</span><br></pre></td></tr></table></figure><p>如果需要指定缓存的起始目录,可以用下面的方式:</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">F(<span class="string">'data'</span>,<span class="variable">$data</span>,TEMP_PATH);</span><br></pre></td></tr></table></figure><p>删除缓存</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">F(<span class="string">'data'</span>,<span class="literal">NULL</span>);</span><br></pre></td></tr></table></figure><h1 id="G-方法"><a href="#G-方法" class="headerlink" title="G 方法"></a>G 方法</h1><p>G 方法的作用包括标记位置和区间统计两个功能,下面来看下具体用法:</p><h2 id="标记位置"><a href="#标记位置" class="headerlink" title="标记位置"></a>标记位置</h2><p>G 方法的第一个用法就是标记位置,例如:</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">G(<span class="string">'begin'</span>);</span><br></pre></td></tr></table></figure><p>表示把当前位置标记为 begin 标签,并且记录当前位置的执行时间,如果环境支持的话,还能记录内存占用情况。可以在任何位置调用 G 方法标记。</p><h2 id="运行时间统计"><a href="#运行时间统计" class="headerlink" title="运行时间统计"></a>运行时间统计</h2><p>标记位置后,我们就可以再次调用 G 方法进行区间统计了,例如:</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">G(<span class="string">'begin'</span>);</span><br><span class="line"><span class="comment">// ...其他代码段</span></span><br><span class="line">G(<span class="string">'end'</span>);</span><br><span class="line"><span class="comment">// ...也许这里还有其他代码</span></span><br><span class="line"><span class="comment">// 进行统计区间</span></span><br><span class="line"><span class="keyword">echo</span> G(<span class="string">'begin'</span>,<span class="string">'end'</span>).<span class="string">'s'</span>;</span><br></pre></td></tr></table></figure><p><em>G(‘begin’,’end’)</em> 表示统计 begin 位置到 end 位置的执行时间(单位是秒),begin 必须是一个已经标记过的位置,如果这个时候 end 位置还没被标记过,则会自动把当前位置标记为 end 标签,输出的结果类似于:</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">0.0056</span>s</span><br></pre></td></tr></table></figure><p>默认的统计精度是小数点后 4 位,如果觉得这个统计精度不够,还可以设置例如:</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">G(<span class="string">'begin'</span>,<span class="string">'end'</span>,<span class="number">6</span>).<span class="string">'s'</span>;</span><br></pre></td></tr></table></figure><p>内存开销统计</p><p>如果你的环境支持内存占用统计的话,还可以使用 G 方法进行区间内存开销统计(单位为 kb),例如:</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">echo</span> G(<span class="string">'begin'</span>,<span class="string">'end'</span>,<span class="string">'m'</span>).<span class="string">'kb'</span>;</span><br></pre></td></tr></table></figure><p>第三个参数使用 m 表示进行内存开销统计,输出的结果可能是:</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">625</span>kb</span><br></pre></td></tr></table></figure><h1 id="I-方法"><a href="#I-方法" class="headerlink" title="I 方法"></a>I 方法</h1><p>正如你所见到的一样,I 方法是 Thinkphp 众多单字母函数中的新成员,其命名来自于英文 Input(输入),主要用于更加方便和安全的获取系统输入变量,可以用于任何地方,用法格式如下:</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">I(<span class="string">'变量类型.变量名'</span>,[<span class="string">'默认值'</span>],[<span class="string">'过滤方法'</span>])</span><br></pre></td></tr></table></figure><p>变量类型是指请求方式或者输入类型,包括:</p><table><thead><tr><th align="center">方式</th><th align="center">说明</th></tr></thead><tbody><tr><td align="center">get</td><td align="center">获取 GET 参数</td></tr><tr><td align="center">post</td><td align="center">获取 POST 参数</td></tr><tr><td align="center">param</td><td align="center">自动判断请求类型获取 GET、POST 或者 PUT 参数</td></tr><tr><td align="center">request</td><td align="center">获取 REQUEST 参数</td></tr><tr><td align="center">put</td><td align="center">获取 PUT 参数</td></tr><tr><td align="center">session</td><td align="center">获取 $_SESSION 参数</td></tr><tr><td align="center">cookie</td><td align="center">获取 $_COOKIE 参数</td></tr><tr><td align="center">server</td><td align="center">获取 $_SERVER 参数</td></tr><tr><td align="center">globals</td><td align="center">获取 $GLOBALS 参数</td></tr></tbody></table><p>注意:变量类型不区分大小写。变量名则严格区分大小写。</p><p>默认值和过滤方法均属于可选参数。</p><h1 id="L-方法"><a href="#L-方法" class="headerlink" title="L 方法"></a>L 方法</h1><p>L 方法用于启用多语言的情况下,设置和获取当前的语言定义。</p><p>调用格式:</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">L(<span class="string">'语言变量'</span>,[<span class="string">'语言值'</span>])</span><br></pre></td></tr></table></figure><h1 id="M-方法"><a href="#M-方法" class="headerlink" title="M 方法"></a>M 方法</h1><p>M 方法用于实例化一个基础模型类,和 D 方法的区别在于:</p><ul><li>不需要自定义模型类,减少 IO 加载,性能较好;</li><li>实例化后只能调用基础模型类(默认是 Model 类)中的方法;</li><li>可以在实例化的时候指定表前缀、数据库和数据库的连接信息;</li></ul><p>D 方法的强大则体现在你封装的自定义模型类有多强,不过随着新版 Think 框架的基础模型类的功能越来越强大,M 方法也比 D 方法越来越实用了。</p><p>M 方法的调用格式:</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">M(<span class="string">'[基础模型名:]模型名'</span>,<span class="string">'数据表前缀'</span>,<span class="string">'数据库连接信息'</span>)</span><br></pre></td></tr></table></figure><h1 id="R-方法"><a href="#R-方法" class="headerlink" title="R 方法"></a>R 方法</h1><p>R 方法用于调用某个控制器的操作方法,是 A 方法的进一步增强和补充。</p><p>R 方法的调用格式:</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">R(<span class="string">'[项目://][分组/]模块/操作'</span>,<span class="string">'参数'</span>,<span class="string">'控制器层名称'</span>)</span><br></pre></td></tr></table></figure><p>可以通过 R 方法在其他控制器里面调用这个操作方法(一般 R 方法用于跨模块调用)</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$data</span> = R(<span class="string">'User/detail'</span>,<span class="keyword">array</span>(<span class="string">'5'</span>));</span><br></pre></td></tr></table></figure><p>官方的建议是不要在同一层多太多调用,会引起逻辑的混乱,被公共调用的部分应该封装成单独的接口,可以借助3.1的新特性多层控制器,单独添加一个控制器层用于接口调用</p><h1 id="S-方法"><a href="#S-方法" class="headerlink" title="S 方法"></a>S 方法</h1><p>S 方法还支持对当前的缓存方式传入缓存参数,例如:</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">S(<span class="string">'data'</span>,<span class="variable">$Data</span>,<span class="number">3600</span>,<span class="string">'File'</span>,<span class="keyword">array</span>(<span class="string">'length'</span>=><span class="number">10</span>,<span class="string">'temp'</span>=>RUNTIME_PATH.<span class="string">'temp/'</span>));</span><br></pre></td></tr></table></figure><h1 id="T-方法"><a href="#T-方法" class="headerlink" title="T 方法"></a>T 方法</h1><p>为了更方便的输出模板文件,新版封装了一个 T 函数用于生成模板文件名。</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">T([资源:<span class="comment">//][模块@][主题/][控制器/]操作,[视图分层])</span></span><br></pre></td></tr></table></figure><p>T 函数的返回值是一个完整的模板文件名,可以直接用于 display 和 fetch 方法进行渲染输出。</p><h1 id="U-方法"><a href="#U-方法" class="headerlink" title="U 方法"></a>U 方法</h1><p>U 方法用于完成对 URL 地址的组装,特点在于可以自动根据当前的 URL 模式和设置生成对应的 URL 地址,格式为:</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">U(<span class="string">'地址'</span>,<span class="string">'参数'</span>,<span class="string">'伪静态'</span>,<span class="string">'是否跳转'</span>,<span class="string">'显示域名'</span>);</span><br></pre></td></tr></table></figure><p>在模板中使用 U 方法而不是固定写死 URL 地址的好处在于,一旦你的环境变化或者参数设置改变,你不需要更改模板中的任何代码。</p>]]></content>
<categories>
<category> PHP </category>
</categories>
<tags>
<tag> PHP </tag>
<tag> ThinkPHP </tag>
</tags>
</entry>
</search>