-
Notifications
You must be signed in to change notification settings - Fork 0
/
search.xml
545 lines (308 loc) · 441 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
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>模型软删除修改</title>
<link href="/softDelete.html"/>
<url>/softDelete.html</url>
<content type="html"><![CDATA[<p>  由于框架底层自带的软删除默认使用的是删除时间(默认字段名deleted_at)作来标记某条记录是否已被删除。</p><ul><li>存在问题:当正常执行一条查询时,第一个过滤条件就是deleted_at is null, 在mysql数据库中null是无法被建立索引的,所以在数据量大的时候,会造成很严重的查询缓慢。</li><li>解决方案:修改deleted_at 字段类型为int,默认值为0,无符号,不为null,并通过存入时间戳标记是否删除。这里会涉及到模型底层的相关修改。</li></ul><p>在实际开发中,一般是不随意修改框架底层的,所以个人选择重写,将SoftDeletes类和SoftDeletingScope类源码复制修改即可。</p><h4 id="触发原理"><a href="#触发原理" class="headerlink" title="触发原理"></a>触发原理</h4><p>当在任意一个模型中 use SoftDeletes之后,是如何在最终的查询语句里添加deleted_at=0 的,以下面模型为例<br><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="keyword">namespace</span> <span class="title">App</span>;</span><br><span class="line"><span class="keyword">use</span> <span class="title">App</span>\<span class="title">Rewrites</span>\<span class="title">SoftDeletes</span>; <span class="comment">//重写的软删除类</span></span><br><span class="line"><span class="keyword">use</span> <span class="title">Illuminate</span>\<span class="title">Database</span>\<span class="title">Eloquent</span>\<span class="title">Model</span>;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Department</span> <span class="keyword">extends</span> <span class="title">Model</span> </span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">use</span> <span class="title">SoftDeletes</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">protected</span> $primaryKey = <span class="string">'department_id'</span>;</span><br><span class="line"> <span class="keyword">protected</span> $table = <span class="string">'department'</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><br><a id="more"></a><br>在Department模型实例化时,通过基类的构造方法中bootIfNotBooted,然后执行boot方法,再触发bootTraits方法。在bootTraits方法中获取模型中用到的trait类,然后循环遍历,判断trait类中是否存在bootClassname的方法,有则执行。<br><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">//基类Model</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">(array $attributes = [])</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line">...</span><br><span class="line"> <span class="keyword">$this</span>->bootIfNotBooted();</span><br><span class="line"> ..</span><br><span class="line">}</span><br><span class="line"><span class="keyword">protected</span> <span class="keyword">static</span> <span class="function"><span class="keyword">function</span> <span class="title">bootTraits</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="comment">//获取模型中用到的trait类</span></span><br><span class="line"> <span class="keyword">foreach</span> (class_uses_recursive(get_called_class()) <span class="keyword">as</span> $trait) {</span><br><span class="line"> <span class="comment">// 如果softDelete类中存在bootsoftDelete方法</span></span><br><span class="line"> <span class="keyword">if</span> (method_exists(get_called_class(), $method = <span class="string">'boot'</span>.class_basename($trait))) {</span><br><span class="line"> <span class="comment">//静态调用,执行SoftDeletes中的bootSoftDeletes方法</span></span><br><span class="line"> forward_static_call([get_called_class(), $method]);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><h4 id="bootSoftDeletes"><a href="#bootSoftDeletes" class="headerlink" title="bootSoftDeletes"></a>bootSoftDeletes</h4><p>启用软删除,为当前模型添加一个全局查询SoftDeletingScope, 在Model类中获取一个newQuery时,就会应用这个全局Scope,即执行SoftDeletingScope类上的apply方法。<br><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="comment">//SoftDeletes</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="function"><span class="keyword">function</span> <span class="title">bootSoftDeletes</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">static</span>::addGlobalScope(<span class="keyword">new</span> SoftDeletingScope);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//Model</span></span><br><span class="line"><span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">newQuery</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> $builder = <span class="keyword">$this</span>->newQueryWithoutScopes();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->applyGlobalScopes($builder);</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">applyGlobalScopes</span><span class="params">($builder)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="keyword">$this</span>->getGlobalScopes() <span class="keyword">as</span> $scope) {</span><br><span class="line"> <span class="comment">//应用Scope</span></span><br><span class="line"> $scope->apply($builder, <span class="keyword">$this</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> $builder;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><br>关于Scope的简单说明,假设User模型上有一个常用的多个条件查询,并定义其为一个scope。这样就可以在该模型上的其他查询上直接‘拼接’scope条件。<br><figure class="highlight clean"><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="comment">//抽象比喻,非具体实现代码</span></span><br><span class="line">$scope = <span class="keyword">where</span>(<span class="string">'statu1'</span>,<span class="number">1</span>)-><span class="keyword">where</span>(<span class="string">'status2'</span>,<span class="number">2</span>)-><span class="keyword">where</span>(<span class="string">'status3'</span>,<span class="number">3</span>);</span><br><span class="line"></span><br><span class="line">User::<span class="keyword">where</span>(<span class="string">'user_id'</span>,<span class="number">1</span>)->$scope();</span><br></pre></td></tr></table></figure><br>执行apply方法,使用了软删除scope。这里的是重写后的代码。源码使用的whereNull(‘deleted_at’)查询。<br><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="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">apply</span><span class="params">(Builder $builder, Model $model)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="comment">//源码 whereNull($model->getQualifiedDeletedAtColumn())</span></span><br><span class="line"> $builder->where($model->getQualifiedDeletedAtColumn(),<span class="number">0</span>);</span><br><span class="line"> <span class="keyword">$this</span>->extend($builder);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><br>我们要的目的很明确,在使用软删除的模型上都加上where(‘deleted_at’,0)条件。下面修改SoftDeletingScope中的所有相关查询条件:<br><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="comment">//SoftDeletingScope类</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">extend</span><span class="params">(Builder $builder)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line">...</span><br><span class="line"> <span class="keyword">return</span> $builder->update([</span><br><span class="line"> $column => time(), <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><br><span class="line"><span class="comment">//软删除数据恢复</span></span><br><span class="line"><span class="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">addRestore</span><span class="params">(Builder $builder)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line">...</span><br><span class="line"> <span class="keyword">return</span> $builder->update([$builder->getModel()->getDeletedAtColumn() => <span class="number">0</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="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">addOnlyTrashed</span><span class="params">(Builder $builder)</span></span></span><br><span class="line"><span class="function"></span>{...</span><br><span class="line"> $builder->getQuery()->where($model->getQualifiedDeletedAtColumn(),<span class="string">'>'</span>,<span class="number">0</span>);</span><br><span class="line"> ...</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//SoftDelete类,当执行模型的delete()方法时,实则执行runSoftDelete</span></span><br><span class="line"><span class="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">runSoftDelete</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> $query = <span class="keyword">$this</span>->newQueryWithoutScopes()->where(<span class="keyword">$this</span>->getKeyName(), <span class="keyword">$this</span>->getKey());</span><br><span class="line"></span><br><span class="line"> <span class="keyword">$this</span>->{<span class="keyword">$this</span>->getDeletedAtColumn()} = $time = time(); </span><br><span class="line"></span><br><span class="line"> $query->update([<span class="keyword">$this</span>->getDeletedAtColumn() => time()]); <span class="comment">// 更新时间戳</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><h4 id="withTrash修复"><a href="#withTrash修复" class="headerlink" title="withTrash修复"></a>withTrash修复</h4><p>当修改完毕后,当使用模型上的delete、get、onlyTrashed等方法这些都是没有问题,除了withTrash 方法。用一个实际查询举例<br><figure class="highlight clean"><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">Department::withTrash()-><span class="keyword">where</span>(<span class="string">'id'</span>,<span class="string">'<'</span>,<span class="number">9</span>)->get()</span><br><span class="line"><span class="comment">//执行流程与前者是不同的,但结果一样。</span></span><br><span class="line">Department::<span class="keyword">where</span>(<span class="string">'id'</span>,<span class="string">'<'</span>,<span class="number">9</span>)->withTrash()->get()</span><br></pre></td></tr></table></figure></p><p>当执行new static实例化模型时,软删除scope( 即where(deleted_at,0) )就已经被加上去了。由于我们需要查询所有数据,包括被标记为已删除的数据,所有需要把查询条件中的deleted_at=0去掉。<br><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="comment">//SoftDeletingScope</span></span><br><span class="line"><span class="comment">//前者,直接执行SoftDelete类上的withTrashed方法,获取当前模型实例,并移除软删除scope</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="function"><span class="keyword">function</span> <span class="title">withTrashed</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">new</span> <span class="keyword">static</span>)->newQueryWithoutScope(<span class="keyword">new</span> SoftDeletingScope);</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">newQueryWithoutScope</span><span class="params">($scope)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">$this</span>->getGlobalScope($scope)->remove($builder = <span class="keyword">$this</span>->newQuery(), <span class="keyword">$this</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> $builder;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//后者实则是执行Eloquent\Builder上的withTrash方法,</span></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__call</span><span class="params">($method, $parameters)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="comment">//macros数组的值则是在SoftDeletingScope中执行apply方法里的extend方法,储存的</span></span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">isset</span>(<span class="keyword">$this</span>->macros[$method])) {</span><br><span class="line"> array_unshift($parameters, <span class="keyword">$this</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> call_user_func_array(<span class="keyword">$this</span>->macros[$method], $parameters);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="comment">//macros数组来源,这里便为withTrashed绑定了一个回调并存放在macros</span></span><br><span class="line"><span class="comment">//SoftDeletingScope</span></span><br><span class="line"><span class="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">addWithTrashed</span><span class="params">(Builder $builder)</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> $builder->macro(<span class="string">'withTrashed'</span>, <span class="function"><span class="keyword">function</span> <span class="params">(Builder $builder)</span> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->remove($builder, $builder->getModel());</span><br><span class="line"> <span class="keyword">return</span> $builder;</span><br><span class="line"> });</span><br><span class="line"> }</span><br><span class="line"></span><br></pre></td></tr></table></figure><br>两种执行的最终结果都是执行了SoftDeletingScope中的remove方法,传入Eloquent\Builder,Department 作为参数,其目的就是去掉Builder里的软删除查询条件。<br>模型的最终数据,是通过Database\Query\Builder执行编译完成的查询语句来获取的。而查询语句的生成原理在这里很重要。<br><figure class="highlight awk"><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></pre></td><td class="code"><pre><span class="line"><span class="regexp">//</span>比如执行如下代码,分别对比源码及修改后的语句生成方式</span><br><span class="line"><span class="variable">$res</span> = Department::where(<span class="string">'id'</span>,<span class="string">'<'</span>,<span class="number">0</span>)->get();</span><br><span class="line"><span class="regexp">//</span>在语句完成前,对比Query\Builder中wheres和bindings属性数据</span><br><span class="line"></span><br><span class="line"><span class="regexp">//</span>修改源码之前</span><br><span class="line"><span class="regexp">//</span> wheres: array:<span class="number">1</span> [▼</span><br><span class="line"> <span class="regexp">//</span> <span class="number">0</span> => array:<span class="number">3</span> [▼</span><br><span class="line"> <span class="regexp">//</span> <span class="string">"type"</span> => <span class="string">"Null"</span></span><br><span class="line"> <span class="regexp">//</span> <span class="string">"column"</span> => <span class="string">"department.deleted_at"</span></span><br><span class="line"> <span class="regexp">//</span> <span class="string">"boolean"</span> => <span class="string">"and"</span></span><br><span class="line"> <span class="regexp">//</span> ],</span><br><span class="line"> <span class="regexp">//</span> <span class="number">1</span> => array:<span class="number">5</span> [▼</span><br><span class="line"> <span class="regexp">//</span> <span class="string">"type"</span> => <span class="string">"Basic"</span></span><br><span class="line"> <span class="regexp">//</span> <span class="string">"column"</span> => <span class="string">"department_id"</span></span><br><span class="line"> <span class="regexp">//</span> <span class="string">"operator"</span> => <span class="string">"<"</span></span><br><span class="line"> <span class="regexp">//</span> <span class="string">"value"</span> => <span class="number">9</span></span><br><span class="line"> <span class="regexp">//</span> <span class="string">"boolean"</span> => <span class="string">"and"</span></span><br><span class="line"> <span class="regexp">//</span> ]</span><br><span class="line"> <span class="regexp">//</span> ]</span><br><span class="line"> <span class="regexp">//</span> bindings: [ <span class="number">0</span> => <span class="number">9</span> ]</span><br><span class="line"></span><br><span class="line"> <span class="regexp">//</span>生成的预处理语句</span><br><span class="line"> <span class="string">"select * from department where department.deleted_at is null and department_id < ?"</span></span><br><span class="line"></span><br><span class="line"> <span class="regexp">//</span>withTrashed, 直接移除wheres中的第一个数组</span><br><span class="line"> <span class="string">"select * from department where department_id < ?"</span></span><br><span class="line"></span><br><span class="line"> <span class="regexp">//</span>修改源码之后</span><br><span class="line"> <span class="regexp">//</span> wheres: array:<span class="number">1</span> [▼</span><br><span class="line"> <span class="regexp">//</span> <span class="number">0</span> => array:<span class="number">3</span> [▼</span><br><span class="line"> <span class="regexp">//</span> <span class="string">"type"</span> => <span class="string">"Basic"</span></span><br><span class="line"> <span class="regexp">//</span> <span class="string">"column"</span> => <span class="string">"department.deleted_at"</span></span><br><span class="line"> <span class="regexp">//</span> <span class="string">"operator"</span> => <span class="string">"<"</span></span><br><span class="line"> <span class="regexp">//</span> <span class="string">"value"</span> => <span class="number">9</span></span><br><span class="line"> <span class="regexp">//</span> <span class="string">"boolean"</span> => <span class="string">"and"</span></span><br><span class="line"> <span class="regexp">//</span> ],</span><br><span class="line"> <span class="regexp">//</span> <span class="number">1</span> => array:<span class="number">5</span> [▼</span><br><span class="line"> <span class="regexp">//</span> <span class="string">"type"</span> => <span class="string">"Basic"</span></span><br><span class="line"> <span class="regexp">//</span> <span class="string">"column"</span> => <span class="string">"department_id"</span></span><br><span class="line"> <span class="regexp">//</span> <span class="string">"operator"</span> => <span class="string">"<"</span></span><br><span class="line"> <span class="regexp">//</span> <span class="string">"value"</span> => <span class="number">9</span></span><br><span class="line"> <span class="regexp">//</span> <span class="string">"boolean"</span> => <span class="string">"and"</span></span><br><span class="line"> <span class="regexp">//</span> ]</span><br><span class="line"> <span class="regexp">//</span> ]</span><br><span class="line"> <span class="regexp">//</span> bindings: [ <span class="number">0</span> => <span class="number">0</span> , <span class="number">1</span>=> <span class="number">9</span>] </span><br><span class="line"></span><br><span class="line"> <span class="regexp">//</span>生成的预处理语句</span><br><span class="line"> <span class="string">"select * from department where department.deleted_at = ? and department_id < ?"</span></span><br><span class="line"></span><br><span class="line"> <span class="regexp">//</span>withTrashed, 直接移除wheres中的第一个数组, </span><br><span class="line"> <span class="string">"select * from department where department_id < ?"</span></span><br><span class="line"></span><br><span class="line"> <span class="regexp">//</span>这里必须同时移除bindings数组中的第一个元素,否则执行的会是department_id<<span class="number">0</span></span><br><span class="line"></span><br></pre></td></tr></table></figure></p><p><font color="red">必须同时去掉软删除对应的where条件和bindings参数</font>最终修改结果如下:<br><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="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">remove</span><span class="params">(Builder $builder, Model $model)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> $column = $model->getQualifiedDeletedAtColumn();</span><br><span class="line"></span><br><span class="line"> $query = $builder->getQuery(); <span class="comment">//Database\Query\Builder</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">//其实就是array_filter()实现 </span></span><br><span class="line"> $query->wheres = collect($query->wheres)->reject(<span class="function"><span class="keyword">function</span> <span class="params">($where)</span> <span class="title">use</span> <span class="params">($column, $query)</span> </span>{</span><br><span class="line"> <span class="comment">//遍历wheres查询条件,并去掉软删除对应条件和绑定的参数</span></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->isSoftDeleteConstraint($where, $column, $query);</span><br><span class="line"> })->values()->all();</span><br><span class="line">}</span><br><span class="line"><span class="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">isSoftDeleteConstraint</span><span class="params">(array $where, $column, Query $query)</span></span></span><br><span class="line"><span class="function"></span>{ </span><br><span class="line"> $isSoft = $where[<span class="string">'value'</span>] === <span class="number">0</span> && $where[<span class="string">'column'</span>] == $column;</span><br><span class="line"> <span class="keyword">if</span>($isSoft){</span><br><span class="line"> $bindings = $query->getRawBindings()[<span class="string">'where'</span>];</span><br><span class="line"> array_shift($bindings);</span><br><span class="line"> <span class="comment">//重新设置where中的绑定数据</span></span><br><span class="line"> $query->setBindings($bindings);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> $isSoft;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>]]></content>
<categories>
<category> laravel源码学习分享 </category>
</categories>
</entry>
<entry>
<title>Eloquent模型类</title>
<link href="/Eloquent.html"/>
<url>/Eloquent.html</url>
<content type="html"><![CDATA[<p>关于模型类的理解,其实模型类是建立在DB类的QueryBuilder上面,将其查询结果赋值在模型的属性上,一条查询结果,便是独立的模型类。这里依然是举例子作分析。</p><h4 id="基本查询"><a href="#基本查询" class="headerlink" title="基本查询"></a>基本查询</h4><p>首先以 User::where(‘user_id’,1)->get() 作为基本分析。所有的模型类都是继承基类Model的,当执行where 方法时,本质都是执行的__call 方法,而最终执行的是 newQuery()->where。</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><br><span class="line"><span class="comment">//实例化调用 (new User())->where</span></span><br><span class="line"><span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__call</span><span class="params">($method, $parameters)</span></span></span><br><span class="line"><span class="function"></span>{ </span><br><span class="line"> <span class="keyword">if</span> (in_array($method, [<span class="string">'increment'</span>, <span class="string">'decrement'</span>])) {</span><br><span class="line"> <span class="keyword">return</span> call_user_func_array([<span class="keyword">$this</span>, $method], $parameters);</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//获取模型的查询列</span></span><br><span class="line"> $query = <span class="keyword">$this</span>->newQuery();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> call_user_func_array([$query, $method], $parameters);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//静态调用user::where</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="function"><span class="keyword">function</span> <span class="title">__callStatic</span><span class="params">($method, $parameters)</span></span></span><br><span class="line"><span class="function"></span>{ </span><br><span class="line"> $instance = <span class="keyword">new</span> <span class="keyword">static</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> call_user_func_array([$instance, $method], $parameters);</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><a id="more"></a><p>执行newQuery()方法,获取模型的查询类。注意点 newBaseQueryBuilder实质就是<font color="red">Illuminate\Database\Query\Builder类</font>,用来将获取真正的查询结果集。这里将DB类的Query\Builder传入newEloquentBuilder()方法中,返回模型的Eloquent\Builder类<br><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="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">newQuery</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="comment">//或取Eloquent\Builder类</span></span><br><span class="line"> $builder = <span class="keyword">$this</span>->newQueryWithoutScopes();</span><br><span class="line"></span><br><span class="line"> <span class="comment">//应用全局Scope查询域,这里主要是软删除</span></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->applyGlobalScopes($builder);</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">newQueryWithoutScopes</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="comment">//获取Eloquent\Builder类</span></span><br><span class="line"> $builder = <span class="keyword">$this</span>->newEloquentBuilder(</span><br><span class="line"> <span class="comment">//Query\Builder</span></span><br><span class="line"> <span class="keyword">$this</span>->newBaseQueryBuilder()</span><br><span class="line"> );</span><br><span class="line"> <span class="comment">//储存with数据</span></span><br><span class="line"> <span class="comment">//Eloquent\Builder中的model属性设置为当前User类,并</span></span><br><span class="line"> <span class="keyword">return</span> $builder->setModel(<span class="keyword">$this</span>)->with(<span class="keyword">$this</span>->with);</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><br>然后执行Eloquent\Builder中的where(‘user_id’,1)方法,可以清楚的看到就是执行当前模型中所绑定的Query\Builder类的where方法(这里实际上就是DB类的查询原理了)。<br><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><br><span class="line"><span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">where</span><span class="params">($column, $operator = null, $value = null, $boolean = <span class="string">'and'</span>)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> ....</span><br><span class="line"> call_user_func_array([<span class="keyword">$this</span>->query, <span class="string">'where'</span>], func_get_args());</span><br><span class="line"> ....</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><br>最后执行get方法,当getModels方法执行完毕时,结果集就已经获取完毕。 getModels主要做了三件事: </p><ul><li>$this->query->get ,直接获取数据集</li><li>获取当前模型对应的连接名 </li><li>将数据写入User模型里相关属性里,hydrate方法返回一个框架封装的Collection集合类,调用集合的all方法则将集合转为数组(Note: user模型类不变)</li><li></li></ul><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 class="comment">//获取结果集</span></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">($columns = [<span class="string">'*'</span>])</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> $models = <span class="keyword">$this</span>->getModels($columns);</span><br><span class="line"> <span class="comment">//with 查询</span></span><br><span class="line"> <span class="keyword">if</span> (count($models) > <span class="number">0</span>) {</span><br><span class="line"> <span class="comment">//with多个模型数据组装,</span></span><br><span class="line"> $models = <span class="keyword">$this</span>->eagerLoadRelations($models);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->model->newCollection($models);</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">getModels</span><span class="params">($columns = [<span class="string">'*'</span>])</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> $results = <span class="keyword">$this</span>->query->get($columns);</span><br><span class="line"></span><br><span class="line"> $connection = <span class="keyword">$this</span>->model->getConnectionName();</span><br><span class="line"></span><br><span class="line"> <span class="comment">//hydrate方法返回一个Collection类</span></span><br><span class="line"> <span class="comment">// Collection {</span></span><br><span class="line"> <span class="comment">// items: array:1 [</span></span><br><span class="line"> <span class="comment">// 0 => User { }</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">//</span></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->model->hydrate($results, $connection)->all();</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="with查询"><a href="#with查询" class="headerlink" title="with查询"></a>with查询</h4><p>User::where(‘user_id’,1)->with(‘depa’)->get()与 User::with(‘depa’)->where(‘user_id’,1)->get()执行结果虽然一致,但流程是不同的。</p><p>前者执行的是Eloquent\Builder上的with方法<br><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="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">with</span><span class="params">($relations)</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">if</span> (is_string($relations)) {</span><br><span class="line"> $relations = func_get_args();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> $eagers = <span class="keyword">$this</span>->parseRelations($relations);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">$this</span>->eagerLoad = array_merge(<span class="keyword">$this</span>->eagerLoad, $eagers);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>;</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><br>后者执行的Eloquent\Model上的with方法,但最终还是通过获取newQuery实例(即 Eloquent\Builder),然后继续执行with方法<br><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="keyword">public</span> <span class="keyword">static</span> <span class="function"><span class="keyword">function</span> <span class="title">with</span><span class="params">($relations)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (is_string($relations)) {</span><br><span class="line"> $relations = func_get_args();</span><br><span class="line"> }</span><br><span class="line"> $instance = <span class="keyword">new</span> <span class="keyword">static</span>;</span><br><span class="line"> <span class="keyword">return</span> $instance->newQuery()->with($relations);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><br>$this->eagerLoad 将需要渴求式加载的模型方法存入当前Builder类中,这里的eagerLoad实际上是一个由关系名对应的空闭包组成的数组<br><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="keyword">$this</span>->eagerLoad = [</span><br><span class="line"> <span class="string">'depa'</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></pre></td></tr></table></figure><br>eagerLoadRelations方法中的loadRelation方法,这里传入的就是[User], ‘depa’, function(){} 这三个参数。<br><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">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">loadRelation</span><span class="params">(array $models, $name, Closure $constraints)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"></span><br><span class="line"> $relation = <span class="keyword">$this</span>->getRelation($name);</span><br><span class="line"> <span class="comment">// 为关联关系限定查询条件 </span></span><br><span class="line"> $relation->addEagerConstraints($models); </span><br><span class="line"></span><br><span class="line"> call_user_func($constraints, $relation);</span><br><span class="line"></span><br><span class="line"> <span class="comment">//为当前模型设置relations 数组,默认为null。 这里是relations['depa'] =null,</span></span><br><span class="line"> $models = $relation->initRelation($models, $name);</span><br><span class="line"></span><br><span class="line"> <span class="comment">//通过关联关系,获取查询结果集</span></span><br><span class="line"> $results = $relation->getEager();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> $relation->match($models, $results, $name);</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>首先getRelation方法,根据User中定义的depa关联方法,返回一个hasOne的关联模型类(例子中用的hasOne)<br><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="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">getRelation</span><span class="params">($name)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"></span><br><span class="line"> $relation = Relation::noConstraints(<span class="function"><span class="keyword">function</span> <span class="params">()</span> <span class="title">use</span> <span class="params">($name)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->getModel()->$name();</span><br><span class="line"> });</span><br><span class="line"> <span class="comment">//是否嵌套关联,如with('depa.creator')</span></span><br><span class="line"> $nested = <span class="keyword">$this</span>->nestedRelations($name);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (count($nested) > <span class="number">0</span>) {</span><br><span class="line"> $relation->getQuery()->with($nested);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> $relation;</span><br><span class="line">}</span><br><span class="line"><span class="comment">//返回结果</span></span><br><span class="line">HasOne { </span><br><span class="line"> foreignKey: <span class="string">"department.department_id"</span></span><br><span class="line"> localKey: <span class="string">"depa_id"</span></span><br><span class="line"> query: Builder {}</span><br><span class="line"> <span class="keyword">parent</span>: User {}</span><br><span class="line"> related: Department {}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><br>getEager方法,执行get并触发魔术方法,实质是执行Eloquent\Builder->get()方法。<br><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="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">getEager</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>->get();</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">__call</span><span class="params">($method, $parameters)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> $result = call_user_func_array([<span class="keyword">$this</span>->query, $method], $parameters);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> ($result === <span class="keyword">$this</span>->query) {</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 class="keyword">return</span> $result;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><br>为关联关系限定查询条件 $relation->addEagerConstraints($models)。我们的例子中with(‘depa’)在实际查询中,对应的是where(depa_id = User->depa_id),那么这个查询的限定就是通过addEagerConstraints实现的<br><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="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">addEagerConstraints</span><span class="params">(array $models)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="comment">//获取外键depa_id, 获取所有models(可以是多个User模型)中对应的关联键中的值,相当于array_column('depa_id',[User,User])</span></span><br><span class="line"><span class="comment">//执行 whereIn('depa_id',[1,2,3...]);</span></span><br><span class="line"> <span class="keyword">$this</span>->query->whereIn(<span class="keyword">$this</span>->foreignKey, <span class="keyword">$this</span>->getKeys($models, <span class="keyword">$this</span>->localKey));</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>最终将获取的数据写入当前User模型的relations 数组中。</p>]]></content>
<categories>
<category> laravel源码学习分享 </category>
</categories>
<tags>
<tag> Eloquent模型 </tag>
</tags>
</entry>
<entry>
<title>DatabaseServiceProvider</title>
<link href="/database.html"/>
<url>/database.html</url>
<content type="html"><![CDATA[<p>提供数据库连接及DB操作,同时为模型(Eloquent)设置Connection获取方式</p><h4 id="boot"><a href="#boot" class="headerlink" title="boot"></a>boot</h4><p>这里为 <font color="red">Model模型类</font> 设置了 <font color="red">db连接获取方式</font> 和事件处理类<br><figure class="highlight css"><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="selector-tag">public</span> <span class="selector-tag">function</span> <span class="selector-tag">boot</span>()</span><br><span class="line">{</span><br><span class="line"> <span class="attribute">Model</span>::<span class="built_in">setConnectionResolver</span>($this->app[<span class="string">'db'</span>]);</span><br><span class="line"></span><br><span class="line"> <span class="attribute">Model</span>::<span class="built_in">setEventDispatcher</span>($this->app[<span class="string">'events'</span>]);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><br><a id="more"></a></p><h4 id="register"><a href="#register" class="headerlink" title="register"></a>register</h4><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="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">register</span><span class="params">()</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> Model::clearBootedModels(); <span class="comment">//清楚已经解析完毕的Model</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">$this</span>->registerEloquentFactory(); <span class="comment">//注册模型工厂类</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">//$this->registerQueueableEntityResolver(); //未使用过</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">//注册db.factory,返回对应的</span></span><br><span class="line"> <span class="keyword">$this</span>->app->singleton(<span class="string">'db.factory'</span>, <span class="function"><span class="keyword">function</span> <span class="params">($app)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> ConnectionFactory($app);</span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> <span class="keyword">$this</span>->app->singleton(<span class="string">'db'</span>, <span class="function"><span class="keyword">function</span> <span class="params">($app)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> DatabaseManager($app, $app[<span class="string">'db.factory'</span>]);</span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> <span class="keyword">$this</span>->app->bind(<span class="string">'db.connection'</span>, <span class="function"><span class="keyword">function</span> <span class="params">($app)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> $app[<span class="string">'db'</span>]->connection();</span><br><span class="line"> });</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>简单的查询 流程图,如 DB::table(‘user’)->where(‘id’,1)->get()<br><img src="/images/db_process.png"></p><h4 id="源码流程解析"><a href="#源码流程解析" class="headerlink" title="源码流程解析"></a>源码流程解析</h4><p>首先获取 DatabaseManager类, 执行table方法时,触发__call。<br><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="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span><span class="params">($app, ConnectionFactory $factory)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">$this</span>->app = $app;</span><br><span class="line"> <span class="keyword">$this</span>->factory = $factory; <span class="comment">// 连接工厂类</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//执行table('user')</span></span><br><span class="line"><span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__call</span><span class="params">($method, $parameters)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">return</span> call_user_func_array([<span class="keyword">$this</span>->connection(), $method], $parameters);</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">connection</span><span class="params">($name = null)</span></span></span><br><span class="line"><span class="function"></span>{ </span><br><span class="line"> <span class="comment">//解析连接名,默认读取database.php配置下的default对应的连接名</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">list</span>($name, $type) = <span class="keyword">$this</span>->parseConnectionName($name);</span><br><span class="line"></span><br><span class="line"> <span class="comment">//这里$name= mysql, $type=null</span></span><br><span class="line"> <span class="keyword">if</span> (! <span class="keyword">isset</span>(<span class="keyword">$this</span>->connections[$name])) {</span><br><span class="line"> <span class="comment">//根据配置中的连接名 ,获取连接类MysqlConnection</span></span><br><span class="line"> $connection = <span class="keyword">$this</span>->makeConnection($name); </span><br><span class="line"></span><br><span class="line"> <span class="comment">//为连接类设置读、写PDO</span></span><br><span class="line"> <span class="keyword">$this</span>->setPdoForType($connection, $type);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">$this</span>->connections[$name] = <span class="keyword">$this</span>->prepare($connection);</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//保存当前连接</span></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->connections[$name];</span><br><span class="line">}</span><br></pre></td></tr></table></figure><br>这里的makeConnection方法返回一个mysqlConnection类(继承Connection), 这个类设置了<font color="red">PDO连接、语法编译类QueryGrammar、语句执行类PostProcessor。</font><br><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="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span><span class="params">(PDO $pdo, $database = <span class="string">''</span>, $tablePrefix = <span class="string">''</span>, array $config = [])</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">$this</span>->pdo = $pdo;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">$this</span>->database = $database;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">$this</span>->tablePrefix = $tablePrefix;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">$this</span>->config = $config;</span><br><span class="line"> <span class="comment">//语法编译</span></span><br><span class="line"> <span class="keyword">$this</span>->useDefaultQueryGrammar();</span><br><span class="line"> <span class="comment">//语句执行</span></span><br><span class="line"> <span class="keyword">$this</span>->useDefaultPostProcessor();</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>DB::table(‘user’)执行后的返回值是 Illuminate\Database\Query\builder类<br><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="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">table</span><span class="params">($table)</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>->query()->from($table);</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">query</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">new</span> QueryBuilder(</span><br><span class="line"> <span class="keyword">$this</span>, <span class="keyword">$this</span>->getQueryGrammar(), <span class="keyword">$this</span>->getPostProcessor()</span><br><span class="line"> );</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><br>之后所有的where、whereIn、join等都是进行原生Sql语句的组装,并在最终执行runSelect返回查询结果集。其查询方式是通过预处理实现的。<br><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="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">runSelect</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="comment">// select * from `users` where `user_id` = ? or `depa_id` = ?</span></span><br><span class="line"> <span class="comment">//获取绑定的参数(数组)</span></span><br><span class="line"> <span class="comment">// [ 1, 2]</span></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->connection->select(<span class="keyword">$this</span>->toSql(), <span class="keyword">$this</span>->getBindings(), ! <span class="keyword">$this</span>->useWritePdo);</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>]]></content>
<categories>
<category> laravel源码学习分享 </category>
</categories>
<tags>
<tag> DatabaseServiceProvider </tag>
<tag> DB </tag>
<tag> Eloquent </tag>
</tags>
</entry>
<entry>
<title>Event-队列</title>
<link href="/event-queue.html"/>
<url>/event-queue.html</url>
<content type="html"><![CDATA[<div class="note success"><p>当事件监听了实现了ShouldQueue时,该事件就会通过队列进行处理。</p></div><p>根据已有事件监听者,在执行Dipatcher是,在队列(redis)里为其添加该监听者的序列化数据。在任务一条条执行(出队列),将数据解析,执行对应监听者类的方法(默认handler方法)。</p><h5 id="ShouldQueue"><a href="#ShouldQueue" class="headerlink" title="ShouldQueue"></a>ShouldQueue</h5><figure class="highlight actionscript"><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="comment">//实现ShouldQueue接口</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">TestListener1</span> <span class="keyword">implements</span> <span class="title">ShouldQueue</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">test</span><span class="params">()</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> </span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><a id="more"></a><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">//Dipatcher执行makeListener</span></span><br><span class="line"> <span class="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">createClassCallable</span><span class="params">($listener, $container)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line">...</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">$this</span>->handlerShouldBeQueued($class)) {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->createQueuedHandlerCallable($class, $method);</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="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">createQueuedHandlerCallable</span><span class="params">($class, $method)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="function"><span class="keyword">function</span> <span class="params">()</span> <span class="title">use</span> <span class="params">($class, $method)</span> </span>{</span><br><span class="line"> $arguments = <span class="keyword">$this</span>->cloneArgumentsForQueueing(func_get_args());</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (method_exists($class, <span class="string">'queue'</span>)) {</span><br><span class="line"> <span class="comment">//自定义的队列操作方法</span></span><br><span class="line"> <span class="keyword">$this</span>->callQueueMethodOnHandler($class, $method, $arguments);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">$this</span>->resolveQueue()->push(<span class="string">'Illuminate\Events\CallQueuedHandler@call'</span>, [</span><br><span class="line"> <span class="string">'class'</span> => $class, <span class="string">'method'</span> => $method, <span class="string">'data'</span> => serialize($arguments),</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><h5 id="resolveQueue"><a href="#resolveQueue" class="headerlink" title="resolveQueue"></a>resolveQueue</h5><p>resolveQueue通过执行 $app->make(‘Illuminate\Contracts\Queue\Factory’),实质获取QueueManager类。也就是执行了容器最初绑定event时,通过setQueueResolver为event赋予的闭包。<br><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">$this</span>->app->singleton(<span class="string">'events'</span>, <span class="function"><span class="keyword">function</span> <span class="params">($app)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> (<span class="keyword">new</span> Dispatcher($app))->setQueueResolver(</span><br><span class="line"> <span class="comment">//执行下面的闭包</span></span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="params">()</span> <span class="title">use</span> <span class="params">($app)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> $app->make(<span class="string">'Illuminate\Contracts\Queue\Factory'</span>);</span><br><span class="line"> });</span><br><span class="line">});</span><br></pre></td></tr></table></figure><br>说白了就是讲当前监听者类序列化, 将类名、执行方法、序列化后的数据存入队列,这里以redis为例。如执行event(new \App\Event\TestEvent())时,会在redis产生如下的数据:<br><figure class="highlight stata"><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="comment">//redis_key</span></span><br><span class="line">在默认<span class="keyword">DB</span>下 queues下 的 'queues:default'中</span><br><span class="line"><span class="comment">//数据</span></span><br><span class="line">{</span><br><span class="line"> <span class="string">"job"</span>: <span class="string">"Illuminate\\Events\\CallQueuedHandler@call"</span>,</span><br><span class="line"> <span class="string">"data"</span>: {</span><br><span class="line"> <span class="string">"class"</span>: <span class="string">"App\\Listeners\\TestListener1"</span>,</span><br><span class="line"> <span class="string">"method"</span>: <span class="string">"test"</span>,</span><br><span class="line"> <span class="string">"data"</span>: <span class="string">"a:1:{i:0;O:20:\"</span><span class="keyword">App</span>\\Events\\TestEvent\<span class="string">":0:{}}"</span></span><br><span class="line"> },</span><br><span class="line"> <span class="string">"id"</span>: <span class="string">"ihS5FJPgxxFOUdg7TxmWjErmmY2Q6PTk"</span>,</span><br><span class="line"> <span class="string">"attempts"</span>: 1</span><br><span class="line">}</span><br></pre></td></tr></table></figure><br>在实际开发过程有些事件的触发后不需要即时处理,那么就先放进队列,然后在出队列进行逐个处理,比如系统通知等。看到上面的json字符串,我们大概都能想到它的处理流程,最终其实也是执行了App\Listeners\TestListener1下的test方法。<br>关于出队列的处理,我们知道在命令行通过执行php artisan queue:work 就可以将这些队列任务处理完毕。</p>]]></content>
<categories>
<category> laravel源码学习分享 </category>
</categories>
<tags>
<tag> event队列 </tag>
</tags>
</entry>
<entry>
<title>queue之Artisan</title>
<link href="/queue-work.html"/>
<url>/queue-work.html</url>
<content type="html"><![CDATA[<div class="note success"><p>关于事件出队列的处理,即控制台的queue:work命令的原理解析。</p></div><h5 id="artisan命令写入"><a href="#artisan命令写入" class="headerlink" title="artisan命令写入"></a>artisan命令写入</h5><p>要执行queue:work命令,首先命令在artisan中必须是存在,那么它是在哪里写入的呢<br><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="comment">// QueueServiceProvider extends ServiceProvider</span></span><br><span class="line"><span class="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">registerWorkCommand</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>->app->singleton(<span class="string">'command.queue.work'</span>, <span class="function"><span class="keyword">function</span> <span class="params">($app)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> WorkCommand($app[<span class="string">'queue.worker'</span>]);</span><br><span class="line"> });</span><br><span class="line"> <span class="comment">//这里就是写入的地方</span></span><br><span class="line"> <span class="keyword">$this</span>->commands(<span class="string">'command.queue.work'</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//父类ServiceProvider</span></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">commands</span><span class="params">($commands)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> $commands = is_array($commands) ? $commands : func_get_args();</span><br><span class="line"></span><br><span class="line"> $events = <span class="keyword">$this</span>->app[<span class="string">'events'</span>];</span><br><span class="line"></span><br><span class="line"> $events->listen(<span class="string">'artisan.start'</span>, <span class="function"><span class="keyword">function</span> <span class="params">($artisan)</span> <span class="title">use</span> <span class="params">($commands)</span> </span>{</span><br><span class="line"> $artisan->resolveCommands($commands);</span><br><span class="line"> });</span><br><span class="line">}</span><br></pre></td></tr></table></figure><br>除了最底层的基本命令(如 help),其他命令一般都是在为服务提供者进行注册时进行的命令写入。可以看到在写入命令的同时,也为artisan.start注册了一个事件监听者。这个用途就是在当我们执行命令时,根据字符,解析成具体操作类。<br><a id="more"></a></p><h5 id="命令解析"><a href="#命令解析" class="headerlink" title="命令解析"></a>命令解析</h5><p>现在对 php artisan queue:work [ php 文件名 参数]。进行解析<br>命令行解析流程如下:</p><ul><li>获取artisan实例, Illuminate\Console\Application</li><li>artisan->resolveCommand(‘queue:work’),获取具体Command类</li><li>执行Command类->execute()方法<br>在这个例子中具体的Command实例就是WorkCommand类,然后执行其在这个例子中具体的Command实例就是WorkCommand类->execute()<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">//Illuminate\Console\Application时,进行事件触发处理</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">(Container $laravel, Dispatcher $events, $version)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line">...</span><br><span class="line"> $events->fire(<span class="string">'artisan.start'</span>, [<span class="keyword">$this</span>]);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//实际是父类(Illuminate\Console\Command)上的方法</span></span><br><span class="line"><span class="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">execute</span><span class="params">(InputInterface $input, OutputInterface $output)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> $method = method_exists(<span class="keyword">$this</span>, <span class="string">'handle'</span>) ? <span class="string">'handle'</span> : <span class="string">'fire'</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->laravel->call([<span class="keyword">$this</span>, $method]);</span><br><span class="line">}</span><br></pre></td></tr></table></figure>WorkCommand是没有handle方法的,所以执行fire方法。在执行process可以看到,会现在当前任务的执行尝试次数,如果不满足条件,则按失败处理,并执行相关处理方法<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="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">fire</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line">....</span><br><span class="line"> $response = <span class="keyword">$this</span>->runWorker(</span><br><span class="line"> $connection, $queue, $delay, $memory, <span class="keyword">$this</span>->option(<span class="string">'daemon'</span>)</span><br><span class="line"> );</span><br><span class="line"> ....</span><br><span class="line">}</span><br><span class="line"><span class="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">runWorker</span><span class="params">($connection, $queue, $delay, $memory, $daemon = false)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line">....</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->worker->pop(</span><br><span class="line"> $connection, $queue, $delay,</span><br><span class="line"> <span class="keyword">$this</span>->option(<span class="string">'sleep'</span>), <span class="keyword">$this</span>->option(<span class="string">'tries'</span>)</span><br><span class="line"> );</span><br><span class="line">}</span><br><span class="line"><span class="comment">//Illuminate\Queue\Worker</span></span><br><span class="line"><span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">process</span><span class="params">($connection, Job $job, $maxTries = <span class="number">0</span>, $delay = <span class="number">0</span>)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> ($maxTries > <span class="number">0</span> && $job->attempts() > $maxTries) {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->logFailedJob($connection, $job);</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//通过RedisQueue类获取RedisJob类</span></span><br><span class="line"> $job = <span class="keyword">$this</span>->getNextJob($connection, $queue);</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"></span><br><span class="line"> $job->fire();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">$this</span>->raiseAfterJobEvent($connection, $job);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> [<span class="string">'job'</span> => $job, <span class="string">'failed'</span> => <span class="keyword">false</span>];</span><br><span class="line"> } <span class="keyword">catch</span> (<span class="keyword">Exception</span> $e) {</span><br><span class="line"> ....</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>按当前例子,这里的Job可以理解为一条redis数据(待处理任务),任务类也是RedisJob类。<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><br><span class="line"> <span class="string">"job"</span>: <span class="string">"Illuminate\\Events\\CallQueuedHandler@call"</span>,</span><br><span class="line"> <span class="string">"data"</span>: {</span><br><span class="line"> <span class="string">"class"</span>: <span class="string">"App\\Listeners\\TestListener1"</span>,</span><br><span class="line"> <span class="string">"method"</span>: <span class="string">"test"</span>,</span><br><span class="line"> <span class="string">"data"</span>: <span class="string">"a:1:{i:0;O:20:\"App\\Events\\TestEvent\":0:{}}"</span></span><br><span class="line"> },</span><br><span class="line"> <span class="string">"id"</span>: <span class="string">"ihS5FJPgxxFOUdg7TxmWjErmmY2Q6PTk"</span>,</span><br><span class="line"> <span class="string">"attempts"</span>: <span class="number">1</span></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="string">"job"</span>: <span class="string">"Illuminate\\Broadcasting\\BroadcastEvent"</span>,</span><br><span class="line"> <span class="string">"data"</span>: {</span><br><span class="line"> <span class="string">"event"</span>: <span class="string">"O:20:\"App\\Events\\TestEvent\":0:{}"</span></span><br><span class="line"> },</span><br><span class="line"> <span class="string">"id"</span>: <span class="string">"SGGHgGBWHzJrH8pPZKrXAmaxujdTZJbj"</span>,</span><br><span class="line"> <span class="string">"attempts"</span>: <span class="number">1</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="function"><span class="keyword">function</span> <span class="title">fire</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>->resolveAndFire(json_decode(<span class="keyword">$this</span>->getRawBody(), <span class="keyword">true</span>));</span><br><span class="line">}</span><br></pre></td></tr></table></figure>resolveAndFire方法,将获取根据job字段值,获取具体操作实例。一般事件默认为Illuminate\Events\CallQueuedHandler@call。<font color="red">parseJob方法,如果没有@method, 则默认method为’fire’</font>,如广播事件则为Illuminate\Broadcasting\BroadcastEvent。 (相当于拼接.‘@fire’)。<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="comment">//基类Illuminate\Queue\Jobs\Job</span></span><br><span class="line"><span class="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">resolveAndFire</span><span class="params">(array $payload)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">list</span>($class, $method) = <span class="keyword">$this</span>->parseJob($payload[<span class="string">'job'</span>]);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">$this</span>->instance = <span class="keyword">$this</span>->resolve($class);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">$this</span>->instance->{$method}(<span class="keyword">$this</span>, <span class="keyword">$this</span>->resolveQueueableEntities($payload[<span class="string">'data'</span>]));</span><br><span class="line">}</span><br></pre></td></tr></table></figure>获取Illuminate\Events\CallQueuedHandler实例,执行该实例的call方法。并将data作为参数传入。<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="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">call</span><span class="params">(Job $job, array $data)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> $handler = <span class="keyword">$this</span>->setJobInstanceIfNecessary(</span><br><span class="line"> $job, <span class="keyword">$this</span>->container->make($data[<span class="string">'class'</span>])</span><br><span class="line"> );</span><br><span class="line"></span><br><span class="line"> call_user_func_array(</span><br><span class="line"> [$handler, $data[<span class="string">'method'</span>]], unserialize($data[<span class="string">'data'</span>])</span><br><span class="line"> );</span><br><span class="line"> <span class="comment">//清除队列数据</span></span><br><span class="line"> <span class="keyword">if</span> (! $job->isDeletedOrReleased()) {</span><br><span class="line"> $job->delete(); </span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>这里需要注意的一点是,清除队列中的该条任务,这里清除的实际是reversed有序队列中的备份任务,因为在生产环境中,由于程序错误导致任务无法正常进行是存在的,所以laravel会默认备份。</li></ul>]]></content>
<categories>
<category> laravel源码学习分享 </category>
</categories>
<tags>
<tag> artisan控制台 </tag>
<tag> queue:work命令 </tag>
</tags>
</entry>
<entry>
<title>Event-服务</title>
<link href="/event-provider.html"/>
<url>/event-provider.html</url>
<content type="html"><![CDATA[<div class="note success"><p>Event事件服务是框架中必要重要的一部分,其中也会用到Queue类,Broadcast类,这也是一种设计模式,叫观察者模式。</p></div><h5 id="Dispatcher"><a href="#Dispatcher" class="headerlink" title="Dispatcher"></a>Dispatcher</h5><p>通过EventProvider为容器注册一个’event’对应的Dispatcher类。通过容器make方法直接获取事件分配类。<font color="red">框架中有两个EventProvider,这两个作用是完全不一样的</font></p><ul><li><p>Illuminate\Events\EventServiceProvider,其注册是在Application的基本服务注册方法里</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">// Application, 在App类实例化时就已经注册了。</span></span><br><span class="line"><span class="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">registerBaseServiceProviders</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>->register(<span class="keyword">new</span> EventServiceProvider(<span class="keyword">$this</span>));</span><br><span class="line"></span><br><span class="line"> <span class="keyword">$this</span>->register(<span class="keyword">new</span> RoutingServiceProvider(<span class="keyword">$this</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">register</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>->app->singleton(<span class="string">'events'</span>, <span class="function"><span class="keyword">function</span> <span class="params">($app)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> (<span class="keyword">new</span> Dispatcher($app))->setQueueResolver(<span class="function"><span class="keyword">function</span> <span class="params">()</span> <span class="title">use</span> <span class="params">($app)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> $app->make(<span class="string">'Illuminate\Contracts\Queue\Factory'</span>);</span><br><span class="line"> });</span><br><span class="line"> });</span><br><span class="line">}</span><br></pre></td></tr></table></figure><a id="more"></a><p>可以看到,这里将event绑定为Dispatcher类,并同时为Dispatcher设置类一个获取Queue(队列)工厂类的闭包。我们框架中的event()实质就是用来处理具体事件的分配器Dispatcher类。</p></li><li><p>App\Providers\EventServiceProvider,在config/app配置的provider数组中注册。</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="comment">//继承</span></span><br><span class="line"><span class="keyword">use</span> <span class="title">Illuminate</span>\<span class="title">Foundation</span>\<span class="title">Support</span>\<span class="title">Providers</span>\<span class="title">EventServiceProvider</span> <span class="title">as</span> <span class="title">ServiceProvider</span>;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">EventServiceProvider</span> <span class="keyword">extends</span> <span class="title">ServiceProvider</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">protected</span> $listen = [</span><br><span class="line"> <span class="string">'App\Events\TestEvent'</span> => [</span><br><span class="line"> <span class="string">'App\Listeners\TestListener1@test'</span>,</span><br><span class="line"> <span class="string">'App\Listeners\TestListener2'</span></span><br><span class="line"> ],</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">boot</span><span class="params">(DispatcherContract $events)</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">parent</span>::boot($events);</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></pre></td></tr></table></figure><p>这个类是继承Support\Providers\EventServiceProvider类的,关注点在其boot方法中。在框架所有服务注册完毕,并准备启动是,就会执行所有服务的Boot方法。</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="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">boot</span><span class="params">(DispatcherContract $events)</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="keyword">$this</span>->listen <span class="keyword">as</span> $event => $listeners) {</span><br><span class="line"> <span class="keyword">foreach</span> ($listeners <span class="keyword">as</span> $listener) {</span><br><span class="line"> $events->listen($event, $listener);</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="keyword">foreach</span> (<span class="keyword">$this</span>->subscribe <span class="keyword">as</span> $subscriber) {</span><br><span class="line"> $events->subscribe($subscriber);</span><br><span class="line"> }</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>如上,在$listen数组中注册一个事件,并使用两个监听者。在执行boot方法时,使用循环遍历的方法,逐个将事件及其监听者传入Dispatcher的listen方法。假设我们当前的例子是不进队列,也不广播的,只走最简单的流程。</p></li></ul><h5 id="Dispatcher-listen"><a href="#Dispatcher-listen" class="headerlink" title="Dispatcher listen"></a>Dispatcher listen</h5><p>将$listen数组中的事件存入Dispatcher中的listeners属性中<br><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="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">listen</span><span class="params">($events, $listener, $priority = <span class="number">0</span>)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">foreach</span> ((<span class="keyword">array</span>) $events <span class="keyword">as</span> $event) {</span><br><span class="line"> <span class="comment">//如果含通配符</span></span><br><span class="line"> <span class="keyword">if</span> (Str::contains($event, <span class="string">'*'</span>)) {</span><br><span class="line"> <span class="keyword">$this</span>->setupWildcardListen($event, $listener);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">$this</span>->listeners[$event][$priority][] = <span class="keyword">$this</span>->makeListener($listener);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">unset</span>(<span class="keyword">$this</span>->sorted[$event]);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><br>含通配符的事件,存入wildcards数组中,这里主要说常用的。可以看到listeners中一个事件名对应的监听者是数组。按我们的例子就是<br><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="comment">//这里的0是事件优先级的排序,默认都为0</span></span><br><span class="line"><span class="keyword">$this</span>->listeners[<span class="string">'App\Events\TestEvent'</span>][<span class="number">0</span>] = [</span><br><span class="line"><span class="keyword">$this</span>->makeListener(<span class="string">'App\Listeners\TestListener1@test'</span>),</span><br><span class="line"><span class="keyword">$this</span>->makeListener(<span class="string">'App\Listeners\TestListener2'</span>)</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="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">createClassListener</span><span class="params">($listener)</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> $container = <span class="keyword">$this</span>->container;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="function"><span class="keyword">function</span> <span class="params">()</span> <span class="title">use</span> <span class="params">($listener, $container)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> call_user_func_array(</span><br><span class="line"> <span class="keyword">$this</span>->createClassCallable($listener, $container), func_get_args()</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="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">createClassCallable</span><span class="params">($listener, $container)</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">//首先进行字符串解析,App\Listeners\TestListener1@test对应</span></span><br><span class="line"> <span class="comment">//$class=App\Listeners\TestListener1 $method=test</span></span><br><span class="line"> <span class="keyword">list</span>($class, $method) = <span class="keyword">$this</span>->parseClassCallable($listener);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">$this</span>->handlerShouldBeQueued($class)) {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->createQueuedHandlerCallable($class, $method);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="comment">//$method默认是handler</span></span><br><span class="line"> <span class="keyword">return</span> [$container->make($class), $method];</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br></pre></td></tr></table></figure><br>makeListener方法会返回一个用来执行 对应Listener类上对应方法的闭包。简单点就是下图,只要当App\Events\TestEvent触发,则会执行这两个函数。<br><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="keyword">$this</span>->listeners[<span class="string">'App\Events\TestEvent'</span>][<span class="number">0</span>] = [</span><br><span class="line"><span class="function"><span class="keyword">function</span><span class="params">()</span></span>{</span><br><span class="line"><span class="keyword">new</span> App\Listeners\TestListener1 ->test();<span class="comment">//自定义的test方法</span></span><br><span class="line">},</span><br><span class="line"><span class="function"><span class="keyword">function</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">new</span> App\Listeners\TestListener2 ->handle(); <span class="comment">//默认方法</span></span><br><span class="line">}</span><br><span class="line">];</span><br></pre></td></tr></table></figure></p><h5 id="事件触发Fire"><a href="#事件触发Fire" class="headerlink" title="事件触发Fire"></a>事件触发Fire</h5><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">fire</span><span class="params">($event, $payload = [], $halt = false)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (is_object($event)) {</span><br><span class="line"> <span class="keyword">list</span>($payload, $event) = [[$event], get_class($event)];</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> $responses = [];</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (! is_array($payload)) {</span><br><span class="line"> $payload = [$payload];</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">$this</span>->firing[] = $event;</span><br><span class="line"></span><br><span class="line"> <span class="comment">//判断当前事件是否需要广播</span></span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">isset</span>($payload[<span class="number">0</span>]) && $payload[<span class="number">0</span>] <span class="keyword">instanceof</span> ShouldBroadcast) {</span><br><span class="line"> <span class="keyword">$this</span>->broadcastEvent($payload[<span class="number">0</span>]);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">foreach</span> (<span class="keyword">$this</span>->getListeners($event) <span class="keyword">as</span> $listener) {</span><br><span class="line"> $response = call_user_func_array($listener, $payload);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (! is_null($response) && $halt) {</span><br><span class="line"> array_pop(<span class="keyword">$this</span>->firing);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> $response;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> ($response === <span class="keyword">false</span>) {</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> $responses[] = $response;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> array_pop(<span class="keyword">$this</span>->firing);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> $halt ? <span class="keyword">null</span> : $responses;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>现在来手动进行事件触发,执行event()->(‘App\Events\TestEvent’),如果是否字符串,就直接执行$this->getListeners(),然后循环执行事件处理方法(test,handle)。如果参数是实例,event()->(new \App\Events\TestEvent),则会判断该实例是否需要广播,如果是,则会另外加入广播队列。</p>]]></content>
<categories>
<category> laravel源码学习分享 </category>
</categories>
<tags>
<tag> event服务 </tag>
<tag> eventDispatcher </tag>
</tags>
</entry>
<entry>
<title>middleware</title>
<link href="/middleware.html"/>
<url>/middleware.html</url>
<content type="html"><![CDATA[<div class="note success"><p>框架中,middleware的使用入口有3类,全局中间件 、 路由中间件 、控制器中间件 </p></div><h5 id="全局中间件"><a href="#全局中间件" class="headerlink" title="全局中间件"></a>全局中间件</h5><p> 全局使用在App\Http\Kernel下有中间件数组<br><figure class="highlight moonscript"><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><br><span class="line">protected $middleware = [</span><br><span class="line"> \Illuminate\Foundation\Http\Middleware\<span class="name">CheckForMaintenanceMode</span>::<span class="class"><span class="keyword">class</span>,</span></span><br><span class="line"> \App\Http\Middleware\EncryptCookies::<span class="class"><span class="keyword">class</span>,</span></span><br><span class="line"> \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::<span class="class"><span class="keyword">class</span>,</span></span><br><span class="line"> \Illuminate\Session\Middleware\StartSession::<span class="class"><span class="keyword">class</span>,</span></span><br><span class="line"> \Illuminate\View\Middleware\ShareErrorsFromSession::<span class="class"><span class="keyword">class</span>,</span></span><br><span class="line"> \App\Http\Middleware\VerifyCsrfToken::<span class="class"><span class="keyword">class</span>,</span></span><br><span class="line">];</span><br><span class="line"></span><br><span class="line">//路由中间件数组</span><br><span class="line">protected $routeMiddleware = [</span><br><span class="line"> <span class="string">'auth'</span> => \App\Http\Middleware\Authenticate::<span class="class"><span class="keyword">class</span>,</span></span><br><span class="line"> <span class="string">'auth.basic'</span> => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::<span class="class"><span class="keyword">class</span>,</span></span><br><span class="line"> <span class="string">'guest'</span> => \App\Http\Middleware\RedirectIfAuthenticated::<span class="class"><span class="keyword">class</span>,</span></span><br><span class="line">];</span><br></pre></td></tr></table></figure><br><a id="more"></a><br>在框架核心类kernel进行实例化时,会将route数组中的中间件存入Router类middleware属性中<br><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="comment">//Illuminate\Foundation\Http\Kernel</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">(Application $app, Router $router)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">$this</span>->app = $app;</span><br><span class="line"> <span class="keyword">$this</span>->router = $router;</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="keyword">$this</span>->routeMiddleware <span class="keyword">as</span> $key => $middleware) {</span><br><span class="line"> $router->middleware($key, $middleware);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="comment">//Illuminate\Routing\Router</span></span><br><span class="line"><span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">middleware</span><span class="params">($name, $class)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">$this</span>->middleware[$name] = $class;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><h5 id="全局中间件的使用"><a href="#全局中间件的使用" class="headerlink" title="全局中间件的使用"></a>全局中间件的使用</h5><p>在kernel类的管道中,全局中间件作为最外层的处理类<br><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="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">sendRequestThroughRouter</span><span class="params">($request)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="comment">// through方法里就是全局中间件的数组</span></span><br><span class="line"> <span class="keyword">return</span> (<span class="keyword">new</span> Pipeline(<span class="keyword">$this</span>->app))</span><br><span class="line"> ->send($request)</span><br><span class="line"> ->through(<span class="keyword">$this</span>->app->shouldSkipMiddleware() ? [] : <span class="keyword">$this</span>->middleware)</span><br><span class="line"> ->then(<span class="keyword">$this</span>->dispatchToRouter());</span><br><span class="line">}</span><br><span class="line"><span class="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">dispatchToRouter</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="function"><span class="keyword">function</span> <span class="params">($request)</span> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->app->instance(<span class="string">'request'</span>, $request);</span><br><span class="line"> <span class="comment">//执行路由分配</span></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->router->dispatch($request);</span><br><span class="line"> };</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><h5 id="路由中间件"><a href="#路由中间件" class="headerlink" title="路由中间件"></a>路由中间件</h5><p>举例 Route::get(‘/‘,‘IndexController@index’)->middleware(‘auth’)。这是直接在当前请求并配到的Route类上直接进行’auth’中间件绑定。执行上面的dispatch时则会用到’auth’。router类的dispatch方法最终又会经过另一pipeline处理<br><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="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">runRouteWithinStack</span><span class="params">(Route $route, Request $request)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line">...</span><br><span class="line"></span><br><span class="line"> $middleware = $shouldSkipMiddleware ? [] : <span class="keyword">$this</span>->gatherRouteMiddlewares($route);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> (<span class="keyword">new</span> Pipeline(<span class="keyword">$this</span>->container))</span><br><span class="line"> ->send($request)</span><br><span class="line"> ->through($middleware)</span><br><span class="line"> ->then(<span class="function"><span class="keyword">function</span> <span class="params">($request)</span> <span class="title">use</span> <span class="params">($route)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->prepareResponse(</span><br><span class="line"> $request,</span><br><span class="line"> $route->run($request)</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="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">gatherRouteMiddlewares</span><span class="params">(Route $route)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">return</span> Collection::make($route->middleware())->map(<span class="function"><span class="keyword">function</span> <span class="params">($name)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> Collection::make(<span class="keyword">$this</span>->resolveMiddlewareClassName($name));</span><br><span class="line"> })</span><br><span class="line"> ->collapse()->all();</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">resolveMiddlewareClassName</span><span class="params">($name)</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> $map = <span class="keyword">$this</span>->middleware;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">list</span>($name, $parameters) = array_pad(explode(<span class="string">':'</span>, $name, <span class="number">2</span>), <span class="number">2</span>, <span class="keyword">null</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> (<span class="keyword">isset</span>($map[$name]) ? $map[$name] : $name).($parameters !== <span class="keyword">null</span> ? <span class="string">':'</span>.$parameters : <span class="string">''</span>);</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><br>首先会获取路由中定义的全部中间件,然后进行逐一解析。比如定义middleware(‘auth’)中间件,最终会根据kernel中$routeMiddleware数组下标解析成下面的字符串<br><figure class="highlight taggerscript"><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><br><span class="line">'<span class="symbol">\A</span>pp<span class="symbol">\H</span>ttp<span class="symbol">\M</span>iddleware<span class="symbol">\A</span>uthenticate'</span><br><span class="line">//如果定义middleware('auth:1,2,3'),最终解析</span><br><span class="line">'<span class="symbol">\A</span>pp<span class="symbol">\H</span>ttp<span class="symbol">\M</span>iddleware<span class="symbol">\A</span>uthenticate:1,2,3'</span><br></pre></td></tr></table></figure><br>在经过Pipeline 的then方法时,会进行中间件字符串解析。看then方法中的getSlice方法<br><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="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">getSlice</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">list</span>($name, $parameters) = <span class="keyword">$this</span>->parsePipeString($pipe);</span><br><span class="line"><span class="comment">//解析后$name = '\App\Http\Middleware\Authenticate'</span></span><br><span class="line"><span class="comment">// $parameters = [1,2,3]</span></span><br><span class="line"> <span class="keyword">return</span> call_user_func_array([<span class="keyword">$this</span>->container->make($name), <span class="keyword">$this</span>->method],</span><br><span class="line"> array_merge([$passable, $stack], $parameters));</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//$pipe 便是字符串 '\App\Http\Middleware\Authenticate:1,2,3'</span></span><br><span class="line"> <span class="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">parsePipeString</span><span class="params">($pipe)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">list</span>($name, $parameters) = array_pad(explode(<span class="string">':'</span>, $pipe, <span class="number">2</span>), <span class="number">2</span>, []);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (is_string($parameters)) {</span><br><span class="line"> $parameters = explode(<span class="string">','</span>, $parameters);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> [$name, $parameters];</span><br><span class="line">}</span><br></pre></td></tr></table></figure><br>最终结果就是 通过容器make($name),也就是获取中间件实例,然后执行其handle方法,传入参数分别为(request, next, parameters)</p><h5 id="控制器的中间件"><a href="#控制器的中间件" class="headerlink" title="控制器的中间件"></a>控制器的中间件</h5><p>这类中间件的是在控制器的构造函数中添加,但其却是在路由管道的最内层方法 $route->run($request)被使用到<br><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 class="comment">//如 IndexController</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="keyword">$this</span>->middleware(<span class="string">'auth'</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//Illuminate\Routing\Route</span></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">run</span><span class="params">(Request $request)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">$this</span>->container = <span class="keyword">$this</span>->container ?: <span class="keyword">new</span> Container;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">if</span> (! is_string(<span class="keyword">$this</span>->action[<span class="string">'uses'</span>])) {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->runCallable($request);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">$this</span>->customDispatcherIsBound()) {</span><br><span class="line"> <span class="comment">//这里便是控制器中间件的pipeline处理</span></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->runWithCustomDispatcher($request);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->runController($request);</span><br><span class="line"> } <span class="keyword">catch</span> (HttpResponseException $e) {</span><br><span class="line"> <span class="keyword">return</span> $e->getResponse();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><br>控制器的中间件处理与上面一样,同样是通过管道处理,但是注意点在于customDispatcherIsBound()方法,判断容器中是否存在下面这样一个绑定,也就是在下面第二个方法中要用到的make(‘….’)。<br><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="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">customDispatcherIsBound</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{ </span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->container->bound(<span class="string">'illuminate.route.dispatcher'</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">runWithCustomDispatcher</span><span class="params">(Request $request)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">list</span>($class, $method) = explode(<span class="string">'@'</span>, <span class="keyword">$this</span>->action[<span class="string">'uses'</span>]);</span><br><span class="line"></span><br><span class="line"> $dispatcher = <span class="keyword">$this</span>->container->make(<span class="string">'illuminate.route.dispatcher'</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> $dispatcher->dispatch(<span class="keyword">$this</span>, $request, $class, $method);</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>illuminate.route.dispatcher的绑定位置,在config/app.php的provides数组里<br><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="comment">//config/app.php</span></span><br><span class="line"><span class="string">'providers'</span> => [</span><br><span class="line">....</span><br><span class="line"> Illuminate\Routing\ControllerServiceProvider::class,</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="class"><span class="keyword">class</span> <span class="title">ControllerServiceProvider</span> <span class="keyword">extends</span> <span class="title">ServiceProvider</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">register</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>->app->singleton(<span class="string">'illuminate.route.dispatcher'</span>, <span class="function"><span class="keyword">function</span> <span class="params">($app)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> ControllerDispatcher($app[<span class="string">'router'</span>], $app);</span><br><span class="line"> });</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><br>简单点说就是,如果把这里的服务注释掉,那么在控制器中写入中间的是无效的。</p>]]></content>
<categories>
<category> laravel源码学习分享 </category>
</categories>
<tags>
<tag> 中间件 </tag>
</tags>
</entry>
<entry>
<title>Session</title>
<link href="/session.html"/>
<url>/session.html</url>
<content type="html"><![CDATA[<p>laravel框架的session 是自定义类, 整个框架没有使用php自带的session_start等方法。</p><h4 id="session-start"><a href="#session-start" class="headerlink" title="session start"></a>session start</h4><p>在Illuminate\Session\Middleware\StartSession中间件中,自定义了session 启动的方法<br><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="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">handle</span><span class="params">($request, Closure $next)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">$this</span>->sessionHandled = <span class="keyword">true</span>;</span><br><span class="line"> <span class="comment">//判断config/session.php中的配置是否存在</span></span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">$this</span>->sessionConfigured()) {</span><br><span class="line"> $session = <span class="keyword">$this</span>->startSession($request);</span><br><span class="line"></span><br><span class="line"> $request->setSession($session);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> $response = $next($request);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">$this</span>->sessionConfigured()) {</span><br><span class="line"> <span class="keyword">$this</span>->storeCurrentUrl($request, $session);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">$this</span>->collectGarbage($session);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">$this</span>->addCookieToResponse($response, $session);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> $response;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><br><a id="more"></a><br>在request 请求进来时,判断config/session.php中的配置是否存在。存在,创建自定义session。<br>① 根据配置获取对应的驱动,默认是通过文件缓存来存储session_id<br>②从request中获取laravel_session对应的cookie,并解析得到session_id<br>③为$session存储类即Store类的id属性设置值, setId方法里如果请求中的session_id值不存在,则会重新生成</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="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">startSession</span><span class="params">(Request $request)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> with($session = <span class="keyword">$this</span>->getSession($request))->setRequestOnHandler($request);</span><br><span class="line"></span><br><span class="line"> $session->start();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> $session;</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">getSession</span><span class="params">(Request $request)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"></span><br><span class="line"> $session = <span class="keyword">$this</span>->manager->driver();</span><br><span class="line"></span><br><span class="line"> $session->setId($request->cookies->get($session->getName()));</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> $session;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>④$session->start(),从Store中读取session数据。根据不同的Hander,默认是通过文件读取(Filesystem)进行数据获取</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 class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">start</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>->loadSession();</span><br><span class="line"> <span class="comment">//_token文件不存在,则重新生成_token,并存入sessin中</span></span><br><span class="line"> <span class="keyword">if</span> (! <span class="keyword">$this</span>->has(<span class="string">'_token'</span>)) {</span><br><span class="line"> <span class="keyword">$this</span>->regenerateToken();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->started = <span class="keyword">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"> * Load the session data from the handler.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> void</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">loadSession</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>->attributes = array_merge(<span class="keyword">$this</span>->attributes, <span class="keyword">$this</span>->readFromHandler());</span><br><span class="line"></span><br><span class="line"> <span class="keyword">foreach</span> (array_merge(<span class="keyword">$this</span>->bags, [<span class="keyword">$this</span>->metaBag]) <span class="keyword">as</span> $bag) {</span><br><span class="line"> <span class="keyword">$this</span>->initializeLocalBag($bag);</span><br><span class="line"></span><br><span class="line"> $bag->initialize(<span class="keyword">$this</span>->bagData[$bag->getStorageKey()]);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>⑥ 响应获取后,将当前url添加至session中,然后随机回收清除过期session数据,最后将当前session_id添加至响应头,下次请求便根据session_id,读取storage/framework/sessions下面对应文件中存储的session数据<br><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="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">addCookieToResponse</span><span class="params">(Response $response, SessionInterface $session)</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>->usingCookieSessions()) {</span><br><span class="line"> <span class="keyword">$this</span>->manager->driver()->save();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">$this</span>->sessionIsPersistent($config = <span class="keyword">$this</span>->manager->getSessionConfig())) {</span><br><span class="line"> $response->headers->setCookie(<span class="keyword">new</span> Cookie(</span><br><span class="line"> $session->getName(), $session->getId(), <span class="keyword">$this</span>->getCookieExpirationDate(),</span><br><span class="line"> $config[<span class="string">'path'</span>], $config[<span class="string">'domain'</span>], Arr::get($config, <span class="string">'secure'</span>, <span class="keyword">false</span>)</span><br><span class="line"> ));</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>]]></content>
<categories>
<category> laravel源码学习分享 </category>
</categories>
<tags>
<tag> middleware </tag>
<tag> session </tag>
</tags>
</entry>
<entry>
<title>FormRequest类</title>
<link href="/formrequest.html"/>
<url>/formrequest.html</url>
<content type="html"><![CDATA[<p>探究request请求中,表单自动验证的实现原理。<br>①任意建一个控制器,如IndexController,添加index方法</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="keyword">namespace</span> <span class="title">App</span>\<span class="title">Http</span>\<span class="title">Controllers</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">use</span> <span class="title">App</span>\<span class="title">Http</span>\<span class="title">Requests</span>\<span class="title">IndexRequest</span>;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">IndexController</span> <span class="keyword">extends</span> <span class="title">Controller</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"><span class="comment">//通过依赖注入进行InputRequest类的实例化</span></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">index</span><span class="params">(IndexRequest $request)</span></span></span><br><span class="line"><span class="function"> </span>{ </span><br><span class="line"> dump($request);</span><br><span class="line"> <span class="comment">// echo 123;</span></span><br><span class="line"> } </span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>@任意建一个继承了FormRequest类的类,如IndexRequest<br><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="keyword">namespace</span> <span class="title">App</span>\<span class="title">Http</span>\<span class="title">Requests</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">use</span> <span class="title">Illuminate</span>\<span class="title">Foundation</span>\<span class="title">Http</span>\<span class="title">FormRequest</span>;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">IndexRequest</span> <span class="keyword">extends</span> <span class="title">FormRequest</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"><span class="comment">// public $redirect = '/home';</span></span><br><span class="line"><span class="comment">// public $redirectAction = 'IndexController@test';</span></span><br><span class="line"><span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">authorize</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">true</span>;</span><br><span class="line">}</span><br><span class="line"> <span class="comment">//这里请求参数id 是必须的</span></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">rules</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><br><span class="line"> <span class="string">'id'</span> => <span class="string">'required'</span></span><br><span class="line"> ];</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><br><a id="more"></a></p><h5 id="如何自动验证"><a href="#如何自动验证" class="headerlink" title="如何自动验证"></a>如何自动验证</h5><p>在IndexController中依赖注入,说白了就是通过容器make()方法获取实例,那么验证又是在哪里,以怎样的方式触发的呢<br>在框架config的app.php 中有很多服务注册,这里主要用到的一个服务就是</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="comment">//app.php</span></span><br><span class="line">...</span><br><span class="line">Illuminate\Validation\ValidationServiceProvider::class,</span><br><span class="line">...</span><br><span class="line"></span><br><span class="line"><span class="comment">//ValidationServiceProvider</span></span><br><span class="line"><span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">register</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>->registerValidationResolverHook();</span><br><span class="line"> ....</span><br><span class="line">}</span><br><span class="line"> <span class="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">registerValidationResolverHook</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>->app->afterResolving(<span class="function"><span class="keyword">function</span> <span class="params">(ValidatesWhenResolved $resolved)</span> </span>{</span><br><span class="line"> $resolved->validate();</span><br><span class="line"> });</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>这里注册了一个全局的afterResolving 回调,看一下afterResolving都做了什么<br><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="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">afterResolving</span><span class="params">($abstract, Closure $callback = null)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> ($abstract <span class="keyword">instanceof</span> Closure && $callback === <span class="keyword">null</span>) {</span><br><span class="line"> <span class="keyword">$this</span>->afterResolvingCallback($abstract);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">$this</span>->afterResolvingCallbacks[$abstract][] = $callback;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">resolvingCallback</span><span class="params">(Closure $callback)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="comment">//这里的abstract就是类的全名</span></span><br><span class="line"><span class="comment">//Illuminate\Contracts\Validation\ValidatesWhenResolved</span></span><br><span class="line"> $abstract = <span class="keyword">$this</span>->getFunctionHint($callback);</span><br><span class="line"> <span class="keyword">if</span> ($abstract) {</span><br><span class="line"> <span class="keyword">$this</span>->resolvingCallbacks[$abstract][] = $callback;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">$this</span>->globalResolvingCallbacks[] = $callback;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>可以看到 为app类的resolvingCallbacks数组中添加了一个ValidatesWhenResolved指向的闭包,也就是上面的<br>function (ValidatesWhenResolved $resolved) { $resolved->validate(); }</p><h5 id="验证触发"><a href="#验证触发" class="headerlink" title="验证触发"></a>验证触发</h5><p>真正的验证是在 Container类执行make(‘\App\Http\Requests\IndexRequest’)时触发的。</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></pre></td><td class="code"><pre><span class="line"><span class="comment">//容器的make方法</span></span><br><span class="line">...</span><br><span class="line"><span class="keyword">$this</span>->fireResolvingCallbacks($abstract, $object);</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="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">fireResolvingCallbacks</span><span class="params">($abstract, $object)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">$this</span>->fireCallbackArray(</span><br><span class="line"> $object, <span class="keyword">$this</span>->getCallbacksForType(</span><br><span class="line"> <span class="comment">//获取afterresolving回调</span></span><br><span class="line"> $abstract, $object, <span class="keyword">$this</span>->afterResolvingCallbacks</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="comment">//为所有的回调函数传入当前Object(这里便是InputRequest) 和 app实例</span></span><br><span class="line"><span class="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">fireCallbackArray</span><span class="params">($object, array $callbacks)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">foreach</span> ($callbacks <span class="keyword">as</span> $callback) {</span><br><span class="line"> $callback($object, <span class="keyword">$this</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>容器在make 任意类时都去获取全局的afterResolvingCallbacks,但是会根据指定类型进行回调,其他则直接过滤。下面这个方法则会获取当前make类对应的回调。<br>当$type恒等于 $abstract 或者 $object instanceof $type,<br>在当前例子下便是<br>‘App\Http\Requests\IndexRequest’ === ‘Illuminate\Contracts\Validation\ValidatesWhenResolved’ 不成立<br>Object(App\Http\Requests\IndexRequest) instanceof Object(ValidatesWhenResolved) 成立<br>因为InputRequest是继承FormRquest的,FormRquest又实现ValidatesWhenResolved接口</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="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">getCallbacksForType</span><span class="params">($abstract, $object, array $callbacksPerType)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> $results = [];</span><br><span class="line"></span><br><span class="line"> <span class="keyword">foreach</span> ($callbacksPerType <span class="keyword">as</span> $type => $callbacks) {</span><br><span class="line"> <span class="keyword">if</span> ($type === $abstract || $object <span class="keyword">instanceof</span> $type) {</span><br><span class="line"> $results = array_merge($results, $callbacks);</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> $results;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>以上代码都执行完毕后,最终的执行代码就是 InputRequest->validate()。进而执行FormRequest中Trait类的validate方法。接下来便是最基本的验证流程了<br><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">// FormRequest 类</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">FormRequest</span> <span class="keyword">extends</span> <span class="title">Request</span> <span class="keyword">implements</span> <span class="title">ValidatesWhenResolved</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">use</span> <span class="title">ValidatesWhenResolvedTrait</span>;</span><br><span class="line">}</span><br><span class="line"><span class="comment">// </span></span><br><span class="line"><span class="keyword">trait</span> ValidatesWhenResolvedTrait</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">validate</span><span class="params">()</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> $instance = <span class="keyword">$this</span>->getValidatorInstance();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (! <span class="keyword">$this</span>->passesAuthorization()) {</span><br><span class="line"> <span class="keyword">$this</span>->failedAuthorization();</span><br><span class="line"> } <span class="keyword">elseif</span> (! $instance->passes()) {</span><br><span class="line"> <span class="keyword">$this</span>->failedValidation($instance);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><h5 id="FromRequest获取"><a href="#FromRequest获取" class="headerlink" title="FromRequest获取"></a>FromRequest获取</h5><p>首先这个FromRequest类有对应的服务提供者,在config/app.php 的 providers数组中<br><figure class="highlight clean"><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="string">'providers'</span> => [</span><br><span class="line"> ...</span><br><span class="line"> Illuminate\Foundation\Providers\FoundationServiceProvider::<span class="keyword">class</span>,</span><br><span class="line">...</span><br><span class="line">]</span><br></pre></td></tr></table></figure><br>然后在FoundationServiceProvider的provides中存在<br><figure class="highlight scala"><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="class"><span class="keyword">class</span> <span class="title">FoundationServiceProvider</span> <span class="keyword">extends</span> <span class="title">AggregateServiceProvider</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">protected</span> $providers = [</span><br><span class="line"> <span class="type">FormRequestServiceProvider</span>::<span class="class"><span class="keyword">class</span>,</span></span><br><span class="line"><span class="class"> ]</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><br>在框架的bootstrap过程中,所有的服务都会进行一一注册。接下开便是register</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="comment">// AggregateServiceProvider </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">register</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>->instances = [];</span><br><span class="line"></span><br><span class="line"> <span class="keyword">foreach</span> (<span class="keyword">$this</span>->providers <span class="keyword">as</span> $provider) {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">$this</span>->instances[] = <span class="keyword">$this</span>->app->register($provider);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><h5 id="FormRequest与Request"><a href="#FormRequest与Request" class="headerlink" title="FormRequest与Request"></a>FormRequest与Request</h5><p>所有请求参数最开始实际都是只存在Request类中,但是IndexController中的InputRequest类有其所有数据。底层实现原理与上面验证比较类似。<br>当所有服务注册完毕,逐个执行其boot方法,为项目启动做准备时, 这里就注册了一个router.matched的事件监听者,也就是当请求url匹配到存在路由时,触发回调。<br><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="comment">//FormRequestServiceProvider</span></span><br><span class="line"><span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">boot</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>->app[<span class="string">'events'</span>]->listen(<span class="string">'router.matched'</span>, <span class="function"><span class="keyword">function</span> <span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->app->resolving(<span class="function"><span class="keyword">function</span> <span class="params">(FormRequest $request, $app)</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">$this</span>->initializeRequest($request, $app[<span class="string">'request'</span>]);</span><br><span class="line"></span><br><span class="line"> $request->setContainer($app)->setRedirector($app->make(Redirector::class));</span><br><span class="line"> });</span><br><span class="line"> });</span><br><span class="line">}</span><br><span class="line"><span class="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">initializeRequest</span><span class="params">(FormRequest $form, Request $current)</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> $files = $current->files->all();</span><br><span class="line"></span><br><span class="line"> $files = is_array($files) ? array_filter($files) : $files;</span><br><span class="line"></span><br><span class="line"> $form->initialize(</span><br><span class="line"> $current->query->all(), $current->request->all(), $current->attributes->all(),</span><br><span class="line"> $current->cookies->all(), $files, $current->server->all(), $current->getContent()</span><br><span class="line"> );</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">if</span> ($session = $current->getSession()) {</span><br><span class="line"> $form->setSession($session);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> $form->setUserResolver($current->getUserResolver());</span><br><span class="line"></span><br><span class="line"> $form->setRouteResolver($current->getRouteResolver());</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><br>这个回调的最终目的就是 将原Request类中的所有属性为InputRequest复制一份。包括设置获取user及route的回调,如 基本写法request()->user(), 通过依赖注入后$inputrequest->user() 也可实现该效果.</p>]]></content>
<categories>
<category> laravel源码学习分享 </category>
</categories>
<tags>
<tag> FormReuqest </tag>
</tags>
</entry>
<entry>
<title>Auth 用户认证</title>
<link href="/auth.html"/>
<url>/auth.html</url>
<content type="html"><![CDATA[<p>  laravel Auth认证,自带登录,注册,api认证(高版本才有)等方式。</p><h4 id="auth基本配置"><a href="#auth基本配置" class="headerlink" title="auth基本配置"></a>auth基本配置</h4><p>用户认证的基本配置是config/auth.php 文件<br><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="string">'driver'</span> => <span class="string">'eloquent'</span>, <span class="comment">// 数据库驱动,eloquent 或 database</span></span><br><span class="line"><span class="string">'model'</span> => App\User::class, <span class="comment">// 默认用户认证模型</span></span><br><span class="line"><span class="string">'table'</span> => <span class="string">'users'</span>, <span class="comment">// 默认表名</span></span><br><span class="line"><span class="string">'password'</span> => [ <span class="comment">// 忘记密码配置</span></span><br><span class="line"> <span class="string">'email'</span> => <span class="string">'emails.password'</span>,</span><br><span class="line"> <span class="string">'table'</span> => <span class="string">'password_resets'</span>,</span><br><span class="line"> <span class="string">'expire'</span> => <span class="number">60</span>,</span><br><span class="line"> ],</span><br></pre></td></tr></table></figure></p><h4 id="auth服务提供者"><a href="#auth服务提供者" class="headerlink" title="auth服务提供者"></a>auth服务提供者</h4><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="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">register</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>->registerAuthenticator(); <span class="comment">// 注册用户认证者</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">// 为已认证的用户,注册一个可以直接获取user信息的闭包</span></span><br><span class="line"> </span><br><span class="line"> <span class="keyword">$this</span>->registerUserResolver(); </span><br><span class="line"> <span class="comment">//操作方法权限控制</span></span><br><span class="line"> <span class="keyword">$this</span>->registerAccessGate();</span><br><span class="line"></span><br><span class="line"> <span class="comment">//为request 重新绑定可以获取user的闭包</span></span><br><span class="line"> <span class="comment">//登录之后,在任何request请求中,直接使用request()->user()即可获取</span></span><br><span class="line"> <span class="keyword">$this</span>->registerRequestRebindHandler();</span><br><span class="line">}</span><br></pre></td></tr></table></figure><a id="more"></a><h5 id="registerAuthenticator"><a href="#registerAuthenticator" class="headerlink" title="registerAuthenticator"></a>registerAuthenticator</h5><p>①注册auth对应的单一绑定,最终返回 AuthManager类<br>②注册auth.drive 的驱动操作绑定<br><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="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">registerAuthenticator</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>->app->singleton(<span class="string">'auth'</span>, <span class="function"><span class="keyword">function</span> <span class="params">($app)</span> </span>{</span><br><span class="line"></span><br><span class="line"> $app[<span class="string">'auth.loaded'</span>] = <span class="keyword">true</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> AuthManager($app);</span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> <span class="keyword">$this</span>->app->singleton(<span class="string">'auth.driver'</span>, <span class="function"><span class="keyword">function</span> <span class="params">($app)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> $app[<span class="string">'auth'</span>]->driver();</span><br><span class="line"> });</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>举例语法 Auth::user()<br>首先 通过Auth门面的静态调用方法获取AuthManager类( 设为 $authmanager)<br>然后 执行$authmanager->user();<br><figure class="highlight scala"><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="class"><span class="keyword">class</span> <span class="title">AuthManager</span> <span class="keyword">extends</span> <span class="title">Manager</span> <span class="title">//</span> <span class="title">继承了Manager</span> </span></span><br><span class="line"><span class="class">....</span></span><br><span class="line"><span class="class"><span class="title">//Manager基类的__call</span> <span class="title">方法</span></span></span><br><span class="line"><span class="class"><span class="title">public</span> <span class="title">function</span> <span class="title">__call</span>(<span class="params">$method, $parameters</span>)</span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">return</span> call_user_func_array([$<span class="keyword">this</span>->driver(), $method], $parameters);</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>第二步调用了魔术方法,实际执行是 根据配置driver 创建对应驱动。先获取到$provider ,并传入Guard类作为其属性<br><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="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">createEloquentDriver</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> $provider = <span class="keyword">$this</span>->createEloquentProvider();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> Guard($provider, <span class="keyword">$this</span>->app[<span class="string">'session.store'</span>]);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 获取对应的User模型, 可以最直观的理解为PDO连接句柄</span></span><br><span class="line"><span class="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">createEloquentProvider</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> $model = <span class="keyword">$this</span>->app[<span class="string">'config'</span>][<span class="string">'auth.model'</span>];</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> EloquentUserProvider(<span class="keyword">$this</span>->app[<span class="string">'hash'</span>], $model);</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>最终执行的是 new Guard ->user();<br><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="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">user</span><span class="params">()</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>->loggedOut) {</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//多次使用Auth::user(),直接返回</span></span><br><span class="line"> <span class="keyword">if</span> (! is_null(<span class="keyword">$this</span>->user)) {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->user;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 根据session_id 获取session。从而获取登录之后</span></span><br><span class="line"> <span class="comment">//用户表的主键id,</span></span><br><span class="line"> $id = <span class="keyword">$this</span>->session->get(<span class="keyword">$this</span>->getName());</span><br><span class="line"></span><br><span class="line"> $user = <span class="keyword">null</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (! is_null($id)) {</span><br><span class="line"> <span class="comment">// 如果id 存在,通过User::find($id),获取用户信息</span></span><br><span class="line"> $user = <span class="keyword">$this</span>->provider->retrieveById($id);</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//recaller 用于 remember_token 的使用</span></span><br><span class="line"> $recaller = <span class="keyword">$this</span>->getRecaller();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (is_null($user) && ! is_null($recaller)) {</span><br><span class="line"> $user = <span class="keyword">$this</span>->getUserByRecaller($recaller);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> ($user) {</span><br><span class="line"> <span class="keyword">$this</span>->updateSession($user->getAuthIdentifier());</span><br><span class="line"></span><br><span class="line"> <span class="keyword">$this</span>->fireLoginEvent($user, <span class="keyword">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="keyword">return</span> <span class="keyword">$this</span>->user = $user;</span><br><span class="line"> }</span><br></pre></td></tr></table></figure></p><h4 id="登录"><a href="#登录" class="headerlink" title="登录"></a>登录</h4><p>使用AuthenticatesAndRegistersUsers(Trait类),方便复用和方法重新<br><figure class="highlight rust"><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">//AuthController</span></span><br><span class="line"> <span class="keyword">use</span> AuthenticatesAndRegistersUsers, ThrottlesLogins;</span><br><span class="line"></span><br><span class="line"><span class="comment">//AuthenticatesAndRegistersUsers</span></span><br><span class="line"><span class="class"><span class="keyword">trait</span> <span class="title">AuthenticatesAndRegistersUsers</span></span></span><br><span class="line">{</span><br><span class="line"> <span class="keyword">use</span> AuthenticatesUsers, RegistersUsers {</span><br><span class="line"> <span class="comment">//trait 方法冲突解决</span></span><br><span class="line"> AuthenticatesUsers::redirectPath insteadof RegistersUsers; </span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>ThrottlesLogins类进行登录次数尝试的现在<br>在AuthenticatesUsers定义登录方法,在RegistersUsers定义注册方法<br><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">postLogin</span><span class="params">(Request $request)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">$this</span>->validate($request, [</span><br><span class="line"> <span class="keyword">$this</span>->loginUsername() => <span class="string">'required'</span>, <span class="string">'password'</span> => <span class="string">'required'</span>,</span><br><span class="line"> ]);</span><br><span class="line"></span><br><span class="line"> $throttles = <span class="keyword">$this</span>->isUsingThrottlesLoginsTrait();</span><br><span class="line"> <span class="comment">// 如果有使用throttles,检查是否尝试登录次数过多</span></span><br><span class="line"> <span class="keyword">if</span> ($throttles && <span class="keyword">$this</span>->hasTooManyLoginAttempts($request)) {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->sendLockoutResponse($request);</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 从请求数据里获取username 和 password 组成的数组</span></span><br><span class="line"> $credentials = <span class="keyword">$this</span>->getCredentials($request);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (Auth::attempt($credentials, $request->has(<span class="string">'remember'</span>))) {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->handleUserWasAuthenticated($request, $throttles);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> ($throttles) {</span><br><span class="line"> <span class="comment">//登录失败,增加尝试次数</span></span><br><span class="line"> <span class="keyword">$this</span>->incrementLoginAttempts($request);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> redirect(<span class="keyword">$this</span>->loginPath())</span><br><span class="line"> ->withInput($request->only(<span class="keyword">$this</span>->loginUsername(), <span class="string">'remember'</span>))</span><br><span class="line"> ->withErrors([</span><br><span class="line"> <span class="keyword">$this</span>->loginUsername() => <span class="keyword">$this</span>->getFailedLoginMessage(),</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="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">handleUserWasAuthenticated</span><span class="params">(Request $request, $throttles)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> ($throttles) {</span><br><span class="line"> <span class="comment">//登录成功,清空尝试次数</span></span><br><span class="line"> <span class="keyword">$this</span>->clearLoginAttempts($request);</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 用户认证通过后,自定义方法</span></span><br><span class="line"> <span class="keyword">if</span> (method_exists(<span class="keyword">$this</span>, <span class="string">'authenticated'</span>)) {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->authenticated($request, Auth::user());</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 通过 $path = $this->session->pull('url.intended', $default);</span></span><br><span class="line"> <span class="comment">// 最终登录成功跳转</span></span><br><span class="line"> <span class="keyword">return</span> redirect()->intended(<span class="keyword">$this</span>->redirectPath());</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>真正的用户登录数据的校验<br><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="comment">// 数据校验</span></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">attempt</span><span class="params">(array $credentials = [], $remember = false, $login = true)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">$this</span>->fireAttemptEvent($credentials, $remember, $login);</span><br><span class="line"> <span class="comment">// 通过$credentials中所有字段(不含password字段)值在user表中进行查询</span></span><br><span class="line"> <span class="keyword">$this</span>->lastAttempted = $user = <span class="keyword">$this</span>->provider->retrieveByCredentials($credentials);</span><br><span class="line"> <span class="comment">//将查询到的user信息中的密码与 提交的密码进行哈希比对</span></span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">$this</span>->hasValidCredentials($user, $credentials)) {</span><br><span class="line"> <span class="keyword">if</span> ($login) {</span><br><span class="line"> <span class="keyword">$this</span>->login($user, $remember);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">false</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">login</span><span class="params">(UserContract $user, $remember = false)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="comment">//更新session , 参数是user表主键值</span></span><br><span class="line"> <span class="keyword">$this</span>->updateSession($user->getAuthIdentifier());</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> ($remember) {</span><br><span class="line"> <span class="comment">//创建remember_token值,并写入user表对应的字段里</span></span><br><span class="line"> <span class="keyword">$this</span>->createRememberTokenIfDoesntExist($user);</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">$this</span>->queueRecallerCookie($user);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// If we have an event dispatcher instance set we will fire an event so that</span></span><br><span class="line"> <span class="comment">// any listeners will hook into the authentication events and run actions</span></span><br><span class="line"> <span class="comment">// based on the login and logout events fired from the guard instances.</span></span><br><span class="line"> <span class="keyword">$this</span>->fireLoginEvent($user, $remember);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">$this</span>->setUser($user);</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>重点看下 <font color="red">$this->queueRecallerCookie($user);</font> 这里会把remember_token 存入CookieJar的队列属性中,在kernel的中间件AddQueuedCookiesToResponse里会为响应头添加缓存,除非清楚浏览器缓存,否则一直存在(因为默认是以forever方式存储的).</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="comment">// AddQueuedCookiesToResponse 中间件</span></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">($request, Closure $next)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> $response = $next($request);</span><br><span class="line"></span><br><span class="line"> <span class="comment">//此时响应数据已拿到,只需为reponse头设置cookie 信息</span></span><br><span class="line"> <span class="keyword">foreach</span> (<span class="keyword">$this</span>->cookies->getQueuedCookies() <span class="keyword">as</span> $cookie) {</span><br><span class="line"> $response->headers->setCookie($cookie);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> $response;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category> laravel源码学习分享 </category>
</categories>
<tags>
<tag> 用户认证 </tag>
<tag> Auth </tag>
</tags>
</entry>
<entry>
<title>registerProvider</title>
<link href="/registerProvider.html"/>
<url>/registerProvider.html</url>
<content type="html"><![CDATA[<div class="note success"><p>框架bootstrap过程之 registerProvider。这里包括即时注册、延时注册、和事件注册服务。</p></div><p>为所有已存在的服务提供者进行统一注册<br><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">//Illuminate\Foundation\Bootstrap\RegisterProviders</span></span><br><span class="line"><span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">bootstrap</span><span class="params">(Application $app)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> $app->registerConfiguredProviders();</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// Illuminate\Foundation\Application</span></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">registerConfiguredProviders</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> $manifestPath = <span class="keyword">$this</span>->getCachedServicesPath();</span><br><span class="line"></span><br><span class="line"> (<span class="keyword">new</span> ProviderRepository(<span class="keyword">$this</span>, <span class="keyword">new</span> Filesystem, $manifestPath))</span><br><span class="line"> ->load(<span class="keyword">$this</span>->config[<span class="string">'app.providers'</span>]);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><br>首先获取需要注册的服务提供者的清单, 先读取服务提供者清单缓存,文件是位于root/bootstrap/cache下的services.json。<br> providers保存所有需要注册的服务(config/app.php里的providers)<br> eager保存即时注册的服务<br> deferred保存需要延时注册服务<br> when 保存需要条件才注册的服务<br><a id="more"></a><br><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="attr">"providers"</span>: [ ],</span><br><span class="line"> <span class="attr">"eager"</span>: [],</span><br><span class="line"> <span class="attr">"deferred"</span>: [],</span><br><span class="line"> <span class="attr">"when"</span>: [],</span><br><span class="line">}</span><br></pre></td></tr></table></figure><br>ProviderRepository作为保存服务提供者的仓库类,接收了三个参数 app实例, 文件操作类实例, providers缓存清单。<br><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="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">load</span><span class="params">(array $providers)</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> $manifest = <span class="keyword">$this</span>->loadManifest();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">$this</span>->shouldRecompile($manifest, $providers)) {</span><br><span class="line"> $manifest = <span class="keyword">$this</span>->compileManifest($providers);</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//读取when 数组</span></span><br><span class="line"> <span class="keyword">foreach</span> ($manifest[<span class="string">'when'</span>] <span class="keyword">as</span> $provider => $events) {</span><br><span class="line"> <span class="keyword">$this</span>->registerLoadEvents($provider, $events);</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//读取eager数组</span></span><br><span class="line"> <span class="keyword">foreach</span> ($manifest[<span class="string">'eager'</span>] <span class="keyword">as</span> $provider) {</span><br><span class="line"> <span class="keyword">$this</span>->app->register(<span class="keyword">$this</span>->createProvider($provider));</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//读取deferred数组</span></span><br><span class="line"> <span class="keyword">$this</span>->app->addDeferredServices($manifest[<span class="string">'deferred'</span>]);</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><br>首先通过loadManifest方法读取缓存清单,并通过json_decode转成数组,再通过数组合并array_merge([‘when’=>[]], $manifest),如果原缓存清单没有when数组则添加。<br>然后通过对比config/app下的providers数组与清单里的providers数组是否一致,来决定是否重新编译。若框架初次运行,肯定是要编译的。所以关注点也在于编译清单的compileManifest方法</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">compileManifest</span><span class="params">($providers)</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> $manifest = <span class="keyword">$this</span>->freshManifest($providers);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">foreach</span> ($providers <span class="keyword">as</span> $provider) {</span><br><span class="line"> <span class="comment">//获取具体服务提供者实例</span></span><br><span class="line"> <span class="comment">//$instance = new $provider(app);</span></span><br><span class="line"> $instance = <span class="keyword">$this</span>->createProvider($provider);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> ($instance->isDeferred()) {</span><br><span class="line"> <span class="keyword">foreach</span> ($instance->provides() <span class="keyword">as</span> $service) {</span><br><span class="line"> $manifest[<span class="string">'deferred'</span>][$service] = $provider;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 使用基类ServierProvider的when方法,返回空数组[]</span></span><br><span class="line"> $manifest[<span class="string">'when'</span>][$provider] = $instance->when();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> {</span><br><span class="line"> $manifest[<span class="string">'eager'</span>][] = $provider;</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="keyword">$this</span>->writeManifest($manifest);</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//获取初始化数组</span></span><br><span class="line"> <span class="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">freshManifest</span><span class="params">(array $providers)</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">return</span> [<span class="string">'providers'</span> => $providers, <span class="string">'eager'</span> => [], <span class="string">'deferred'</span> => []];</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>首先通过freshManifest获取初始化的默认数组,然后对配置中的providers数组进行循环遍历处理。根据具体类的属性,最终生成想要的清单。<br>这里假设$provides 只有两个 Illuminate\Auth\AuthServiceProvider 和 Illuminate\Cache\CacheServiceProvider,作为例子。<br>获取服务提供者实例,根据其deffer属性判断是否为需要延迟注册的服务。如果不是,则存入eager对应的数组中。<br><figure class="highlight scala"><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">//没有deffer=true属性 </span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">AuthServiceProvider</span> <span class="keyword">extends</span> <span class="title">ServiceProvider</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="comment">//延时加载</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">CacheServiceProvider</span> <span class="keyword">extends</span> <span class="title">ServiceProvider</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">protected</span> $defer = <span class="literal">true</span>; </span><br><span class="line">}</span><br></pre></td></tr></table></figure><br>例子中编译好的清单$manifest就是下面这样的,接着执行writeManifest方法,将清单写入缓存server.json<br><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></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> <span class="attr">"providers"</span>: [ </span><br><span class="line"> <span class="string">"Illuminate\\Auth\\AuthServiceProvider"</span>,</span><br><span class="line"> <span class="string">"Illuminate\\Cache\\CacheServiceProvider"</span>,</span><br><span class="line"> ],</span><br><span class="line"> <span class="attr">"eager"</span>: [</span><br><span class="line"> <span class="string">"Illuminate\\Auth\\AuthServiceProvider"</span>,</span><br><span class="line"> ],</span><br><span class="line"> <span class="attr">"deferred"</span>: [</span><br><span class="line"> <span class="string">"Illuminate\\Cache\\CacheServiceProvider"</span>,</span><br><span class="line"> ],</span><br><span class="line"> <span class="attr">"when"</span>: {</span><br><span class="line"> <span class="attr">"Illuminate\\Cache\\CacheServiceProvider"</span>: [],</span><br><span class="line"> },</span><br><span class="line">}</span><br></pre></td></tr></table></figure><br>继续看上面的load方法<br>1.读取eager数组的直接执行app->regisert(provider实例);</p><p>2.读取when数组,比如我们重写CacheServiceProvider的when方法, 返回如下的数组<br><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><br><span class="line"> <span class="string">"when"</span>: {</span><br><span class="line"> <span class="comment">// 可以多个事件</span></span><br><span class="line"> <span class="string">"Illuminate\\Cache\\CacheServiceProvider"</span>: [<span class="string">'test_cache_when1'</span>,<span class="string">'test_cache_when2'</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="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">registerLoadEvents</span><span class="params">($provider, array $events)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (count($events) < <span class="number">1</span>) {</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> $app = <span class="keyword">$this</span>->app;</span><br><span class="line"> <span class="comment">//注册事件监听者</span></span><br><span class="line"> $app->make(<span class="string">'events'</span>)->listen($events, <span class="function"><span class="keyword">function</span> <span class="params">()</span> <span class="title">use</span> <span class="params">($app, $provider)</span> </span>{</span><br><span class="line"> $app->register($provider);</span><br><span class="line"> });</span><br><span class="line">}</span><br></pre></td></tr></table></figure><br>这里的实质就是注册事件回调,当我们执行event()->fire(‘test_cache_when1’), 或者event()->fire(‘test_cache_when2’)就会触发事件回调,将对应的provider进行注册。</p><p>3.读取deffer数组 ,这里把延时服务数组赋值给app类的deferredServices属性,真正的注册则是在执行app的make方法时实现的。<br><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">// application类</span></span><br><span class="line"><span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">addDeferredServices</span><span class="params">(array $services)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">$this</span>->deferredServices = array_merge(<span class="keyword">$this</span>->deferredServices, $services);</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">make</span><span class="params">($abstract, array $parameters = [])</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line">...</span><br><span class="line"><span class="comment">//如果延时服务存在,那么在make之前进行注册</span></span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">isset</span>(<span class="keyword">$this</span>->deferredServices[$abstract])) {</span><br><span class="line"> <span class="keyword">$this</span>->loadDeferredProvider($abstract);</span><br><span class="line"> }</span><br><span class="line"> ...</span><br><span class="line">} </span><br></pre></td></tr></table></figure><br>所谓服务注册无非是为容器绑定一个可以返回所需实例的闭包,而实际使用中,除了app启动时必须实例外(如router),只有需要用到的对应实例,才进行闭包绑定,然后再通过容器make。</p>]]></content>
<categories>
<category> laravel源码学习分享 </category>
</categories>
<tags>
<tag> 服务注册 </tag>
</tags>
</entry>
<entry>
<title>门面Facades类</title>
<link href="/facades.html"/>
<url>/facades.html</url>
<content type="html"><![CDATA[<p>  门面,重要设计思想。通过门面,我们可以直接在所需类上使用静态调用的方法,如Cache::get(‘test’)、DB::table(‘test’)等</p><h4 id="Facedes初始化"><a href="#Facedes初始化" class="headerlink" title="Facedes初始化"></a>Facedes初始化</h4><p>门面的初始化在核心类执行bootstrap方法时,就初始化完成。<br><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="comment">//Illuminate\Foundation\Bootstrap\RegisterFacades 的 bootstrap()</span></span><br><span class="line"><span class="comment">//单例模式,获取AliasLoader实例</span></span><br><span class="line"> AliasLoader::getInstance($app->make(<span class="string">'config'</span>)->get(<span class="string">'app.aliases'</span>))->register();</span><br><span class="line"></span><br><span class="line"> <span class="comment">//config目录下app.aliases的门面别名数组</span></span><br><span class="line"> <span class="string">'aliases'</span> => [</span><br><span class="line"> <span class="string">'Cache'</span> => Illuminate\Support\Facades\Cache::class,</span><br><span class="line"> <span class="string">'DB'</span> => Illuminate\Support\Facades\DB::class,</span><br><span class="line"> ],</span><br></pre></td></tr></table></figure></p><h4 id="class-alias"><a href="#class-alias" class="headerlink" title="class_alias"></a>class_alias</h4><p>为门面类的实例注册别名。拿Cache门面举例,打印 new Cache() 实质返回 Illuminate\Support\Facades\Cache类<br><a id="more"></a><br><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="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">register</span><span class="params">()</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>->registered) {</span><br><span class="line"> <span class="keyword">$this</span>->prependToLoaderStack();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">$this</span>->registered = <span class="keyword">true</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">prependToLoaderStack</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{ </span><br><span class="line"> <span class="comment">//将load函数显式注册到SPL __autoload函数队列中</span></span><br><span class="line"> spl_autoload_register([<span class="keyword">$this</span>, <span class="string">'load'</span>], <span class="keyword">true</span>, <span class="keyword">true</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="function"><span class="keyword">function</span> <span class="title">load</span><span class="params">($alias)</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="keyword">$this</span>->aliases[$alias])) {</span><br><span class="line"> <span class="comment">//例如 class_alias('Illuminate\Support\Facades\Cache', 'Cache')</span></span><br><span class="line"> <span class="keyword">return</span> class_alias(<span class="keyword">$this</span>->aliases[$alias], $alias);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><br>所有的门面类都必须继承Facades<br><figure class="highlight scala"><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">namespace <span class="type">Illuminate</span>\<span class="type">Support</span>\<span class="type">Facades</span>;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Cache</span> <span class="keyword">extends</span> <span class="title">Facade</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">protected</span> static function getFacadeAccessor()</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">return</span> <span class="symbol">'cach</span>e';</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><h4 id="Facades基类"><a href="#Facades基类" class="headerlink" title="Facades基类"></a>Facades基类</h4><p>通过__callStatic方法实现门面的静态调用。<br><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></pre></td><td class="code"><pre><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="function"><span class="keyword">function</span> <span class="title">__callStatic</span><span class="params">($method, $args)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> $instance = <span class="keyword">static</span>::getFacadeRoot();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (! $instance) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> RuntimeException(<span class="string">'A facade root has not been set.'</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">switch</span> (count($args)) {</span><br><span class="line"> <span class="keyword">case</span> <span class="number">0</span>:</span><br><span class="line"> <span class="keyword">return</span> $instance->$method();</span><br><span class="line"> <span class="keyword">case</span> <span class="number">1</span>:</span><br><span class="line"> <span class="keyword">return</span> $instance->$method($args[<span class="number">0</span>]);</span><br><span class="line"> <span class="keyword">case</span> <span class="number">2</span>:</span><br><span class="line"> <span class="keyword">return</span> $instance->$method($args[<span class="number">0</span>], $args[<span class="number">1</span>]);</span><br><span class="line"> <span class="keyword">case</span> <span class="number">3</span>:</span><br><span class="line"> <span class="keyword">return</span> $instance->$method($args[<span class="number">0</span>], $args[<span class="number">1</span>], $args[<span class="number">2</span>]);</span><br><span class="line"> <span class="keyword">case</span> <span class="number">4</span>:</span><br><span class="line"> <span class="keyword">return</span> $instance->$method($args[<span class="number">0</span>], $args[<span class="number">1</span>], $args[<span class="number">2</span>], $args[<span class="number">3</span>]);</span><br><span class="line"> <span class="keyword">default</span>:</span><br><span class="line"> <span class="keyword">return</span> call_user_func_array([$instance, $method], $args);</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="keyword">public</span> <span class="keyword">static</span> <span class="function"><span class="keyword">function</span> <span class="title">getFacadeRoot</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="comment">//传入'cache'</span></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">static</span>::resolveFacadeInstance(<span class="keyword">static</span>::getFacadeAccessor());</span><br><span class="line">}</span><br><span class="line"><span class="keyword">protected</span> <span class="keyword">static</span> <span class="function"><span class="keyword">function</span> <span class="title">resolveFacadeInstance</span><span class="params">($name)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (is_object($name)) {</span><br><span class="line"> <span class="keyword">return</span> $name;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">isset</span>(<span class="keyword">static</span>::$resolvedInstance[$name])) {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">static</span>::$resolvedInstance[$name];</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// static::$app[$name], 在app类上已数组方式获取'cache'。 最终通过容器的make('cache')方法获取对应实例(CacheManager)</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">static</span>::$resolvedInstance[$name] = <span class="keyword">static</span>::$app[$name];</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>]]></content>
<categories>
<category> laravel源码学习分享 </category>
</categories>
<tags>
<tag> 门面 </tag>
<tag> Facedes </tag>
</tags>
</entry>
<entry>
<title>发送response</title>
<link href="/send-response.html"/>
<url>/send-response.html</url>
<content type="html"><![CDATA[<p>   index.php 的最后两行代码。整体流程结束。<br><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="comment">//index.php</span></span><br><span class="line">$response->send(); <span class="comment">// 发送响应</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 循环遍历kernel里所有中间件和当前路由所用中间件, 如果terminate方法存在,则执行</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//app->terminate(), 执行 全局terminate 方法</span></span><br><span class="line">$kernel->terminate($request, $response);</span><br></pre></td></tr></table></figure></p><h4 id="sendResponse"><a href="#sendResponse" class="headerlink" title="sendResponse"></a>sendResponse</h4><p>$response 为 Illuminate\Http\Response类,继承插件BaseResponse类<br><figure class="highlight scala"><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="comment">//插件 symfony/http-foundation</span></span><br><span class="line">use <span class="type">Symfony</span>\<span class="type">Component</span>\<span class="type">HttpFoundation</span>\<span class="type">Response</span> as <span class="type">BaseResponse</span>;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Response</span> <span class="keyword">extends</span> <span class="title">BaseResponse</span></span></span><br></pre></td></tr></table></figure><br><a id="more"></a><br>使用父类Symfony\Component\HttpFoundation\Response的send<br><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="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">send</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>->sendHeaders(); <span class="comment">//设置响应头信息</span></span><br><span class="line"> <span class="keyword">$this</span>->sendContent(); </span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (function_exists(<span class="string">'fastcgi_finish_request'</span>)) {</span><br><span class="line"> fastcgi_finish_request();</span><br><span class="line"> } <span class="keyword">elseif</span> (!\in_array(PHP_SAPI, <span class="keyword">array</span>(<span class="string">'cli'</span>, <span class="string">'phpdbg'</span>), <span class="keyword">true</span>)) {</span><br><span class="line"> <span class="comment">//与apache之间响应信息交互完毕。无法继续使用header()函数</span></span><br><span class="line"> <span class="keyword">static</span>::closeOutputBuffers(<span class="number">0</span>, <span class="keyword">true</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><h4 id="sendContent"><a href="#sendContent" class="headerlink" title="sendContent"></a>sendContent</h4><p>Illuminate\Http\Response里的sendContent。如果content是Renderable实例,也就是在路由控制器中执行了return view()。需要就content进行视图编译后,将其赋值为静态html文件。<br><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="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">setContent</span><span class="params">($content)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">$this</span>->original = $content;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">$this</span>->shouldBeJson($content)) {</span><br><span class="line"> <span class="keyword">$this</span>->header(<span class="string">'Content-Type'</span>, <span class="string">'application/json'</span>);</span><br><span class="line"></span><br><span class="line"> $content = <span class="keyword">$this</span>->morphToJson($content);</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="keyword">elseif</span> ($content <span class="keyword">instanceof</span> Renderable) {</span><br><span class="line"> <span class="comment">// 获取编译完成的视图 HTML 文件</span></span><br><span class="line"> $content = $content->render();</span><br><span class="line"> </span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">parent</span>::setContent($content);</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><h4 id="terminate"><a href="#terminate" class="headerlink" title="terminate"></a>terminate</h4><p>此时response已返回成功,terminate为后续操作。会逐一执行所有中间的terminate方法。<br><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="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">terminate</span><span class="params">($request, $response)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="comment">//当前this为kernel </span></span><br><span class="line"> $middlewares = <span class="keyword">$this</span>->app->shouldSkipMiddleware() ? [] : array_merge(</span><br><span class="line"> <span class="keyword">$this</span>->gatherRouteMiddlewares($request), <span class="comment">//当前路由中间件</span></span><br><span class="line"> <span class="keyword">$this</span>->middleware <span class="comment">//kernel中间件</span></span><br><span class="line"> );</span><br><span class="line"> <span class="keyword">foreach</span> ($middlewares <span class="keyword">as</span> $middleware) {</span><br><span class="line"> <span class="keyword">list</span>($name, $parameters) = <span class="keyword">$this</span>->parseMiddleware($middleware);</span><br><span class="line"></span><br><span class="line"> $instance = <span class="keyword">$this</span>->app->make($name); </span><br><span class="line"> <span class="comment">// 通过容器获取中间件实例,执行方法terminate()</span></span><br><span class="line"> <span class="keyword">if</span> (method_exists($instance, <span class="string">'terminate'</span>)) {</span><br><span class="line"> $instance->terminate($request, $response);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">$this</span>->app->terminate();</span><br><span class="line">}</span><br></pre></td></tr></table></figure><br>比如执行 StartSession 中间件的 terminate方法,最终保存session。<br><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"> \Illuminate\Session\Middleware\StartSession</span><br><span class="line"><span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">terminate</span><span class="params">($request, $response)</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>->sessionHandled && <span class="keyword">$this</span>->sessionConfigured() && ! <span class="keyword">$this</span>->usingCookieSessions()) {</span><br><span class="line"> <span class="keyword">$this</span>->manager->driver()->save();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>]]></content>
<categories>
<category> laravel源码学习分享 </category>
</categories>
<tags>
<tag> 发送响应 </tag>
<tag> sendresponse </tag>
<tag> terminate </tag>
</tags>
</entry>
<entry>
<title>将Request分配至Route</title>
<link href="/router-dispatch.html"/>
<url>/router-dispatch.html</url>
<content type="html"><![CDATA[<p>在上篇的管道中的最终会执行下面这行代码<br><figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">return</span> <span class="variable">$this</span>->router->dispatch(<span class="variable">$request</span>);</span><br></pre></td></tr></table></figure></p><h4 id="dispatch方法"><a href="#dispatch方法" class="headerlink" title="dispatch方法"></a>dispatch方法</h4><p>首先调用路由前置的过滤方法, 如在routes.php 中可以使用Route::filter(‘before’=>’auth’)来创建前置方法<br><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="comment">//Router类</span></span><br><span class="line"><span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">dispatch</span><span class="params">(Request $request)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">$this</span>->currentRequest = $request;</span><br><span class="line"> <span class="comment">//分配至路由前,需要执行的过滤器</span></span><br><span class="line"> $response = <span class="keyword">$this</span>->callFilter(<span class="string">'before'</span>, $request);</span><br><span class="line"> <span class="comment">//如果过滤器有直接返回response,就不再进行路由分配</span></span><br><span class="line"> <span class="keyword">if</span> (is_null($response)) {</span><br><span class="line"> $response = <span class="keyword">$this</span>->dispatchToRoute($request);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> $response = <span class="keyword">$this</span>->prepareResponse($request, $response);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">$this</span>->callFilter(<span class="string">'after'</span>, $request, $response);</span><br><span class="line"> <span class="keyword">return</span> $response;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><br><a id="more"></a></p><h4 id="findRoute方法"><a href="#findRoute方法" class="headerlink" title="findRoute方法"></a>findRoute方法</h4><p>findRoute方法实质是从RouteCollection类中,根据路由url获取对应的Route类。 Router类是路由处理者,将routes.php 中的路由,用路由名做key,Route类做value,最终存入RouteCollection。如下图<br><img src="/images/route_collection.png"><br>通过请求methd,与url 在RouteCollection进行键值匹配,获取Route类<br><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="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">findRoute</span><span class="params">($request)</span></span></span><br><span class="line"><span class="function"></span>{ </span><br><span class="line"> <span class="comment">//$this->routes 是 RouteCollection</span></span><br><span class="line"> <span class="comment">//获取一个匹配路由,如果不存在则扔出错误。匹配请求方式Post,get,匹配url</span></span><br><span class="line"> <span class="keyword">$this</span>->current = $route = <span class="keyword">$this</span>->routes->match($request);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">$this</span>->container->instance(<span class="string">'Illuminate\Routing\Route'</span>, $route);<span class="comment">// 将当前路由实例注入容器</span></span><br><span class="line"> </span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->substituteBindings($route);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><br>substituteBindings方法实质是获取路由中正则匹配到的参数,如 Route::get(‘/aaa/{id}/{type}’,function($id,$type){}), 请求url为/aaa/11/1,那么id=11,type=1就会被捕获,并作为参数传入action对应的闭包中。</p><h4 id="runRouteWithinStack"><a href="#runRouteWithinStack" class="headerlink" title="runRouteWithinStack"></a>runRouteWithinStack</h4><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">// dispatchToRoute()方法中的核心方法</span></span><br><span class="line">$response = <span class="keyword">$this</span>->runRouteWithinStack(</span><br><span class="line"> $route, $request</span><br><span class="line"> );</span><br><span class="line"><span class="comment">//路由管道</span></span><br><span class="line"><span class="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">runRouteWithinStack</span><span class="params">(Route $route, Request $request)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> $shouldSkipMiddleware = <span class="keyword">$this</span>->container->bound(<span class="string">'middleware.disable'</span>) &&</span><br><span class="line"> <span class="keyword">$this</span>->container->make(<span class="string">'middleware.disable'</span>) === <span class="keyword">true</span>;</span><br><span class="line"> <span class="comment">//路由中间件</span></span><br><span class="line"> <span class="comment">//可以在routes.php中直接定义</span></span><br><span class="line"> <span class="comment">//如果在控制器的构造函数中执行$this->middleware('name'),必须有</span></span><br><span class="line"> <span class="comment">//Illuminate\Routing\ControllerServiceProvider::class这个服务</span></span><br><span class="line"> $middleware = $shouldSkipMiddleware ? [] : <span class="keyword">$this</span>->gatherRouteMiddlewares($route);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> (<span class="keyword">new</span> Pipeline(<span class="keyword">$this</span>->container))</span><br><span class="line"> ->send($request)</span><br><span class="line"> ->through($middleware)</span><br><span class="line"> ->then(<span class="function"><span class="keyword">function</span> <span class="params">($request)</span> <span class="title">use</span> <span class="params">($route)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->prepareResponse(</span><br><span class="line"> $request,</span><br><span class="line"> $route->run($request) <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><h4 id="run-request"><a href="#run-request" class="headerlink" title="run($request)"></a>run($request)</h4><p>执行路由对应的方法<br><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="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">run</span><span class="params">(Request $request)</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->container = <span class="keyword">$this</span>->container ?: <span class="keyword">new</span> Container;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">if</span> (! is_string(<span class="keyword">$this</span>->action[<span class="string">'uses'</span>])) {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->runCallable($request);</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//如果有自定义路由分配器,则重新由该分配器处理路由</span></span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">$this</span>->customDispatcherIsBound()) {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->runWithCustomDispatcher($request);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->runController($request);</span><br><span class="line"> } <span class="keyword">catch</span> (HttpResponseException $e) {</span><br><span class="line"> <span class="keyword">return</span> $e->getResponse();</span><br><span class="line"> }</span><br><span class="line"> }</span><br></pre></td></tr></table></figure></p><p>当路由对应的action 是匿名函数,如 Route::get(‘/‘,function(Request $reuqest){ });<br>通过反射类和容器获取request 依赖实例,注入参数,并执行<br><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">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">runCallable</span><span class="params">(Request $request)</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> $parameters = <span class="keyword">$this</span>->resolveMethodDependencies(</span><br><span class="line"> <span class="keyword">$this</span>->parametersWithoutNulls(), <span class="keyword">new</span> ReflectionFunction(<span class="keyword">$this</span>->action[<span class="string">'uses'</span>])</span><br><span class="line"> );</span><br><span class="line"> <span class="keyword">return</span> call_user_func_array(<span class="keyword">$this</span>->action[<span class="string">'uses'</span>], $parameters);</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><br>当路由对应的action 是Controller类对应的方法名,如 Route::get(‘/‘,‘IndexController@index’);<br>首先通过反射类和容器获取IndexController里面的index方法中的依赖注入实例,如index(Request $request)<br>然后通过容器获取IndexController实例,最终执行index方法。<br><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="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">runController</span><span class="params">(Request $request)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">list</span>($class, $method) = explode(<span class="string">'@'</span>, <span class="keyword">$this</span>->action[<span class="string">'uses'</span>]);</span><br><span class="line"></span><br><span class="line"> $parameters = <span class="keyword">$this</span>->resolveClassMethodDependencies(</span><br><span class="line"> <span class="keyword">$this</span>->parametersWithoutNulls(), $class, $method</span><br><span class="line"> );</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">if</span> (! method_exists($instance = <span class="keyword">$this</span>->container->make($class), $method)) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> NotFoundHttpException;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> call_user_func_array([$instance, $method], $parameters);</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><h4 id="prepareResponse"><a href="#prepareResponse" class="headerlink" title="prepareResponse"></a>prepareResponse</h4><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><br><span class="line"><span class="number">1</span>、将路由action最终执行返回的结果设置为content属性。注意 <span class="string">'echo'</span> 情况下content 依然为空</span><br><span class="line"><span class="number">2</span>、在中间件后续操作中,也会为response头设置cookie等其他属性</span><br><span class="line"><span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">prepareResponse</span><span class="params">($request, $response)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> ($response <span class="keyword">instanceof</span> PsrResponseInterface) {</span><br><span class="line"> $response = (<span class="keyword">new</span> HttpFoundationFactory)->createResponse($response);</span><br><span class="line"> } <span class="keyword">elseif</span> (! $response <span class="keyword">instanceof</span> SymfonyResponse) {</span><br><span class="line"> $response = <span class="keyword">new</span> Response($response);</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//根据response类的相关属性,设置响应头信息</span></span><br><span class="line"> <span class="keyword">return</span> $response->prepare($request);</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category> laravel源码学习分享 </category>
</categories>
<tags>
<tag> 分配路由 </tag>
<tag> findRoute方法 </tag>
<tag> prepareResponse </tag>
</tags>
</entry>
<entry>
<title>核心类中的pipeline</title>
<link href="/kernel-pipeline.html"/>
<url>/kernel-pipeline.html</url>
<content type="html"><![CDATA[<p>  这是框架中kernel管道中的源码,through 方法将获取 App\Http\kernel中的$middleware数组,给Pipeline中的pipes属性赋值(与上篇中的$pipes一样),规定需要通过的中间件。</p><h4 id="middleware"><a href="#middleware" class="headerlink" title="middleware"></a>middleware</h4><p>App\Http\kernel中的$middleware 如下<br><figure class="highlight tex"><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">protected <span class="formula">$middleware = [</span></span><br><span class="line"><span class="formula"> //判断当前项目是否处于维护模式</span></span><br><span class="line"><span class="formula"> <span class="tag">\<span class="name">Illuminate</span></span><span class="tag">\<span class="name">Foundation</span></span><span class="tag">\<span class="name">Http</span></span><span class="tag">\<span class="name">Middleware</span></span><span class="tag">\<span class="name">CheckForMaintenanceMode</span></span>::class,</span></span><br><span class="line"><span class="formula"> //响应头Cookie如XSRF-TOKEN,laravel_session加密,以及对应Request的Cookie解密</span></span><br><span class="line"><span class="formula"> <span class="tag">\<span class="name">App</span></span><span class="tag">\<span class="name">Http</span></span><span class="tag">\<span class="name">Middleware</span></span><span class="tag">\<span class="name">EncryptCookies</span></span>::class, </span></span><br><span class="line"><span class="formula"> //获取CookieJar队列中的Cookie类, 并存入响应头, 如用户登录remember_token</span></span><br><span class="line"><span class="formula"> <span class="tag">\<span class="name">Illuminate</span></span><span class="tag">\<span class="name">Cookie</span></span><span class="tag">\<span class="name">Middleware</span></span><span class="tag">\<span class="name">AddQueuedCookiesToResponse</span></span>::class, </span></span><br><span class="line"><span class="formula"> //初始化session,整个底层并未session_start,通过手动生成session_id来完成这一动作</span></span><br><span class="line"><span class="formula"> <span class="tag">\<span class="name">Illuminate</span></span><span class="tag">\<span class="name">Session</span></span><span class="tag">\<span class="name">Middleware</span></span><span class="tag">\<span class="name">StartSession</span></span>::class,</span></span><br><span class="line"><span class="formula"> //将session中的errors变量,注入到全局视图类中。这是个一次性session</span></span><br><span class="line"><span class="formula"> <span class="tag">\<span class="name">Illuminate</span></span><span class="tag">\<span class="name">View</span></span><span class="tag">\<span class="name">Middleware</span></span><span class="tag">\<span class="name">ShareErrorsFromSession</span></span>::class,</span></span><br><span class="line"><span class="formula"> //Csrf 验证请求中的XSRF-TOKEN值</span></span><br><span class="line"><span class="formula"> <span class="tag">\<span class="name">App</span></span><span class="tag">\<span class="name">Http</span></span><span class="tag">\<span class="name">Middleware</span></span><span class="tag">\<span class="name">VerifyCsrfToken</span></span>::class,</span></span><br><span class="line"><span class="formula"> ];</span></span><br></pre></td></tr></table></figure><br><a id="more"></a><br><figure class="highlight livescript"><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="keyword">return</span> (<span class="keyword">new</span> Pipeline($<span class="keyword">this</span>->app))</span><br><span class="line"><span class="function"> -></span>send($request)</span><br><span class="line"><span class="function"> -></span>through($<span class="keyword">this</span>->app->shouldSkipMiddleware() ? [] : $<span class="keyword">this</span>->middleware)</span><br><span class="line"><span class="function"> -></span><span class="keyword">then</span>($<span class="keyword">this</span>->dispatchToRouter());</span><br></pre></td></tr></table></figure></p><h4 id="then方法"><a href="#then方法" class="headerlink" title="then方法"></a>then方法</h4><p>首先关注其参数,是将当前请求经kernel中间件处理完毕后,分配至路由需要执行的最终Closure<br><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></pre></td><td class="code"><pre><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">then</span><span class="params">(Closure $destination)</span></span></span><br><span class="line"><span class="function"> </span>{ </span><br><span class="line"> $destination = <span class="function"><span class="keyword">function</span> <span class="params">($request)</span> </span>{</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">$this</span>->app->instance(<span class="string">'request'</span>, $request);</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->router->dispatch($request); <span class="comment">// 请求最终到达的路由</span></span><br><span class="line"></span><br><span class="line"> };</span><br><span class="line"> $firstSlice = <span class="keyword">$this</span>->getInitialSlice($destination);</span><br><span class="line"></span><br><span class="line"> $pipes = array_reverse(<span class="keyword">$this</span>->pipes); <span class="comment">//即中间件数组 顺序颠倒,因为array_reduce使用逆嵌套</span></span><br><span class="line"><span class="comment">// $this->passable就是request类</span></span><br><span class="line"> <span class="keyword">return</span> call_user_func(</span><br><span class="line"> array_reduce($pipes, <span class="keyword">$this</span>->getSlice(), $firstSlice), <span class="keyword">$this</span>->passable</span><br><span class="line"> );</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">getSlice</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="function"><span class="keyword">function</span> <span class="params">($stack, $pipe)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="function"><span class="keyword">function</span> <span class="params">($passable)</span> <span class="title">use</span> <span class="params">($stack, $pipe)</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> ($pipe <span class="keyword">instanceof</span> Closure) {</span><br><span class="line"> <span class="keyword">return</span> call_user_func($pipe, $passable, $stack);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">list</span>($name, $parameters) = <span class="keyword">$this</span>->parsePipeString($pipe);</span><br><span class="line"> <span class="comment">//$this->method = handle; 方法</span></span><br><span class="line"> <span class="comment">// $name 即中间类名,通过容器获取实例</span></span><br><span class="line"> <span class="keyword">return</span> call_user_func_array([<span class="keyword">$this</span>->container->make($name), <span class="keyword">$this</span>->method],</span><br><span class="line"> array_merge([$passable, $stack], $parameters));</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="comment">//最内层,将请求分发至路由的闭包</span></span><br><span class="line"> <span class="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">getInitialSlice</span><span class="params">(Closure $destination)</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="function"><span class="keyword">function</span> <span class="params">($passable)</span> <span class="title">use</span> <span class="params">($destination)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> call_user_func($destination, $passable);</span><br><span class="line"> };</span><br><span class="line"> }</span><br></pre></td></tr></table></figure></p><p>所有的焦点都聚集到最终返回响应的路由。下篇分析 $this->router->dispatch($request)。</p>]]></content>
<categories>
<category> laravel源码学习分享 </category>
</categories>
<tags>
<tag> pipeline </tag>
<tag> middleware </tag>
</tags>
</entry>
<entry>
<title>pipeline管道(原理模拟)</title>
<link href="/pipeline.html"/>
<url>/pipeline.html</url>
<content type="html"><![CDATA[<h4 id="管道概念"><a href="#管道概念" class="headerlink" title="管道概念"></a>管道概念</h4><p>  当从一个进程连接数据流到另一个进程时,我们使用术语管道。我们通常是把一个进程的输出通过管道连接到另一个进程的输入。通过这些进程(<font color="#f56954">中间件Middleware</font>)的处理后最终返回结果值。这里也有一个高大上的术语:<font color="#f56954">装饰者模式</font><br><img src="/images/pipeline.png"></p><h4 id="基本实现"><a href="#基本实现" class="headerlink" title="基本实现"></a>基本实现</h4><p>按照上图,下面是用代码模拟其实现的过程。<br><a id="more"></a><br><figure class="highlight xml"><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="php"><span class="meta"><?php</span> </span></span><br><span class="line"><span class="php"><span class="class"><span class="keyword">class</span> <span class="title">Hardwater</span></span></span></span><br><span class="line"><span class="php">{</span></span><br><span class="line"><span class="php"><span class="keyword">public</span> $contain = [</span></span><br><span class="line"><span class="php"><span class="string">'sand'</span>=> <span class="keyword">true</span>,</span></span><br><span class="line"><span class="php"><span class="string">'impurity'</span>=> <span class="keyword">true</span>,</span></span><br><span class="line"><span class="php"><span class="string">'ion'</span> => [<span class="string">'Mg+'</span>,<span class="string">'Al3+'</span>],</span></span><br><span class="line"><span class="php">];</span></span><br><span class="line"><span class="php">}</span></span><br><span class="line"><span class="php"><span class="comment">//滤网,清除沙子</span></span></span><br><span class="line"><span class="php"><span class="class"><span class="keyword">class</span> <span class="title">Sieve</span></span></span></span><br><span class="line"><span class="php">{</span></span><br><span class="line"><span class="php"><span class="keyword">public</span> <span class="keyword">static</span> <span class="function"><span class="keyword">function</span> <span class="title">handle</span><span class="params">($water)</span></span></span></span><br><span class="line"><span class="php">{</span></span><br><span class="line"><span class="php">$water->contain[<span class="string">'sand'</span>] = <span class="keyword">false</span>;</span></span><br><span class="line"><span class="php"></span></span><br><span class="line"><span class="php"><span class="keyword">return</span> $water;</span></span><br><span class="line"><span class="php">}</span></span><br><span class="line"><span class="php">}</span></span><br><span class="line"><span class="php"><span class="comment">//明矾,清除细颗粒杂质</span></span></span><br><span class="line"><span class="php"><span class="class"><span class="keyword">class</span> <span class="title">KAlSO4</span></span></span></span><br><span class="line"><span class="php">{</span></span><br><span class="line"><span class="php"><span class="keyword">public</span> <span class="keyword">static</span> <span class="function"><span class="keyword">function</span> <span class="title">handle</span><span class="params">($water)</span></span></span></span><br><span class="line"><span class="php">{</span></span><br><span class="line"><span class="php">$water->contain[<span class="string">'impurity'</span>] = <span class="keyword">false</span>;</span></span><br><span class="line"><span class="php"></span></span><br><span class="line"><span class="php"><span class="keyword">return</span> $water;</span></span><br><span class="line"><span class="php">}</span></span><br><span class="line"><span class="php">}</span></span><br><span class="line"><span class="php"><span class="comment">//高温加热</span></span></span><br><span class="line"><span class="php"><span class="class"><span class="keyword">class</span> <span class="title">Heat</span></span></span></span><br><span class="line"><span class="php">{</span></span><br><span class="line"><span class="php"><span class="keyword">public</span> <span class="keyword">static</span> <span class="function"><span class="keyword">function</span> <span class="title">handle</span><span class="params">($water)</span></span></span></span><br><span class="line"><span class="php">{</span></span><br><span class="line"><span class="php">$water->contain[<span class="string">'ion'</span>] = [];</span></span><br><span class="line"><span class="php"></span></span><br><span class="line"><span class="php"><span class="keyword">return</span> $water;</span></span><br><span class="line"><span class="php">}</span></span><br><span class="line"><span class="php">}</span></span><br><span class="line"><span class="php">$water = <span class="keyword">new</span> Hardwater;</span></span><br><span class="line"><span class="php"></span></span><br><span class="line"><span class="php">$water = Sieve::handle($water);</span></span><br><span class="line"><span class="php"></span></span><br><span class="line"><span class="php">$water = KAlSO4::handle($water);</span></span><br><span class="line"><span class="php"></span></span><br><span class="line"><span class="php">$softWater = Heat::handle($water);</span></span><br><span class="line"><span class="php"></span></span><br><span class="line"><span class="php"><span class="comment">//变形一下</span></span></span><br><span class="line"><span class="php">$softWater = Heat::handle(</span></span><br><span class="line"><span class="php">KAlSO4::handle(</span></span><br><span class="line"><span class="php">Sieve::handle($water)</span></span><br><span class="line"><span class="php">)</span></span><br><span class="line"><span class="php">);</span></span><br></pre></td></tr></table></figure></p><h4 id="嵌套闭包实现"><a href="#嵌套闭包实现" class="headerlink" title="嵌套闭包实现"></a>嵌套闭包实现</h4><p>这块需要理解通过array_reduce,生成最终pipeline函数的过程。重在实际操作。<br><blockquote><footer><strong>array_reduce</strong><cite><a href="http://php.net/manual/zh/function.array-reduce.php" target="_blank" rel="noopener">php.net/manual/zh/function.array-reduce.php</a></cite></footer></blockquote><br><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">hardWater</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"><span class="keyword">public</span> $contain = [</span><br><span class="line"><span class="string">'sand'</span>=> <span class="keyword">true</span>,</span><br><span class="line"><span class="string">'impurity'</span>=> <span class="keyword">true</span>,</span><br><span class="line"><span class="string">'ion'</span> => [<span class="string">'Mg+'</span>,<span class="string">'Al3+'</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="class"><span class="keyword">class</span> <span class="title">Sieve</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="function"><span class="keyword">function</span> <span class="title">handle</span><span class="params">($water,Closure $next)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">echo</span> <span class="string">"沙子处理<br>"</span>;</span><br><span class="line">$water->contain[<span class="string">'sand'</span>] = <span class="keyword">null</span>;</span><br><span class="line"></span><br><span class="line">$softWater = $next($water);</span><br><span class="line"></span><br><span class="line"><span class="keyword">echo</span> <span class="string">"沙子过滤完毕<br>"</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> $softWater;</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="class"><span class="keyword">class</span> <span class="title">KAlSO4</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="function"><span class="keyword">function</span> <span class="title">handle</span><span class="params">($water,Closure $next)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">echo</span> <span class="string">"明矾处理<br>"</span>;</span><br><span class="line">$water->contain[<span class="string">'impurity'</span>] = <span class="keyword">null</span>;</span><br><span class="line"></span><br><span class="line">$softWater = $next($water);</span><br><span class="line"></span><br><span class="line"><span class="keyword">echo</span> <span class="string">"杂质过滤完毕<br>"</span>;</span><br><span class="line"><span class="keyword">return</span> $softWater;</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="class"><span class="keyword">class</span> <span class="title">Heat</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="function"><span class="keyword">function</span> <span class="title">handle</span><span class="params">($water,Closure $next)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">echo</span> <span class="string">"加热处理<br>"</span>;</span><br><span class="line">$water->contain[<span class="string">'ion'</span>] = <span class="keyword">null</span>;</span><br><span class="line">$softWater = $next($water);</span><br><span class="line"><span class="keyword">echo</span> <span class="string">"离子过滤完毕<br>"</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> $softWater;</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">getSlice</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="function"><span class="keyword">function</span> <span class="params">($stack,$pipe)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">return</span> <span class="function"><span class="keyword">function</span><span class="params">($water)</span> <span class="title">use</span> <span class="params">($stack,$pipe)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">return</span> $pipe::handle($water,$stack);</span><br><span class="line">};</span><br><span class="line">};</span><br><span class="line">}</span><br><span class="line"><span class="comment">// 通过增加和减少$pipes的数量,查看最终管道闭包的变化,更易于理解</span></span><br><span class="line">$pipes = [</span><br><span class="line"><span class="string">'Sieve'</span>,</span><br><span class="line"><span class="string">'KAlSO4'</span>,</span><br><span class="line"><span class="comment">//'Heat'</span></span><br><span class="line">];</span><br><span class="line">$firstSlice = <span class="function"><span class="keyword">function</span><span class="params">($water)</span> </span>{</span><br><span class="line"> <span class="keyword">echo</span> <span class="string">"<span style='color:green;'>硬水净化完毕</span><br/>"</span>;</span><br><span class="line"> $softWater = $water;</span><br><span class="line"> <span class="keyword">return</span> $softWater;</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line">$pipes = array_reverse($pipes); <span class="comment">// 由于闭包是逆向生成,必须先颠倒顺序。</span></span><br><span class="line"></span><br><span class="line">$pipeline = array_reduce($pipes, getSlice(),$firstSlice); <span class="comment">//最终管道闭包</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">echo</span> <span class="string">"<pre>"</span>.print_r($pipeline,<span class="number">1</span>);</span><br><span class="line"></span><br><span class="line">$hardWater = <span class="keyword">new</span> hardWater;</span><br><span class="line">$res = call_user_func($pipeline,$hardWater);</span><br></pre></td></tr></table></figure></p><p>这是最终的函数,以及打印结果<br><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></pre></td><td class="code"><pre><span class="line">Closure Object</span><br><span class="line">(</span><br><span class="line"><span class="comment">//第一次将Hardwater传入Sieve进行处理,比如结果为A1</span></span><br><span class="line"> [<span class="keyword">static</span>] => <span class="keyword">Array</span> </span><br><span class="line"> (</span><br><span class="line"> [stack] => Closure Object <span class="comment">// $next( A1 )</span></span><br><span class="line"> (</span><br><span class="line"> <span class="comment">// 第二次将A1传入KAlSO4进行处理,比如结果为A2</span></span><br><span class="line"> [<span class="keyword">static</span>] => <span class="keyword">Array</span> </span><br><span class="line"> (</span><br><span class="line"> [stack] => Closure Object <span class="comment">// $next( A2 )</span></span><br><span class="line"> (</span><br><span class="line"> <span class="comment">// 第三次次将A1传入Heat进行处理,比如结果为A3</span></span><br><span class="line"> [<span class="keyword">static</span>] => <span class="keyword">Array</span> </span><br><span class="line"> (</span><br><span class="line"> <span class="comment">//最终$next(A3),执行firstSlice对应的闭包</span></span><br><span class="line"> <span class="comment">//也称之为destination(目的地),最终结果</span></span><br><span class="line"> [stack] => Closure Object</span><br><span class="line"> (</span><br><span class="line"> [parameter] => <span class="keyword">Array</span></span><br><span class="line"> (</span><br><span class="line"> [$water] => </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"> [pipe] => Heat</span><br><span class="line"> )</span><br><span class="line"></span><br><span class="line"> [parameter] => <span class="keyword">Array</span></span><br><span class="line"> (</span><br><span class="line"> [$water] => </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"> [pipe] => KAlSO4</span><br><span class="line"> )</span><br><span class="line"></span><br><span class="line"> [parameter] => <span class="keyword">Array</span></span><br><span class="line"> (</span><br><span class="line"> [$water] => </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"> [pipe] => Sieve</span><br><span class="line"> )</span><br><span class="line"></span><br><span class="line"> [parameter] => <span class="keyword">Array</span></span><br><span class="line"> (</span><br><span class="line"> [$water] => </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><span class="line"><span class="string">'硬水净化完毕'</span></span><br><span class="line">离子过滤完毕</span><br><span class="line">杂质过滤完毕</span><br><span class="line">沙子过滤完毕</span><br></pre></td></tr></table></figure></p>]]></content>
<categories>
<category> laravel源码学习分享 </category>
</categories>
<tags>
<tag> pipeline </tag>
<tag> middleware </tag>
</tags>
</entry>
<entry>
<title>kernel类handle方法</title>
<link href="/kernel-handle.html"/>
<url>/kernel-handle.html</url>
<content type="html"><![CDATA[<p>  通过容器获取kernel实例,将request类传入kernel的handle方法,最终返回响应而这是一个极其漫长的过程,因为这个过程将整个框架所需的服务、文件全部初始化完成。</p><h4 id="kernel的handle方法"><a href="#kernel的handle方法" class="headerlink" title="kernel的handle方法"></a>kernel的handle方法</h4><p>随着这个方法执行完毕,整体框架的流程基本就完成80%了<br><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">//index.php</span></span><br><span class="line">$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);</span><br><span class="line">$response = $kernel->handle(</span><br><span class="line"> $request = Illuminate\Http\Request::capture()</span><br><span class="line">);</span><br><span class="line"></span><br><span class="line"><span class="comment">//kernel的handle方法</span></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">($request)</span></span></span><br><span class="line"><span class="function"></span>{<span class="comment">//在此过程中,所有异常都会通过Exceptions 直接抛出</span></span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> $request->enableHttpMethodParameterOverride();</span><br><span class="line"> <span class="comment">//通过发送请求,经路由处理,最终返回response</span></span><br><span class="line"> $response = <span class="keyword">$this</span>->sendRequestThroughRouter($request);</span><br><span class="line"> } <span class="keyword">catch</span> (<span class="keyword">Exception</span> $e) {</span><br><span class="line"> <span class="keyword">$this</span>->reportException($e);</span><br><span class="line"></span><br><span class="line"> $response = <span class="keyword">$this</span>->renderException($request, $e);</span><br><span class="line"> } <span class="keyword">catch</span> (Throwable $e) {</span><br><span class="line"> $e = <span class="keyword">new</span> FatalThrowableError($e);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">$this</span>->reportException($e);</span><br><span class="line"></span><br><span class="line"> $response = <span class="keyword">$this</span>->renderException($request, $e);</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 触发'kernel.handled'事件listener,如果存在的话</span></span><br><span class="line"> <span class="keyword">$this</span>->app[<span class="string">'events'</span>]->fire(<span class="string">'kernel.handled'</span>, [$request, $response]);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> $response;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><h4 id="sendRequestThroughRouter"><a href="#sendRequestThroughRouter" class="headerlink" title="sendRequestThroughRouter"></a>sendRequestThroughRouter</h4><p>重中之重的方法,分两个部分说<br>① $this->bootstrap();<br>① Pipeline管道;<br><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="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">sendRequestThroughRouter</span><span class="params">($request)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">$this</span>->app->instance(<span class="string">'request'</span>, $request); <span class="comment">//Reuqest 实例加入instances 数组中</span></span><br><span class="line"></span><br><span class="line"> Facade::clearResolvedInstance(<span class="string">'request'</span>); </span><br><span class="line"></span><br><span class="line"> <span class="keyword">$this</span>->bootstrap(); <span class="comment">//关键方法,几乎加载所有服务和文件</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">// 管道类处理request </span></span><br><span class="line"> <span class="keyword">return</span> (<span class="keyword">new</span> Pipeline(<span class="keyword">$this</span>->app))</span><br><span class="line"> ->send($request)</span><br><span class="line"> ->through(<span class="keyword">$this</span>->app->shouldSkipMiddleware() ? [] : <span class="keyword">$this</span>->middleware)</span><br><span class="line"> ->then(<span class="keyword">$this</span>->dispatchToRouter());</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>]]></content>
<categories>
<category> laravel源码学习分享 </category>
</categories>
<tags>
<tag> kernel </tag>
</tags>
</entry>
<entry>
<title>bootstrap所有服务</title>
<link href="/bootstrap.html"/>
<url>/bootstrap.html</url>
<content type="html"><![CDATA[<p>  bootstrap是整个框架的引导,加载了必须的服务,文件等。</p><h4 id="bootstrap"><a href="#bootstrap" class="headerlink" title="bootstrap"></a>bootstrap</h4><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="keyword">protected</span> $bootstrappers = [</span><br><span class="line"> <span class="string">'Illuminate\Foundation\Bootstrap\DetectEnvironment'</span>, <span class="comment">//env环境变量处理类</span></span><br><span class="line"> <span class="string">'Illuminate\Foundation\Bootstrap\LoadConfiguration'</span>, <span class="comment">//config配置文件处理类</span></span><br><span class="line"> <span class="string">'Illuminate\Foundation\Bootstrap\ConfigureLogging'</span>, <span class="comment">//系统日志处理类,报错等</span></span><br><span class="line"> <span class="string">'Illuminate\Foundation\Bootstrap\HandleExceptions'</span>, <span class="comment">//异常处理类</span></span><br><span class="line"> <span class="string">'Illuminate\Foundation\Bootstrap\RegisterFacades'</span>, <span class="comment">//门面处理类</span></span><br><span class="line"> <span class="string">'Illuminate\Foundation\Bootstrap\RegisterProviders'</span>, <span class="comment">// 注册config.app 中所有服务提供者</span></span><br><span class="line"> <span class="string">'Illuminate\Foundation\Bootstrap\BootProviders'</span>, <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">bootstrap</span><span class="params">()</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>->app->hasBeenBootstrapped()) {</span><br><span class="line"> <span class="keyword">$this</span>->app->bootstrapWith(<span class="keyword">$this</span>->bootstrappers()); <span class="comment">// 即传入$this->bootstrappers</span></span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><a id="more"></a><h4 id="bootstrapWith"><a href="#bootstrapWith" class="headerlink" title="bootstrapWith"></a>bootstrapWith</h4><p>通过容器make方法获取上文数组中的实例,并执行其bootstrap(app)方法,传入参数为app实例<br><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><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">bootstrapWith</span><span class="params">(array $bootstrappers)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">$this</span>->hasBeenBootstrapped = <span class="keyword">true</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">foreach</span> ($bootstrappers <span class="keyword">as</span> $bootstrapper) {</span><br><span class="line"> <span class="keyword">$this</span>[<span class="string">'events'</span>]->fire(<span class="string">'bootstrapping: '</span>.$bootstrapper, [<span class="keyword">$this</span>]);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">$this</span>->make($bootstrapper)->bootstrap(<span class="keyword">$this</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">$this</span>[<span class="string">'events'</span>]->fire(<span class="string">'bootstrapped: '</span>.$bootstrapper, [<span class="keyword">$this</span>]);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><br>在bootstrapWith执行完成之后,它的整个流程会在events(Dispatcher类)的sorted属性中有详细记载,如下<br><figure class="highlight tex"><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">protected <span class="formula">$sorted = [</span></span><br><span class="line"><span class="formula">"Illuminate<span class="tag">\<span class="name">Events</span></span><span class="tag">\<span class="name">EventServiceProvider</span></span>" => []</span></span><br><span class="line"><span class="formula"> "Illuminate<span class="tag">\<span class="name">Routing</span></span><span class="tag">\<span class="name">RoutingServiceProvider</span></span>" => []</span></span><br><span class="line"><span class="formula"> "bootstrapping: Illuminate<span class="tag">\<span class="name">Foundation</span></span><span class="tag">\<span class="name">Bootstrap</span></span><span class="tag">\<span class="name">DetectEnvironment</span></span>" => []</span></span><br><span class="line"><span class="formula"> "bootstrapped: Illuminate<span class="tag">\<span class="name">Foundation</span></span><span class="tag">\<span class="name">Bootstrap</span></span><span class="tag">\<span class="name">DetectEnvironment</span></span>" => []</span></span><br><span class="line"><span class="formula"> "bootstrapping: Illuminate<span class="tag">\<span class="name">Foundation</span></span><span class="tag">\<span class="name">Bootstrap</span></span><span class="tag">\<span class="name">LoadConfiguration</span></span>" => []</span></span><br><span class="line"><span class="formula"> "bootstrapped: Illuminate<span class="tag">\<span class="name">Foundation</span></span><span class="tag">\<span class="name">Bootstrap</span></span><span class="tag">\<span class="name">LoadConfiguration</span></span>" => []</span></span><br><span class="line"><span class="formula"> "bootstrapping: Illuminate<span class="tag">\<span class="name">Foundation</span></span><span class="tag">\<span class="name">Bootstrap</span></span><span class="tag">\<span class="name">ConfigureLogging</span></span>" => []</span></span><br><span class="line"><span class="formula"> "bootstrapped: Illuminate<span class="tag">\<span class="name">Foundation</span></span><span class="tag">\<span class="name">Bootstrap</span></span><span class="tag">\<span class="name">ConfigureLogging</span></span>" => []</span></span><br><span class="line"><span class="formula"> "bootstrapping: Illuminate<span class="tag">\<span class="name">Foundation</span></span><span class="tag">\<span class="name">Bootstrap</span></span><span class="tag">\<span class="name">HandleExceptions</span></span>" => []</span></span><br><span class="line"><span class="formula"> "bootstrapped: Illuminate<span class="tag">\<span class="name">Foundation</span></span><span class="tag">\<span class="name">Bootstrap</span></span><span class="tag">\<span class="name">HandleExceptions</span></span>" => []</span></span><br><span class="line"><span class="formula"> "bootstrapping: Illuminate<span class="tag">\<span class="name">Foundation</span></span><span class="tag">\<span class="name">Bootstrap</span></span><span class="tag">\<span class="name">RegisterFacades</span></span>" => []</span></span><br><span class="line"><span class="formula"> "bootstrapped: Illuminate<span class="tag">\<span class="name">Foundation</span></span><span class="tag">\<span class="name">Bootstrap</span></span><span class="tag">\<span class="name">RegisterFacades</span></span>" => []</span></span><br><span class="line"><span class="formula"> "bootstrapping: Illuminate<span class="tag">\<span class="name">Foundation</span></span><span class="tag">\<span class="name">Bootstrap</span></span><span class="tag">\<span class="name">RegisterProviders</span></span>" => []</span></span><br><span class="line"><span class="formula"> "Illuminate<span class="tag">\<span class="name">Auth</span></span><span class="tag">\<span class="name">AuthServiceProvider</span></span>" => []</span></span><br><span class="line"><span class="formula"> "Illuminate<span class="tag">\<span class="name">Routing</span></span><span class="tag">\<span class="name">ControllerServiceProvider</span></span>" => []</span></span><br><span class="line"><span class="formula"> "Illuminate<span class="tag">\<span class="name">Cookie</span></span><span class="tag">\<span class="name">CookieServiceProvider</span></span>" => []</span></span><br><span class="line"><span class="formula"> "Illuminate<span class="tag">\<span class="name">Database</span></span><span class="tag">\<span class="name">DatabaseServiceProvider</span></span>" => []</span></span><br><span class="line"><span class="formula"> "Illuminate<span class="tag">\<span class="name">Encryption</span></span><span class="tag">\<span class="name">EncryptionServiceProvider</span></span>" => []</span></span><br><span class="line"><span class="formula"> "Illuminate<span class="tag">\<span class="name">Filesystem</span></span><span class="tag">\<span class="name">FilesystemServiceProvider</span></span>" => []</span></span><br><span class="line"><span class="formula"> "Illuminate<span class="tag">\<span class="name">Pagination</span></span><span class="tag">\<span class="name">PaginationServiceProvider</span></span>" => []</span></span><br><span class="line"><span class="formula"> "Illuminate<span class="tag">\<span class="name">Session</span></span><span class="tag">\<span class="name">SessionServiceProvider</span></span>" => []</span></span><br><span class="line"><span class="formula"> "Illuminate<span class="tag">\<span class="name">Validation</span></span><span class="tag">\<span class="name">ValidationServiceProvider</span></span>" => []</span></span><br><span class="line"><span class="formula"> "Illuminate<span class="tag">\<span class="name">View</span></span><span class="tag">\<span class="name">ViewServiceProvider</span></span>" => []</span></span><br><span class="line"><span class="formula"> "App<span class="tag">\<span class="name">Providers</span></span><span class="tag">\<span class="name">AppServiceProvider</span></span>" => []</span></span><br><span class="line"><span class="formula"> "App<span class="tag">\<span class="name">Providers</span></span><span class="tag">\<span class="name">AuthServiceProvider</span></span>" => []</span></span><br><span class="line"><span class="formula"> "App<span class="tag">\<span class="name">Providers</span></span><span class="tag">\<span class="name">EventServiceProvider</span></span>" => []</span></span><br><span class="line"><span class="formula"> "App<span class="tag">\<span class="name">Providers</span></span><span class="tag">\<span class="name">RouteServiceProvider</span></span>" => []</span></span><br><span class="line"><span class="formula"> "bootstrapped: Illuminate<span class="tag">\<span class="name">Foundation</span></span><span class="tag">\<span class="name">Bootstrap</span></span><span class="tag">\<span class="name">RegisterProviders</span></span>" => []</span></span><br><span class="line"><span class="formula"> "bootstrapping: Illuminate<span class="tag">\<span class="name">Foundation</span></span><span class="tag">\<span class="name">Bootstrap</span></span><span class="tag">\<span class="name">BootProviders</span></span>" => []</span></span><br><span class="line"><span class="formula"> "bootstrapped: Illuminate<span class="tag">\<span class="name">Foundation</span></span><span class="tag">\<span class="name">Bootstrap</span></span><span class="tag">\<span class="name">BootProviders</span></span>" => []</span></span><br><span class="line"><span class="formula"> ]</span></span><br></pre></td></tr></table></figure></p><h4 id="DetectEnvironment"><a href="#DetectEnvironment" class="headerlink" title="DetectEnvironment"></a>DetectEnvironment</h4><p>环境变量配置。使用插件 vlucas/phpdotenv<br>读取.env 文件,将配置写入$_ENV, 和 $_SERVER 变量中<br><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="comment">//DetectEnvironment 中的bootstrap 方法</span></span><br><span class="line"><span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">bootstrap</span><span class="params">(Application $app)</span></span></span><br><span class="line"><span class="function"></span>{ </span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> Dotenv::load($app->environmentPath(), $app->environmentFile());</span><br><span class="line"> } <span class="keyword">catch</span> (InvalidArgumentException $e) {</span><br><span class="line"> <span class="comment">//</span></span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//默认设置环境为生产环境</span></span><br><span class="line"> $app->detectEnvironment(<span class="function"><span class="keyword">function</span> <span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> env(<span class="string">'APP_ENV'</span>, <span class="string">'production'</span>);</span><br><span class="line"> });</span><br><span class="line">}</span><br><span class="line"><span class="comment">//Dotenv中的load 和 setEnvironmentVariable</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="function"><span class="keyword">function</span> <span class="title">load</span><span class="params">($path, $file = <span class="string">'.env'</span>)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> .......</span><br><span class="line"> $lines = file($filePath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); <span class="comment">//跳过空行</span></span><br><span class="line"> <span class="keyword">foreach</span> ($lines <span class="keyword">as</span> $line) {</span><br><span class="line"> <span class="comment">//忽略#号注释</span></span><br><span class="line"> <span class="keyword">if</span> (strpos(trim($line), <span class="string">'#'</span>) === <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (strpos($line, <span class="string">'='</span>) !== <span class="keyword">false</span>) {</span><br><span class="line"> <span class="keyword">static</span>::setEnvironmentVariable($line);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="function"><span class="keyword">function</span> <span class="title">setEnvironmentVariable</span><span class="params">($name, $value = null)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">list</span>($name, $value) = <span class="keyword">static</span>::normaliseEnvironmentVariable($name, $value);</span><br><span class="line"> ....... <span class="comment">// 判断环境变量是否可以覆盖重写</span></span><br><span class="line"> putenv(<span class="string">"$name=$value"</span>);</span><br><span class="line"> $_ENV[$name] = $value;</span><br><span class="line"> $_SERVER[$name] = $value;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><h4 id="LoadConfiguration"><a href="#LoadConfiguration" class="headerlink" title="LoadConfiguration"></a>LoadConfiguration</h4><p>框架Config读取配置。<br><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="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">bootstrap</span><span class="params">(Application $app)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> $items = [];</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (file_exists($cached = $app->getCachedConfigPath())) {</span><br><span class="line"> $items = <span class="keyword">require</span> $cached;</span><br><span class="line"></span><br><span class="line"> $loadedFromCache = <span class="keyword">true</span>;</span><br><span class="line"> }</span><br><span class="line"> $app->instance(<span class="string">'config'</span>, $config = <span class="keyword">new</span> Repository($items));</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (! <span class="keyword">isset</span>($loadedFromCache)) {</span><br><span class="line"> <span class="keyword">$this</span>->loadConfigurationFiles($app, $config);</span><br><span class="line"> }</span><br><span class="line"> date_default_timezone_set($config[<span class="string">'app.timezone'</span>]);<span class="comment">// 时区</span></span><br><span class="line"></span><br><span class="line"> mb_internal_encoding(<span class="string">'UTF-8'</span>); <span class="comment">// 编码</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><br>config 最终对应为 Repository类。其items 属性保存了config 目录下的文件名(key)、配置内容(value)组成的数组键值对。<br><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">Repository(<span class="class"><span class="keyword">class</span>)</span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line">items: <span class="keyword">array</span>:<span class="number">7</span> [▼</span><br><span class="line"> <span class="string">"app"</span> => <span class="keyword">array</span>:<span class="number">10</span> [▶]</span><br><span class="line"> <span class="string">"auth"</span> => <span class="keyword">array</span>:<span class="number">5</span> [▼</span><br><span class="line"><span class="string">"driver"</span> => <span class="string">"eloquent"</span></span><br><span class="line"><span class="string">"model"</span> => <span class="string">"App\User"</span></span><br><span class="line"><span class="string">"table"</span> => <span class="string">"users"</span></span><br><span class="line"><span class="string">"password"</span> => <span class="keyword">array</span>:<span class="number">3</span> [▼</span><br><span class="line"><span class="string">"email"</span> => <span class="string">"auth.passwords.link"</span></span><br><span class="line"><span class="string">"table"</span> => <span class="string">"password_resets"</span></span><br><span class="line"><span class="string">"expire"</span> => <span class="number">10</span></span><br><span class="line">]</span><br><span class="line"> <span class="string">"remember_token_expire"</span> => <span class="number">14400</span></span><br><span class="line"> ]</span><br><span class="line"> <span class="string">"cache"</span> => <span class="keyword">array</span>:<span class="number">3</span> [▶]</span><br><span class="line"> <span class="string">"database"</span> => <span class="keyword">array</span>:<span class="number">5</span> [▶]</span><br><span class="line"> <span class="string">"mail"</span> => <span class="keyword">array</span>:<span class="number">9</span> [▶]</span><br><span class="line"> <span class="string">"session"</span> => <span class="keyword">array</span>:<span class="number">12</span> [▶]</span><br><span class="line"> <span class="string">"view"</span> => <span class="keyword">array</span>:<span class="number">2</span> [▶]</span><br><span class="line"> ]</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><h4 id="ConfigureLogging"><a href="#ConfigureLogging" class="headerlink" title="ConfigureLogging"></a>ConfigureLogging</h4><p>日志写入配置。使用monolog/monolog拓展。为容器添加log 对应的绑定实例(Monolog),并设置默认写入路径<br><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="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">bootstrap</span><span class="params">(Application $app)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> $log = <span class="keyword">$this</span>->registerLogger($app);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> ($app->hasMonologConfigurator()) {</span><br><span class="line"> call_user_func(</span><br><span class="line"> $app->getMonologConfigurator(), $log->getMonolog()</span><br><span class="line"> );</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="comment">//为$log,即Monolog设日志内容的写入路径,默认为storage/logs/laravel.log</span></span><br><span class="line"> <span class="keyword">$this</span>->configureHandlers($app, $log); </span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"> <span class="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">registerLogger</span><span class="params">(Application $app)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> $app->instance(<span class="string">'log'</span>, $log = <span class="keyword">new</span> Writer(</span><br><span class="line"> <span class="keyword">new</span> Monolog($app->environment()), $app[<span class="string">'events'</span>])</span><br><span class="line"> );</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> $log;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><h4 id="HandleExceptions"><a href="#HandleExceptions" class="headerlink" title="HandleExceptions"></a>HandleExceptions</h4><p>自定义异常处理Handler<br><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="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">bootstrap</span><span class="params">(Application $app)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">$this</span>->app = $app;</span><br><span class="line"></span><br><span class="line"> error_reporting(<span class="number">-1</span>);</span><br><span class="line"></span><br><span class="line"> set_error_handler([<span class="keyword">$this</span>, <span class="string">'handleError'</span>]); <span class="comment">// 错误处理</span></span><br><span class="line"></span><br><span class="line"> set_exception_handler([<span class="keyword">$this</span>, <span class="string">'handleException'</span>]); <span class="comment">//抛出异常处理</span></span><br><span class="line"></span><br><span class="line"> register_shutdown_function([<span class="keyword">$this</span>, <span class="string">'handleShutdown'</span>]); <span class="comment">//程序异常终止处理</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (! $app->environment(<span class="string">'testing'</span>)) {</span><br><span class="line"> ini_set(<span class="string">'display_errors'</span>, <span class="string">'Off'</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><h4 id="RegisterFacades"><a href="#RegisterFacades" class="headerlink" title="RegisterFacades"></a>RegisterFacades</h4><p>注册门面类 ,通过class_alias 为一个类创建别名<br><blockquote><footer><strong>class_alias</strong><cite><a href="http://php.net/manual/zh/function.class-alias.php" target="_blank" rel="noopener">php.net/manual/zh/function.class-alias.php</a></cite></footer></blockquote><br><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="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">bootstrap</span><span class="params">(Application $app)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> Facade::clearResolvedInstances();</span><br><span class="line"></span><br><span class="line"> Facade::setFacadeApplication($app); <span class="comment">//为Facede 注入aPP实例</span></span><br><span class="line"> </span><br><span class="line"> AliasLoader::getInstance($app->make(<span class="string">'config'</span>)->get(<span class="string">'app.aliases'</span>))->register();</span><br><span class="line">}</span><br><span class="line"><span class="comment">//执行</span></span><br><span class="line"> spl_autoload_register([<span class="keyword">$this</span>, <span class="string">'load'</span>], <span class="keyword">true</span>, <span class="keyword">true</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">load</span><span class="params">($alias)</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="keyword">$this</span>->aliases[$alias])) {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> class_alias(<span class="keyword">$this</span>->aliases[$alias], $alias);<span class="comment">//门面类实现方式</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><h4 id="RegisterProviders"><a href="#RegisterProviders" class="headerlink" title="RegisterProviders"></a>RegisterProviders</h4><p>读取config配置中的app.providers,对数组中所有进行注册<br><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="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">bootstrap</span><span class="params">(Application $app)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> $app->registerConfiguredProviders();</span><br><span class="line">}</span><br><span class="line"><span class="comment">// app类</span></span><br><span class="line"><span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">registerConfiguredProviders</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="comment">//读取bootstrap/cache/services.json缓存</span></span><br><span class="line"> $manifestPath = <span class="keyword">$this</span>->getCachedServicesPath();</span><br><span class="line"> (<span class="keyword">new</span> ProviderRepository(<span class="keyword">$this</span>, <span class="keyword">new</span> Filesystem, $manifestPath))</span><br><span class="line"> ->load(<span class="keyword">$this</span>->config[<span class="string">'app.providers'</span>]);</span><br><span class="line">}</span><br><span class="line"><span class="comment">// ProviderRepository</span></span><br><span class="line"><span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">load</span><span class="params">(array $providers)</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"> $manifest = <span class="keyword">$this</span>->loadManifest();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">$this</span>->shouldRecompile($manifest, $providers)) {</span><br><span class="line"> $manifest = <span class="keyword">$this</span>->compileManifest($providers);</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//触发加载的服务</span></span><br><span class="line"> <span class="keyword">foreach</span> ($manifest[<span class="string">'when'</span>] <span class="keyword">as</span> $provider => $events) {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">$this</span>->registerLoadEvents($provider, $events);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">foreach</span> ($manifest[<span class="string">'eager'</span>] <span class="keyword">as</span> $provider) {</span><br><span class="line"> <span class="keyword">$this</span>->app->register(<span class="keyword">$this</span>->createProvider($provider)); <span class="comment">// 注册时,写入fire 记录</span></span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//延迟加载的服务</span></span><br><span class="line"> <span class="keyword">$this</span>->app->addDeferredServices($manifest[<span class="string">'deferred'</span>]);</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><h4 id="BootProviders"><a href="#BootProviders" class="headerlink" title="BootProviders"></a>BootProviders</h4><p>启用所有ServerProvider的boot方法。这块的关注点在于RouteServiceProvider<br><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">boot</span><span class="params">()</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>->booted) {</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//调用booting中 class 的回调</span></span><br><span class="line"> <span class="keyword">$this</span>->fireAppCallbacks(<span class="keyword">$this</span>->bootingCallbacks);</span><br><span class="line"> <span class="comment">//过程极度漫长,尤其是routeServiceProvicer</span></span><br><span class="line"> array_walk(<span class="keyword">$this</span>->serviceProviders, <span class="function"><span class="keyword">function</span> <span class="params">($p)</span> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->bootProvider($p);</span><br><span class="line"> });</span><br><span class="line"> <span class="keyword">$this</span>->booted = <span class="keyword">true</span>;</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">$this</span>->fireAppCallbacks(<span class="keyword">$this</span>->bootedCallbacks);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">bootProvider</span><span class="params">(ServiceProvider $provider)</span></span></span><br><span class="line"><span class="function"></span>{ </span><br><span class="line"> <span class="comment">//如果serviceProvider 存在boot方法, 则执行其boot方法</span></span><br><span class="line"> <span class="comment">//(通过APP\providers\ class的boot执行 parent::boot() ,即foundation\support\providers)</span></span><br><span class="line"> <span class="keyword">if</span> (method_exists($provider, <span class="string">'boot'</span>)) {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->call([$provider, <span class="string">'boot'</span>]);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><br>RouteServiceProvider最终会在map方法进行路由载入<br><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="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">map</span><span class="params">(Router $router)</span></span></span><br><span class="line"><span class="function"></span>{ </span><br><span class="line"> $router->group([<span class="string">'namespace'</span> => <span class="keyword">$this</span>->namespace], <span class="function"><span class="keyword">function</span> <span class="params">($router)</span> </span>{</span><br><span class="line"> <span class="keyword">require</span> app_path(<span class="string">'Http/routes.php'</span>); <span class="comment">//app/Http/routes.php</span></span><br><span class="line"> });</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>]]></content>
<categories>
<category> laravel源码学习分享 </category>
</categories>
<tags>
<tag> bootstrap </tag>
<tag> bootProviders </tag>
<tag> RouteServiceProvider </tag>
</tags>
</entry>
<entry>
<title>request实例</title>
<link href="/request-instance.html"/>
<url>/request-instance.html</url>
<content type="html"><![CDATA[<p>  通过index.php继续往下走, Request实例的初始化<br><figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$request</span> = Illuminate\Http\<span class="symbol">Request:</span><span class="symbol">:capture</span>()</span><br></pre></td></tr></table></figure><br>使用拓展 Symfony/Http-Foundation<br><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="keyword">use</span> <span class="title">Symfony</span>\<span class="title">Component</span>\<span class="title">HttpFoundation</span>\<span class="title">Request</span> <span class="title">as</span> <span class="title">SymfonyRequest</span>;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="function"><span class="keyword">function</span> <span class="title">capture</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="comment">//允许请求方法重新,主要用于DELETE PUT方法的最终转换</span></span><br><span class="line"> <span class="keyword">static</span>::enableHttpMethodParameterOverride();</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//根据php超级全局变量$_SERVER的数据,创建一个Request 类</span></span><br><span class="line"> $fromGlobals = SymfonyRequest::createFromGlobals(); </span><br><span class="line"> <span class="comment">//最终返回 Illuminate\Http\Request类</span></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">static</span>::createFromBase($fromGlobals); </span><br><span class="line">}</span><br></pre></td></tr></table></figure><br><a id="more"></a><br>①设置enableHttpMethodParameterOverride = true, 因为框架在设置DELETE PUT 等请求时,实质是通过表单伪造完成的《input type=”hidden” name=”_method” value=”PUT”》<br><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="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">getMethod</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">null</span> === <span class="keyword">$this</span>->method) {</span><br><span class="line"> <span class="keyword">$this</span>->method = strtoupper(<span class="keyword">$this</span>->server->get(<span class="string">'REQUEST_METHOD'</span>, <span class="string">'GET'</span>));</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (<span class="string">'POST'</span> === <span class="keyword">$this</span>->method) {</span><br><span class="line"> <span class="keyword">if</span> ($method = <span class="keyword">$this</span>->headers->get(<span class="string">'X-HTTP-METHOD-OVERRIDE'</span>)) {</span><br><span class="line"> <span class="keyword">$this</span>->method = strtoupper($method);</span><br><span class="line"> } <span class="keyword">elseif</span> (<span class="keyword">self</span>::$httpMethodParameterOverride) {</span><br><span class="line"> <span class="keyword">$this</span>->method = strtoupper(<span class="keyword">$this</span>->request->get(<span class="string">'_method'</span>, <span class="keyword">$this</span>->query->get(<span class="string">'_method'</span>, <span class="string">'POST'</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="keyword">return</span> <span class="keyword">$this</span>->method;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><br>②$fromGlobals实质是SymfonyRequest类。<font color="#f56954">其属性值本身源于PHP自带的超级全局变量$_SERVER。</font></p><p>③最后是通过duplicate方法,将SymfonyRequest属性值复制到Illuminate\Http\Request类中,并最终返回。</p>]]></content>
<categories>
<category> laravel源码学习分享 </category>
</categories>
<tags>
<tag> Request实例 </tag>
</tags>
</entry>
<entry>
<title>Application初始化</title>
<link href="/app-instance.html"/>
<url>/app-instance.html</url>
<content type="html"><![CDATA[<p>  之前已完成Application的自动引入,本篇分享下面这行代码的实现细节 </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">$app = <span class="keyword">new</span> Illuminate\Foundation\Application(</span><br><span class="line"> realpath(<span class="keyword">__DIR__</span>.<span class="string">'/../'</span>) <span class="comment">//参数 basePath 为项目根目录的<绝对路径></span></span><br><span class="line">);</span><br></pre></td></tr></table></figure><h4 id="构造函数"><a href="#构造函数" class="headerlink" title="构造函数"></a>构造函数</h4><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="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span><span class="params">($basePath = null)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">$this</span>->registerBaseBindings(); </span><br><span class="line"></span><br><span class="line"> <span class="keyword">$this</span>->registerBaseServiceProviders(); <span class="comment">//绑定基本服务(event router)</span></span><br><span class="line"> </span><br><span class="line"> <span class="keyword">$this</span>->registerCoreContainerAliases(); <span class="comment">//设置容器别名</span></span><br><span class="line"> </span><br><span class="line"> <span class="keyword">if</span> ($basePath) {</span><br><span class="line"> <span class="keyword">$this</span>->setBasePath($basePath); <span class="comment">//设置基本项目的关键文件</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><a id="more"></a><h4 id="注册基本绑定"><a href="#注册基本绑定" class="headerlink" title="注册基本绑定"></a>注册基本绑定</h4><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="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">registerBaseBindings</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">static</span>::setInstance(<span class="keyword">$this</span>); <span class="comment">//使用单例模式,将静态属性instance 赋值为自身实例</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">$this</span>->instance(<span class="string">'app'</span>, <span class="keyword">$this</span>);<span class="comment">//将属性instances['app'] 赋值为自身实例</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">$this</span>->instance(<span class="string">'Illuminate\Container\Container'</span>, <span class="keyword">$this</span>); <span class="comment">//同上</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="注册基本服务"><a href="#注册基本服务" class="headerlink" title="注册基本服务"></a>注册基本服务</h4><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">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">registerBaseServiceProviders</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>->register(<span class="keyword">new</span> EventServiceProvider(<span class="keyword">$this</span>)); <span class="comment">//注册事件服务, app实例作为参数</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">$this</span>->register(<span class="keyword">new</span> RoutingServiceProvider(<span class="keyword">$this</span>)); <span class="comment">//注册路由服务 ,app实例作为参数</span></span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><h5 id="app的register方法"><a href="#app的register方法" class="headerlink" title="app的register方法"></a>app的register方法</h5><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="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">register</span><span class="params">($provider, $options = [], $force = false)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (($registered = <span class="keyword">$this</span>->getProvider($provider)) && ! $force) {</span><br><span class="line"> <span class="keyword">return</span> $registered;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//如果是字符串,则解析为对应的class实例</span></span><br><span class="line"> <span class="keyword">if</span> (is_string($provider)) {</span><br><span class="line"> $provider = <span class="keyword">$this</span>->resolveProviderClass($provider); <span class="comment">// 即$provider = new $provider()</span></span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//执行服务提供者的注册方法</span></span><br><span class="line"> $provider->register();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">foreach</span> ($options <span class="keyword">as</span> $key => $value) {</span><br><span class="line"> <span class="keyword">$this</span>[$key] = $value;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//将服务提供者标记为已注册</span></span><br><span class="line"> <span class="keyword">$this</span>->markAsRegistered($provider);</span><br><span class="line"> <span class="comment">//如果所有的服务已经启用(一个后续环节)之后,重新注册时,会执行该$provider的boot方法</span></span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">$this</span>->booted) {</span><br><span class="line"> <span class="keyword">$this</span>->bootProvider($provider);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> $provider;</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">getProvider</span><span class="params">($provider)</span></span></span><br><span class="line"><span class="function"></span>{ </span><br><span class="line"> $name = is_string($provider) ? $provider : get_class($provider);</span><br><span class="line"> <span class="comment">// Arr类(Illuminate\Support\Arr,以及Illuminate\Support\Str),是框架数组,字符串帮助函数的底层实现</span></span><br><span class="line"> <span class="comment">//由于这里使用first()方法,意味着只要找到数组中符合条件的第一项,就返回。注册同一个服务,返回最早注册的。</span></span><br><span class="line"> <span class="keyword">return</span> Arr::first(<span class="keyword">$this</span>->serviceProviders, <span class="function"><span class="keyword">function</span> <span class="params">($key, $value)</span> <span class="title">use</span> <span class="params">($name)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> $value <span class="keyword">instanceof</span> $name;</span><br><span class="line"> });</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h5 id="Event的register方法"><a href="#Event的register方法" class="headerlink" title="Event的register方法"></a>Event的register方法</h5><p>执行上文中 <strong>$provider->register()</strong> 方法,即执行new EventServiceProvider($this) 中的register()方法。<font color="#f56954">所有的服务提供者基本都是为当前服务绑定一个可以返回 真正执行者 (如这里的Dispatcher实例) 的闭包。服务的注册方法中一般会存在一个或多个绑定。</font><br><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><br><span class="line"><span class="comment">//所有的服务提供者都会继承ServiceProvider,也就是都有一个特定属性app,即Application实例</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">EventServiceProvider</span> <span class="keyword">extends</span> <span class="title">ServiceProvider</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">register</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>->app->singleton(<span class="string">'events'</span>, <span class="function"><span class="keyword">function</span> <span class="params">($app)</span> </span>{</span><br><span class="line"> <span class="comment">// 获取分配器Dispatcher实例,并为该实例设置队列解析者</span></span><br><span class="line"> <span class="keyword">return</span> (<span class="keyword">new</span> Dispatcher($app))->setQueueResolver(<span class="function"><span class="keyword">function</span> <span class="params">()</span> <span class="title">use</span> <span class="params">($app)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> $app->make(<span class="string">'Illuminate\Contracts\Queue\Factory'</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></pre></td></tr></table></figure></p><h5 id="singleton方法"><a href="#singleton方法" class="headerlink" title="singleton方法"></a>singleton方法</h5><p>  容器singleton方法,<font color="#f56954">使用单例模式注册,即多次执行make(‘events’),返回的同一个实例</font><br><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="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">singleton</span><span class="params">($abstract, $concrete = null)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">$this</span>->bind($abstract, $concrete, <span class="keyword">true</span>); <span class="comment">// 第三个参数true, 表示shared 共享</span></span><br><span class="line">}</span><br><span class="line"><span class="comment">//当前注册服务添加至bindings中</span></span><br><span class="line"><span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">bind</span><span class="params">($abstract, $concrete = null, $shared = false)</span></span></span><br><span class="line"><span class="function"></span>{ </span><br><span class="line"> <span class="keyword">$this</span>->bindings[$abstract] = compact(<span class="string">'concrete'</span>, <span class="string">'shared'</span>);</span><br><span class="line">}</span><br><span class="line"><span class="comment">//容器中的make方法</span></span><br><span class="line"><span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">make</span><span class="params">()</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="keyword">$this</span>->instances[$abstract])) {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->instances[$abstract];</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//通过singleton,shared = true, 之后make会之前返回已经实例化好的类</span></span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">$this</span>->isShared($abstract)) { </span><br><span class="line"> <span class="keyword">$this</span>->instances[$abstract] = $object;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><h5 id="Router的register方法"><a href="#Router的register方法" class="headerlink" title="Router的register方法"></a>Router的register方法</h5><p>RoutingServiceProvider的register方法一共有6个注册<br>  registerRouter      注册路由<br>  registerUrlGenerator   url 生成器<br>  registerRedirector     路由重定向<br>  registerResponseFactory 响应<br>  <del>registerPsrRequest   框架底层本身不存在绑定所需返回类,需要特有拓展</del><br>  <del>registerPsrRespons   框架底层本身不存在绑定所需返回类</del></p><p>这里只分析registerRouter,关注点放在<font color="#f56954">$this->app[‘router’]</font> 和 <font color="#f56954">share()方法</font><br><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="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">registerRouter</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>->app[<span class="string">'router'</span>] = <span class="keyword">$this</span>->app->share(<span class="function"><span class="keyword">function</span> <span class="params">($app)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> Router($app[<span class="string">'events'</span>], $app);</span><br><span class="line"> });</span><br><span class="line"> <span class="comment">//又会触发build, 执行所绑定的闭包 </span></span><br><span class="line"> </span><br><span class="line">}</span><br></pre></td></tr></table></figure><br>  $this->app 是Application类,因为该类implements了PHP自带的ArrayAccess接口,所以支持对象以数组方式使用。$this->app[key] = value,这种赋值运算会触发offsetSet方法(最终为容器bing方法),而$this->app[key],这种取值运算会触发offsetGet方法(最终为容器make方法)。<br><blockquote><footer><strong>ArrayAccess接口</strong><cite><a href="http://php.net/manual/en/class.arrayaccess.php" target="_blank" rel="noopener">php.net/manual/en/class.arrayaccess.php</a></cite></footer></blockquote><br><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="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">share</span><span class="params">(Closure $closure)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="function"><span class="keyword">function</span> <span class="params">($container)</span> <span class="title">use</span> <span class="params">($closure)</span> </span>{</span><br><span class="line"> <span class="keyword">static</span> $object;</span><br><span class="line"> <span class="keyword">if</span> (is_null($object)) {</span><br><span class="line"> $object = $closure($container);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> $object;</span><br><span class="line"> };</span><br><span class="line">}</span><br></pre></td></tr></table></figure><br>  首次执行make 时, router 所绑定的闭包函数的static $object 会变成 new Router($this->app[‘events’], $this->app),再次make 会直接返回 已存在的实例$object。与singleton比较相似。</p><h4 id="注册基本路径"><a href="#注册基本路径" class="headerlink" title="注册基本路径"></a>注册基本路径</h4><p>  将基本文件路径存入容器的instances[]中,方便通过make(‘path’)直接获取<br><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="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">bindPathsInContainer</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>->instance(<span class="string">'path'</span>, <span class="keyword">$this</span>->path()); <span class="comment">// $this->basePath.DIRECTORY_SEPARATOR.'app'</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">foreach</span> ([<span class="string">'base'</span>, <span class="string">'config'</span>, <span class="string">'database'</span>, <span class="string">'lang'</span>, <span class="string">'public'</span>, <span class="string">'storage'</span>] <span class="keyword">as</span> $path) {</span><br><span class="line"> <span class="keyword">$this</span>->instance(<span class="string">'path.'</span>.$path, <span class="keyword">$this</span>->{$path.<span class="string">'Path'</span>}());</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><div style="height: 200px;padding: 0px 0px; "><br> <img src="/images/base_instance.png" align="left" style="margin:-20px 0px auto 0px;float: left;"><br> <div style="float: right; width:400px;height: 180px;margin-top: -70px; text-align:left;"><br> app实例初始化结束后,其instances属性:<br> ①app自身<br> ②容器实例<br> ③事件实例<br> ④基本文件根路径<br> </div><br></div><p>最后绑定核心类、控制台、异常处理类,这种写法的实质是 如通过执行make(‘Illuminate\Contracts\Http\Kernel’),返回App\Http\Kernel类<br><figure class="highlight ruby"><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">$app->singleton(</span><br><span class="line"> Illuminate\Contracts\Http\Kernel::<span class="class"><span class="keyword">class</span>,</span></span><br><span class="line"> App\Http\Kernel::<span class="class"><span class="keyword">class</span></span></span><br><span class="line">);</span><br><span class="line"></span><br><span class="line">$app->singleton(</span><br><span class="line"> Illuminate\Contracts\Console\Kernel::<span class="class"><span class="keyword">class</span>,</span></span><br><span class="line"> App\Console\Kernel::<span class="class"><span class="keyword">class</span></span></span><br><span class="line">);</span><br><span class="line"></span><br><span class="line">$app->singleton(</span><br><span class="line"> Illuminate\Contracts\Debug\ExceptionHandler::<span class="class"><span class="keyword">class</span>,</span></span><br><span class="line"> App\Exceptions\Handler::<span class="class"><span class="keyword">class</span></span></span><br><span class="line">);</span><br><span class="line"><span class="keyword">return</span> $app;</span><br></pre></td></tr></table></figure></p>]]></content>
<categories>
<category> laravel源码学习分享 </category>
</categories>
<tags>
<tag> app实例 </tag>
<tag> singleton方法 </tag>
<tag> share方法 </tag>
</tags>
</entry>
<entry>
<title>容器与控制反转</title>
<link href="/container.html"/>
<url>/container.html</url>
<content type="html"><![CDATA[<p>  由于这些都是一些概念性的内容,为了方便理解,我们需要尽可能的用具象的东西来说明。在此之前,先简单说明一下<font color="LightCoral">控制反转</font> 和 <font color="LightCoral">依赖注入</font>:<br><blockquote><p>控制反转 (Inversion Of Control,Ioc),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。依赖注入 (Dependency Injection, DI),只是其实现方式的其中一种,还有一种叫”依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体,将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。</p></blockquote>关于依赖查找,个人表示并没研究过,这里我们主要理解 依赖注入 。下面通过比较用 <font color="LightSlateBlue">传统方式、工厂模式、容器 </font>去实例化类,并满足该类所有属性需求 ,实现过程中的不同,从而理解容器。<br><a id="more"></a><br>假设我们现在有一个目标:制造一辆山寨汽车 Car</p><ul><li>需要有轮胎 Tyre</li><li>需要有窗户 window</li><li>需要有座椅 Seat<h4 id="传统方式"><a href="#传统方式" class="headerlink" title="传统方式"></a>传统方式</h4><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="comment">// 汽车</span></span><br><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="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="keyword">$this</span>->tyre = <span class="keyword">new</span> Tyre();</span><br><span class="line"><span class="keyword">$this</span>->window = <span class="keyword">new</span> window();</span><br><span class="line"><span class="keyword">$this</span>->seat = <span class="keyword">new</span> Seat();</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="class"><span class="keyword">class</span> <span class="title">Tyre</span></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">window</span></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">Seat</span></span>{}</span><br></pre></td></tr></table></figure></li></ul><p>关于这种传统模式的问题:<br>① 在实际情况中,一个类如果有很多个需要实例化的属性,那我们就需要一直使用new 运算符,严重影响代码可读性<br>② 因为某种原因,其中一个属性类名发生了变化,如Seat变成了Chair,那么只要有用到new Seat的地方都要改<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></pre></td><td class="code"><pre><span class="line"><span class="comment">// 汽车</span></span><br><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="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="keyword">$this</span>->tyre = <span class="keyword">new</span> Tyre();</span><br><span class="line"></span><br><span class="line">$sander = <span class="keyword">new</span> Sander();</span><br><span class="line">$glass = <span class="keyword">new</span> Glass($sander); <span class="comment">//窗户需要打磨</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">$this</span>->window = <span class="keyword">new</span> window($glass); <span class="comment">// 窗户需要玻璃, 如果还有更深层次呢?</span></span><br><span class="line"><span class="keyword">$this</span>->seat = <span class="keyword">new</span> Seat();</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="class"><span class="keyword">class</span> <span class="title">Tyre</span></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">window</span></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">($glass)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">$this</span>->glass = $glass;</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="class"><span class="keyword">class</span> <span class="title">Seat</span></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">Glass</span></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">($sander)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">$this</span>->sander = $sander;</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="class"><span class="keyword">class</span> <span class="title">Sander</span></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><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">Car</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="keyword">$this</span>->factory = <span class="keyword">new</span> Factory();</span><br><span class="line"></span><br><span class="line">$list = [<span class="string">'Tyre'</span>,<span class="string">'Window'</span>,<span class="string">'Seat'</span>];</span><br><span class="line"><span class="keyword">foreach</span>($list <span class="keyword">as</span> $class)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">$this</span>->$class = <span class="keyword">$this</span>->factory->make($class,<span class="string">'param'</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="class"><span class="keyword">class</span> <span class="title">Factory</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">make</span><span class="params">($class,$param)</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> $class($param);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>工厂模式可以很好的解决传统模式中的①和②两个问题,工厂模式一般就已经可以满足正常开发需求;</p><h4 id="容器Container"><a href="#容器Container" class="headerlink" title="容器Container"></a>容器Container</h4><p>真正的主角登场。容器,顾名思义一个可以装东西的’盒子’。而里面装的是什么,正是我们需要考究的。<br><em>还是用制造山寨汽车举例,我需要一个容器,希望里面有轮胎、窗户、座椅,这样我可以直接用。那么我用了,下一个制造者可能有没得用了,当然这只是一种粗浅的比喻 。</em> <font color="#f56954">最好的解决办法就是容器里有的是制造轮胎、窗户的方法,我通过该方法,可以获取想要的实例。而容器本身就是一种高级工厂模式。</font><br><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">Container</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line">$protected $bindings; <span class="comment">// 存放实例制造所需的方法</span></span><br><span class="line">$protected $instances; <span class="comment">//存放已经实例化好的类</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">bind</span><span class="params">($abstract, Closure $concrete)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">$this</span>->bindings[$abstract] = $concrete;</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="function"><span class="keyword">function</span> <span class="title">make</span><span class="params">($abstract, $param=[])</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="keyword">$this</span>->bindings[$abstract])){ <span class="keyword">return</span> <span class="keyword">false</span>; }</span><br><span class="line">$concrete = <span class="keyword">$this</span>->bindings[$abstract];</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> $concrete(<span class="keyword">$this</span>,$param); </span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">$container = <span class="keyword">new</span> Container();</span><br><span class="line"></span><br><span class="line">$container->bind(<span class="string">'tyre'</span>,<span class="function"><span class="keyword">function</span><span class="params">($container,$param)</span></span>{</span><br><span class="line"><span class="keyword">return</span> <span class="keyword">new</span> Tyre;</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line">$container->bind(<span class="string">'window'</span>,<span class="function"><span class="keyword">function</span><span class="params">($container,$param)</span></span>{</span><br><span class="line">$glass = $container->make($param); <span class="comment">//通过容器实例化,并注入依赖</span></span><br><span class="line"><span class="keyword">return</span> <span class="keyword">new</span> window($glass);</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line">$car = <span class="keyword">new</span> Car();</span><br><span class="line">$car->tyre = $container->make(<span class="string">'tyre'</span>);</span><br><span class="line">$car->window = $container->make(<span class="string">'window'</span>,<span class="string">'glass'</span>);</span><br></pre></td></tr></table></figure></p><p>容器的简单形式就算完成。面临最大的问题就是依赖注入的处理不够好</p><h4 id="依赖自动注入"><a href="#依赖自动注入" class="headerlink" title="依赖自动注入"></a>依赖自动注入</h4><p>框架中容器一般是不会为小的属性类(如Window,Tyre,Glass等)单独绑定实现方法的。这种就会通过ReflectionClass类来实现<br><blockquote><footer><strong>PHP反射类文档</strong><cite><a href="http://www.php.net/manual/en/book.reflection.php" target="_blank" rel="noopener">www.php.net/manual/en/book.reflection.php</a></cite></footer></blockquote></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><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// 汽车</span></span><br><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="function"><span class="keyword">function</span> <span class="title">__construct</span><span class="params">($container)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">$this</span>->container = $container;</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">getWindow</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="comment">//window 在容器中并未绑定,通过Reflection来实现</span></span><br><span class="line"><span class="keyword">$this</span>->window = <span class="keyword">$this</span>->container->make(<span class="string">'window'</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="keyword">$this</span>->window;</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">getTyre</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>->tyre = <span class="keyword">$this</span>->container->make(<span class="string">'tyre'</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="class"><span class="keyword">class</span> <span class="title">Window</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">(Glass $glass)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">$this</span>->glass = $glass;</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">Tyre</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">($cons = <span class="number">123</span>)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">$this</span>->cons = $cons;</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">Glass</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><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Container</span> </span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"><span class="keyword">protected</span> $bindings;</span><br><span class="line"><span class="keyword">protected</span> $instances;</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">bind</span><span class="params">($abstract, Closure $concrete)</span> </span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">if</span> (is_null($concrete)) {</span><br><span class="line"> $concrete = $abstract;</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="keyword">$this</span>->bindings[$abstract] = $concrete;</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"> * 这里 拿 'window'举例</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">make</span><span class="params">($concrete ,array $parameters=[])</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="keyword">$this</span>->bindings[$concrete]))</span><br><span class="line">{</span><br><span class="line">$concrete = <span class="keyword">$this</span>->bindings[$concrete];</span><br><span class="line"><span class="keyword">return</span> $concrete(<span class="keyword">$this</span>, $parameters);</span><br><span class="line">}</span><br><span class="line">$reflector = <span class="keyword">new</span> ReflectionClass($concrete);</span><br><span class="line"> <span class="comment">//反射类是否可以实例化(如接口)</span></span><br><span class="line"> <span class="keyword">if</span> (! $reflector->isInstantiable()) {</span><br><span class="line"> $message = <span class="string">"该反射类不可实例化"</span>;</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="keyword">Exception</span>($message);</span><br><span class="line"> }</span><br><span class="line"> $constructor = $reflector->getConstructor();</span><br><span class="line"> <span class="keyword">if</span> (is_null($constructor)) { </span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> $concrete;</span><br><span class="line"> }</span><br><span class="line"> $dependencies = $constructor->getParameters(); <span class="comment">//获取构造函数被注入的依赖</span></span><br><span class="line"></span><br><span class="line"> $instances = []; <span class="comment">//获取依赖实例</span></span><br><span class="line"> <span class="keyword">foreach</span> ($dependencies <span class="keyword">as</span> $parameter) {</span><br><span class="line"> $dependency = $parameter->getClass();</span><br><span class="line"> <span class="keyword">if</span>(is_null($dependency))</span><br><span class="line"> {</span><br><span class="line"> $instances[] = $parameter->getDefaultValue();</span><br><span class="line"> }<span class="keyword">else</span></span><br><span class="line"> {</span><br><span class="line"> $instances[] = <span class="keyword">$this</span>->make($parameter->getClass()->name); <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> $reflector->newInstanceArgs($instances);</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">$c = <span class="keyword">new</span> Container();</span><br><span class="line"><span class="comment">// </span></span><br><span class="line"></span><br><span class="line">$c->bind(<span class="string">'car'</span>,<span class="function"><span class="keyword">function</span><span class="params">($c)</span></span>{</span><br><span class="line"><span class="keyword">return</span> <span class="keyword">new</span> Car($c);</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line">$car = $c->make(<span class="string">'car'</span>);</span><br><span class="line">$window = $car->getWindow(); </span><br><span class="line">var_dump($window);</span><br></pre></td></tr></table></figure><p>容器的概念理解好后,下一篇分享 application 类的实例化</p>]]></content>
<categories>
<category> laravel源码学习分享 </category>
</categories>
<tags>
<tag> 容器 </tag>
<tag> 控制反转 </tag>
<tag> 依赖注入 </tag>
</tags>
</entry>
<entry>
<title>Application.php的引入</title>
<link href="/app-require.html"/>
<url>/app-require.html</url>
<content type="html"><![CDATA[<p>   <font color="red">再次说明:整个代码学习都是基于index.php,进行代码逐行分析。 根据报错,对照完整的源码进行文件补充。</font></p><h5 id="引入composer自动载入"><a href="#引入composer自动载入" class="headerlink" title="引入composer自动载入"></a>引入composer自动载入</h5><p>关于composer自动载入包的安装,只要的我们的根目录下新建composer.json,并写入<br><figure class="highlight"><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">"require" : { </span><br><span class="line">"php" : ">=5.5.9"</span><br><span class="line">}</span><br></pre></td></tr></table></figure> 然后执行 <em>composer install</em> 命令</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="comment">/**** 当前文件位置 index.php ****/</span></span><br><span class="line"><span class="keyword">require</span> <span class="keyword">__DIR__</span>.<span class="string">'/../bootstrap/autoload.php'</span>; </span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/**** 当前文件位置 bootstrap/autoload.php ****/</span></span><br><span class="line">define(<span class="string">'LARAVEL_START'</span>, microtime(<span class="keyword">true</span>));</span><br><span class="line"></span><br><span class="line"><span class="keyword">require</span> <span class="keyword">__DIR__</span>.<span class="string">'/../vendor/autoload.php'</span>; <span class="comment">// 引入Composer autoload</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//获取编译缓存,所有用到的类及方法的集合文件</span></span><br><span class="line"></span><br><span class="line">$compiledPath = <span class="keyword">__DIR__</span>.<span class="string">'/cache/compiled.php'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (file_exists($compiledPath)) { </span><br><span class="line"> <span class="keyword">require</span> $compiledPath;</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>到这里,类文件的自动载入工作就算基本完成了。<br><a id="more"></a></p><h5 id="引入Application-php"><a href="#引入Application-php" class="headerlink" title="引入Application.php"></a>引入Application.php</h5><p>接下来会看到的代码就是<br><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">$app = <span class="keyword">new</span> Illuminate\Foundation\Application(</span><br><span class="line"> realpath(<span class="keyword">__DIR__</span>.<span class="string">'/../'</span>)</span><br><span class="line">);</span><br></pre></td></tr></table></figure></p><p>  首先需要创建 <em>vendor/laravel/framework/src/Illuminate/Foundation/Application.php </em>文件(建议为空类,测试自动引入是否成功)。那么通过composer自动引入Application.php? 通过composer.json,定义路径,然后执行 <em>composer dump-autoload </em>命令。</p><figure class="highlight prolog"><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="string">"autoload"</span>: {</span><br><span class="line"> <span class="string">"classmap"</span>: [</span><br><span class="line"> <span class="string">"vendor/laravel/framework/src/Illuminate"</span>,</span><br><span class="line"> <span class="string">"app"</span></span><br><span class="line"></span><br><span class="line"> ],</span><br><span class="line"> <span class="string">"files"</span> : [</span><br><span class="line"> <span class="string">"vendor/laravel/framework/src/Illuminate/Support/helpers.php"</span>,</span><br><span class="line"> <span class="string">"vendor/laravel/framework/src/Illuminate/Foundation/helpers.php"</span></span><br><span class="line"> ],</span><br><span class="line"> <span class="string">"psr-4"</span>: {</span><br><span class="line"> <span class="string">"App\\"</span>: <span class="string">"app/"</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>之后所有的文件载入不再做赘述,可自行参考以下资料:</p><blockquote><footer><strong>PHP中的PSR规范</strong><cite><a href="https://www.jianshu.com/p/b33155c15343" target="_blank" rel="noopener">www.jianshu.com/p/b33155c15343</a></cite></footer></blockquote><blockquote><footer><strong>composer文档</strong><cite><a href="https://docs.phpcomposer.com/01-basic-usage.html#Autoloading" target="_blank" rel="noopener">docs.phpcomposer.com/01-basic-usage.html#Autoloading</a></cite></footer></blockquote>]]></content>
<categories>
<category> laravel源码学习分享 </category>
</categories>
<tags>
<tag> composer自动引入 </tag>
<tag> autoload </tag>
</tags>
</entry>
<entry>
<title>框架目录结构</title>
<link href="/tree-directory.html"/>
<url>/tree-directory.html</url>
<content type="html"><![CDATA[<p>  laravel 框架按最简单的目录结构理解就是 <strong>核心文件目录</strong> 和 <strong>插件文件目录</strong>。假设这所有的目录结构,最开始我们是并不清楚的,然后随着index.php的运行,报错的出现与不断解决,整个目录结构及用途就会一点点慢慢清晰起来。<br>  当运行,第一个报错肯定是 bootstrap/autoload.php 文件不存在, 然后我们就按照另一份源码缺哈补哈。随着这个报错的解决,自然就会清楚,app\bootstrap文件夹,到目前为止有提供composer 自动载入类的作用。下面是整个框架的目录结构图<br><a id="more"></a></p><h4 id="核心文件目录"><a href="#核心文件目录" class="headerlink" title="核心文件目录"></a>核心文件目录</h4><figure class="highlight routeros"><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></pre></td><td class="code"><pre><span class="line">├── laravel 根目录</span><br><span class="line">├── app</span><br><span class="line">│ ├──<span class="built_in"> Console</span>artisan控制台</span><br><span class="line">│ ├── Events事件注册</span><br><span class="line">│ ├── Exceptions异常处理</span><br><span class="line">│ ├── Httphttp处理</span><br><span class="line">│ | ├── Controllers 控制器</span><br><span class="line">│ | ├── Middleware 中间件</span><br><span class="line">| | ├── Requests 表单请求类FormRequest,用于表单数据快捷验证</span><br><span class="line">│ | └── routes 路由文件</span><br><span class="line">│ ├── Jobs队列任务</span><br><span class="line">│ ├── Listeners事件监听</span><br><span class="line">│ ├── Policies用户操作授权控制</span><br><span class="line">│ └── Providers基本服务提供类</span><br><span class="line">│ └── User.php 默认用户认证模型</span><br><span class="line">|</span><br><span class="line">├── bootstrap 项目启动文件</span><br><span class="line">│ ├── cache 启动文件缓存,主要是services.php,记录服务提供类的即时、延迟、特定加载信息</span><br><span class="line">│ ├── app.php 创建整个项目Application类实例</span><br><span class="line">│ └── autoload 引入composer自动载入类</span><br><span class="line">|</span><br><span class="line">├──<span class="built_in"> config </span> 配置文件</span><br><span class="line">|</span><br><span class="line">├── database数据库迁移</span><br><span class="line">│ </span><br><span class="line">├── public公共资源目录,包含入口文件及资源文件,js、css、image等</span><br><span class="line">|</span><br><span class="line">├── resources 视图文件</span><br><span class="line">│ </span><br><span class="line">├── storage</span><br><span class="line">│ ├── app 其他文件存储目录</span><br><span class="line">│ ├── framework</span><br><span class="line">| | ├── cache 文件缓存目录</span><br><span class="line">| | ├── sessions 会话缓存目录</span><br><span class="line">| | └── views视图缓存目录</span><br><span class="line">│ └── logs 日志文件默认存储目录</span><br><span class="line">├── vendor 拓展文件目录</span><br><span class="line">└── .env 环境变量配置 </span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="拓展文件目录"><a href="#拓展文件目录" class="headerlink" title="拓展文件目录"></a>拓展文件目录</h4><figure class="highlight crmsh"><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">├── laravel/vendor</span><br><span class="line">├── bin 作为php-parse,phpunit,phpspec,psysh 指令执行目录</span><br><span class="line">├── classpreloader用于生成包含特定用例所需的所有类的单个PHP脚本,不依赖于自动加载</span><br><span class="line">├── composer<span class="string">"composer自动加载类"</span></span><br><span class="line">├── danielstjules 具有多字节支持的字符串操作库,如strtoupper('fòôbàř');</span><br><span class="line">├── dnoegel dnoegel/php-xdg-base-dir, XDG目录规范</span><br><span class="line">├── doctrinewww.doctrine-project.org 用于数据库迁移schema生成,数据字段修改</span><br><span class="line">├── fzaninottofzaninotto/faker 用于生成测试数据的PHP库</span><br><span class="line">├── hamcrest一个匹配Hamcrest的官方PHP端口的拓展,具体用途不详</span><br><span class="line">├── jakub-onderka控制台高亮PHP代码</span><br><span class="line">├── jeremeamia用于序列化闭包和匿名函数的PHP库。</span><br><span class="line">├── laravel <span class="string">"最核心拓展"</span></span><br><span class="line">├── league <span class="string">"league/flysystem 本地磁盘文件读写驱动"</span></span><br><span class="line">├── mockery PHP模拟对象框架,用于PHP单元测试</span><br><span class="line">├── monolog <span class="string">"php日志记录库,可以日志发送至files, sockets, inboxes, databases等"</span></span><br><span class="line">├── mtdowlingPHP cron表达式解析器</span><br><span class="line">├── nestbot nesbot/carbon 时间处理插件</span><br><span class="line">├── nikic 包名nikic/php-parser。 PHP词法分析、语法分析,生成一颗抽象语法树。</span><br><span class="line">| PHP内置函数token_get_all()可进行词法分析。在视图编译会用到</span><br><span class="line">├── paragonie</span><br><span class="line">├── phpdocumentor<span class="string">"paragonie/random_compat 安全码生成库,如默认session_id 生成"</span></span><br><span class="line">├── phpspec 可以按PSR标准创建文件夹结构(我目前所知)</span><br><span class="line">├── phpunit php单元测试 </span><br><span class="line">├── predis redis拓展</span><br><span class="line">├── psr <span class="string">"psr/log ,定制日志记录接口规范"</span></span><br><span class="line">├── psys psy/psysh php交互式控制台, 可以写php代码直接运行</span><br><span class="line">├── sebastian 不知道不明了 (°ー°〃)</span><br><span class="line">├── swiftmailer Mail 邮件发送插件</span><br><span class="line">├── symfony <span class="string">"symfony全家桶,在vender/laravel中require 。 重要插件库"</span></span><br><span class="line">├── vlucas <span class="string">"vlucas/phpdotenv 用于ENV环境变量的读取及设置"</span></span><br><span class="line">└── webmozart 通过Assert来测试方法的输入和输出,有点类似于<span class="keyword">Node</span>.<span class="title">js</span> 的Assert</span><br></pre></td></tr></table></figure><h5 id="framework目录"><a href="#framework目录" class="headerlink" title="framework目录"></a>framework目录</h5><p><font color="#f56954" size="3">/vendor/laravel/framework 可以说是整个laravel框架最最核心的目录,vendor目录下所有其他拓展基本都是为其服务<font><br><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><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">├── laravel/vendor/laravel/framework</span><br><span class="line">├── composer.json '记录了核心常用插件使用信息'</span><br><span class="line">└── src 遵循PSR-4目录规范</span><br><span class="line"> └── Illuminate </span><br><span class="line"> ├── Auth 用户认证,Access 、Password、AuthManager</span><br><span class="line"> ├── Broadcasting 广播(没使用过)</span><br><span class="line"> ├── Bus 任务分配(没使用过)</span><br><span class="line"> ├── <span class="keyword">Cache</span> 缓存操作类</span><br><span class="line"> ├── Config 配置操作类</span><br><span class="line"> ├── Console 控制台</span><br><span class="line"> ├── <span class="keyword">Container</span> <span class="string">'容器(实现Ioc),框架核心设计思想之一'</span></span><br><span class="line"> ├── Contracts <span class="string">'契约类(interface),定义app的几乎所有接口规范'</span></span><br><span class="line"> ├── Cookie 响应头Cookie</span><br><span class="line"> ├── <span class="keyword">Database</span> 数据库</span><br><span class="line"> ├── Enctyption 加密,解密类,如用于session_id加密和解密</span><br><span class="line"> ├── <span class="keyword">Events</span> 事件处理</span><br><span class="line"> ├── Filesystem 文件处理</span><br><span class="line"> ├── Foundation <span class="string">'基本文件类,如Application类'</span></span><br><span class="line"> ├── Hashing <span class="keyword">hash</span>加密类</span><br><span class="line"> ├── <span class="keyword">Http</span> request,response 处理 </span><br><span class="line"> ├── <span class="keyword">log</span> <span class="keyword">Log</span>\Write类</span><br><span class="line"> ├── Mail 邮件处理</span><br><span class="line"> ├── Pagination 分页</span><br><span class="line"> ├── Pipenation <span class="string">'管道类,核心设计思想之一,主要用于middleware处理'</span></span><br><span class="line"> ├── Queue 任务队列</span><br><span class="line"> ├── Redis <span class="string">'Redis操作,底层默认是必须安装 predis插件的'</span></span><br><span class="line"> ├── Routing 路由</span><br><span class="line"> ├── <span class="keyword">Session</span> 会话</span><br><span class="line"> ├── Support 其他帮助类,如帮助函数,视图错误信息处理</span><br><span class="line"> ├── <span class="keyword">Translation</span> 验证信息转换,需要resources/lang 语言包</span><br><span class="line"> ├── <span class="keyword">Validation</span> 数据验证类</span><br><span class="line"> └── <span class="keyword">View</span> 视图处理,模板编译</span><br><span class="line"></span><br></pre></td></tr></table></figure></font></font></p>]]></content>
<categories>
<category> laravel源码学习分享 </category>
</categories>
<tags>
<tag> laravel目录结构 </tag>
</tags>
</entry>
<entry>
<title>laravel源码(开篇)</title>
<link href="/summary.html"/>
<url>/summary.html</url>
<content type="html"><![CDATA[<h4 id="学习心得"><a href="#学习心得" class="headerlink" title="学习心得"></a>学习心得</h4><p>  想要真正了解一套框架,是需要花很多心思和时间的,就像想要了解一个的人。<font color="#f56954">坚持源于喜欢,仅此而已!</font><br>  我个人的学习方法就是拿public\index.php,也就是项目的入口文件当做突破口,就当做没有任何手册。当然在此之前,个人觉得还是要有一定的框架使用经验。此学习分享纯属个人见解,不好之处欢迎批评指正!<br>  <em>版本说明: laravel5.1, php 5.6.4</em><br><a id="more"></a><br>   <em>index.php 从头到尾不会超过10行代码,总流程 <font color="#0099ff">创建App实例、接收request、获取route、返回response</font>,结束</em></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="keyword">require</span> <span class="keyword">__DIR__</span>.<span class="string">'/../bootstrap/autoload.php'</span>; </span><br><span class="line"></span><br><span class="line">$app = <span class="keyword">require_once</span> <span class="keyword">__DIR__</span>.<span class="string">'/../bootstrap/app.php'</span>;</span><br><span class="line"></span><br><span class="line">$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);</span><br><span class="line"></span><br><span class="line">$response = $kernel->handle(</span><br><span class="line"> $request = Illuminate\Http\Request::capture()</span><br><span class="line">);</span><br><span class="line"></span><br><span class="line">$response->send(); <span class="comment">// 发送响应</span></span><br><span class="line"></span><br><span class="line">$kernel->terminate($request, $response);</span><br></pre></td></tr></table></figure><h4 id="具体实现"><a href="#具体实现" class="headerlink" title="具体实现"></a>具体实现</h4><p>  准备一份laravel 源码,再准备一个自己的项目。最开始我们的项目是这样的<br><figure class="highlight stylus"><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">├── app 根目录</span><br><span class="line"> └── public </span><br><span class="line"> ├── index<span class="selector-class">.php</span> 拷贝源码</span><br><span class="line"> └── <span class="selector-class">.htaccess</span> 拷贝源码</span><br></pre></td></tr></table></figure><br>将web服务器指定到该目录下,本地执行。<font color="LightCoral" size="4">随着系统报错,故事就开始了…</font> </p>]]></content>
<categories>
<category> laravel源码学习分享 </category>
</categories>
<tags>
<tag> laravel源码 </tag>
</tags>
</entry>
</search>