-
Notifications
You must be signed in to change notification settings - Fork 0
/
atom.xml
1751 lines (1644 loc) · 337 KB
/
atom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title><![CDATA[崔叔隐世记]]></title>
<subtitle><![CDATA[独立之精神, 自由之思想!]]></subtitle>
<link href="/atom.xml" rel="self"/>
<link href="http://sphenginx.github.io/"/>
<updated>2017-12-14T09:14:19.536Z</updated>
<id>http://sphenginx.github.io/</id>
<author>
<name><![CDATA[Sphenginx]]></name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title><![CDATA[MySQL 判断点是否在指定多边形区域内]]></title>
<link href="http://sphenginx.github.io/2017/12/13/mysql-polygon/"/>
<id>http://sphenginx.github.io/2017/12/13/mysql-polygon/</id>
<published>2017-12-13T12:03:01.000Z</published>
<updated>2017-12-14T09:14:19.536Z</updated>
<content type="html"><![CDATA[<p>近期接了个 <code>网格区域管理</code> 的需求, 具体实现为: 首先建立几个百度地图的坐标点, 其次可以在百度地图上画一个多边形,把需要的坐标点圈在多边形里面。 本文将介绍使用mysql判断点是否在指定多边形区域内的方法,提供完整流程。</p>
<h2 id="u521B_u5EFA_u6D4B_u8BD5_u8868"><a href="#u521B_u5EFA_u6D4B_u8BD5_u8868" class="headerlink" title="创建测试表"></a>创建测试表</h2><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="operator"><span class="keyword">CREATE</span> <span class="keyword">TABLE</span> <span class="string">`zone`</span> (</span><br><span class="line"> <span class="string">`id`</span> <span class="built_in">int</span>(<span class="number">10</span>) <span class="keyword">unsigned</span> <span class="keyword">NOT</span> <span class="literal">NULL</span> AUTO_INCREMENT,</span><br><span class="line"> <span class="string">`polygongeo`</span> <span class="built_in">text</span> <span class="keyword">NOT</span> <span class="literal">NULL</span>,</span><br><span class="line"> PRIMARY <span class="keyword">KEY</span> (<span class="string">`id`</span>)</span><br><span class="line">) <span class="keyword">ENGINE</span>=MYISAM <span class="keyword">DEFAULT</span> <span class="keyword">CHARSET</span>=utf8;</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>注意:空间索引只能在存储引擎为MYISAM的表中创建(MySQL5.7版本以上可以用Innodb引擎)</p>
</blockquote>
<h2 id="u63D2_u5165_u591A_u8FB9_u5F62_u6570_u636E"><a href="#u63D2_u5165_u591A_u8FB9_u5F62_u6570_u636E" class="headerlink" title="插入多边形数据"></a>插入多边形数据</h2><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="operator"><span class="keyword">insert</span> <span class="keyword">into</span> zone(polygongeo) <span class="keyword">values</span>(<span class="string">'POLYGON((1 1,1 5,5 5,5 1,1 1))'</span>);</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>注意:<code>polygongeo</code>包含的点必须是个闭环(第一个点 和 最后一个点必须一致) </p>
</blockquote>
<h2 id="u5224_u65AD_u70B9_u662F_u5426_u5728_u591A_u8FB9_u5F62_u533A_u57DF"><a href="#u5224_u65AD_u70B9_u662F_u5426_u5728_u591A_u8FB9_u5F62_u533A_u57DF" class="headerlink" title="判断点是否在多边形区域"></a>判断点是否在多边形区域</h2><h3 id="u6D4B_u8BD5_POINT_283_2C_4_29"><a href="#u6D4B_u8BD5_POINT_283_2C_4_29" class="headerlink" title="测试 POINT(3, 4)"></a>测试 POINT(3, 4)</h3><blockquote>
<p><code>where</code> 查询可以用 <code>MBRWithin</code> 或者 <code>MBRCONTAINS</code>(参数位置交换)</p>
</blockquote>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="operator"><span class="keyword">select</span> AsText(polygongeo) <span class="keyword">from</span> zone <span class="keyword">where</span> MBRWithin(POLYGONFROMTEXT(<span class="string">'POINT(3 4)'</span>), GEOMFROMTEXT(polygongeo));</span></span><br></pre></td></tr></table></figure>
<p>输出: POLYGON((1 1,1 5,5 5,5 1,1 1))<br>表示点 POINT(3, 4) 在多边形区域内 </p>
<h3 id="u6D4B_u8BD5_POINT_286_2C_1_29"><a href="#u6D4B_u8BD5_POINT_286_2C_1_29" class="headerlink" title="测试 POINT(6, 1)"></a>测试 POINT(6, 1)</h3><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="operator"><span class="keyword">select</span> AsText(polygongeo) <span class="keyword">from</span> zone <span class="keyword">where</span> MBRWithin(POLYGONFROMTEXT(<span class="string">'POINT(6 1)'</span>), GEOMFROMTEXT(polygongeo));</span></span><br></pre></td></tr></table></figure>
<p>输出: 空<br>表示点 POINT(6, 1) 在多边形区域外 </p>
<h2 id="u53C2_u8003_u8D44_u6599"><a href="#u53C2_u8003_u8D44_u6599" class="headerlink" title="参考资料"></a>参考资料</h2><ul>
<li><ol>
<li><a href="http://blog.csdn.net/fdipzone/article/details/53896842" target="_blank" rel="external">mysql 判断点是否在指定多边形区域内</a> </li>
</ol>
</li>
<li><ol>
<li><a href="http://www.voidcn.com/article/p-wpvigmsq-bkg.html" target="_blank" rel="external">mongodb 判断坐标是否在指定多边形区域内的方法</a> </li>
</ol>
</li>
<li><ol>
<li><a href="http://www.voidcn.com/article/p-agdcdenf-da.html" target="_blank" rel="external">怎么判断一个点是否在多边形区域内</a></li>
</ol>
</li>
<li><ol>
<li><a href="https://www.chengxiaobai.cn/sql/mysql-according-to-the-latitude-and-longitude-search-sort.html" target="_blank" rel="external">mysql根据经纬度查找排序</a></li>
</ol>
</li>
</ul>
<p>总结:mysql空间查询并不很适合地图坐标,因此查询地图坐标可以使用mongodb实现,参考:<a href="http://blog.csdn.net/fdipzone/article/details/52374630" target="_blank" rel="external">《mongodb 判断坐标是否在指定多边形区域内的方法》</a></p>
]]></content>
<summary type="html">
<![CDATA[<p>近期接了个 <code>网格区域管理</code> 的需求, 具体实现为: 首先建立几个百度地图的坐标点, 其次可以在百度地图上画一个多边形,把需要的坐标点圈在多边形里面。 本文将介绍使用mysql判断点是否在指定多边形区域内的方法,提供完整流程。</p>
<h2 id=]]>
</summary>
<category term="MySQL" scheme="http://sphenginx.github.io/tags/MySQL/"/>
<category term="polygon" scheme="http://sphenginx.github.io/tags/polygon/"/>
<category term="日薪越亿" scheme="http://sphenginx.github.io/categories/%E6%97%A5%E8%96%AA%E8%B6%8A%E4%BA%BF/"/>
</entry>
<entry>
<title><![CDATA[成熟之解BY余秋雨]]></title>
<link href="http://sphenginx.github.io/2017/06/18/grew/"/>
<id>http://sphenginx.github.io/2017/06/18/grew/</id>
<published>2017-06-18T12:03:01.000Z</published>
<updated>2017-06-21T03:03:17.601Z</updated>
<content type="html"><![CDATA[<h2 id="u5E8F"><a href="#u5E8F" class="headerlink" title="序"></a>序</h2><blockquote>
<p> 高中时语文老师推荐读余秋雨的书,自此欲罢不能,然随着年龄的增长,工作压力和生活琐事日益增多,竟渐渐迷失自己,生活工作的一塌糊涂。 今日又读到此文,心有所悟,特整理到博客,以此自勉。 惟愿有生之年早日达到此高度。</p>
</blockquote>
<h2 id="u6B63_u6587"><a href="#u6B63_u6587" class="headerlink" title="正文"></a>正文</h2><p><strong>成熟是一种明亮而不刺眼的光辉,一种圆润而不腻耳的音响,一种不再需要对别人察言观色的从容,一种终于停止向周围申诉求告的大气,一种不理会哄闹的微笑,一种洗刷了偏激的淡漠,一种无须声张的厚实,一种能够看得很远却又并不陡峭的高度。</strong></p>
<p>我一直认为,某个时期,某个社会,即使所有的青年人和老年人都中魔了,只要中年人不荒唐,事情就坏不到哪里去。</p>
<p>在中年,青涩的生命之果变得如此丰满,喧闹的青春冲撞沉淀成了雍容华贵,连繁重的社会责任也有可能溶解为日常的生活情态。</p>
<p>到了该自立的年岁还不知道精神上的自立,这是中国很多中年人的共同悲剧。</p>
<p>天天期待着上级的指示、群众的意见、家人的说法,然后才能跨出每一步——这是尚未精神断奶的标志。</p>
<p>最可怕的是,谁也没有断奶,而社会上又没有那么多上好的乳汁,因此开始了对各种伪劣饮料的集体吮吸。在一片响亮而整齐的吮吸声上面,是那些爬满皱纹却还未苍老的脸。</p>
<p>中年人最容易犯的毛病,是把一切希望都寄托于自己的老年。</p>
<p>如今天天节衣缩食、不苟言笑、忍气吞声,都是在争取着一个有尊严、有资财、有自由的老人。</p>
<p>但是,我们无数次看到了,一个窝囊的中年抵达不到一个欢快的老年。这正像江河,一个浑浊的上段不可能带来一个清澈的下段。</p>
<p>习惯了郁闷的,只能继续郁闷;习惯了卑琐的,只能保持卑琐。而且,由于暮色苍茫间的体力不支、友朋散失,郁闷只能更加郁闷,卑琐只能更加卑琐。</p>
<p>只有在中年树起独立的桅杆,扬起高高的白帆唱出响亮的歌声,才会有好风为你鼓劲,群鸥为你引路,找到一个个都在欢迎你的安静港湾,供你细细选择。</p>
<p>中年人的坚守,应该从观点上升到人格,而人格难以言表。在中年人眼前,大批的对峙消解了,早年的对手失踪了,昨天的敌人无恨了,更多的是把老老少少各色人等照顾在自己身边。</p>
<p>请不要小看这“照顾”二字,中年人的魅力至少有一半与此相关。</p>
<p>中年人失去方寸的主要特征是忘记了自己的年龄,一会儿要别人像对待青年那样关爱自己,一会儿又要别人像对待老人那样尊敬自己,明明一个大男人却不能对任何稍稍大一点的问题作出决定,频频找领导倾诉衷肠,出了什么事情又逃得远远的,不敢负一点责任。在家里,他们训斥孩子就像顽童吵架,没有一点身为人父的慈爱和庄重;对妻子,他们也会轻易地倾泻出自己的精神垃圾来酿造痛苦,全然忘却自己是这座好不容易建造起来的情感楼宇的顶梁柱;甚至对年迈的父母,他们也会任性赌气,极不公平地伤害着已经走向衰弱的身影。</p>
<p>西方一位哲人说,只有饱经沧桑的老人才会领悟真正的人生哲理,同样一句话,出自老人之口比出自青年之口厚重百倍。对此,我不能全然苟同。</p>
<p>哲理产生在两种相反力量的周旋之中,因此它更垂青于中年。世上一切杰出的哲学家都在中年完成了他们的思想体系,便是证据。</p>
<p>人生就是这样,年轻时,怨恨自己年轻,年迈时,怨恨自己年迈,这倒常常促使中年处于一种相对冷静的疏离状态和评判状态,然后一边慰抚年幼者,一边慰抚年老者。我想,中年在人生意义上的魅力,就在于这双向疏离和双向慰抚吧。</p>
<p>因双向疏离,他们变得洒脱和沉静;因双向慰抚,他们变得亲切和有力。但是,也正因为此,他们有时又会感到烦心和惆怅,他们还余留着告别天真岁月的伤感,又迟早会产生暮岁将至的预感。他们置身于人生凯旋的中心点,环视四周,思前想后,不能不感慨万千。</p>
<p>老年是如诗的年岁。这种说法不是为了奉承长辈。</p>
<p>中年太实际、太繁忙,在整体上算不得诗。青年时代常常被诗化,但青年时代的诗太多激情而缺少意境,按我的标准,缺少意境就算不得好诗。<br>只有到了老年,沉重的使命已经卸除,生活的甘苦也已了然,万丈红尘已移到远处,静下来的周际环境和放慢了的生命节奏加在一起,构成了一种总结性、归纳性的轻微和声,诗的意境出现了。</p>
<p>除了极少数命苦的老人,老年岁月总是比较悠闲。老年人可能不会写诗或已经不再写诗,但他们却以诗的方式生存着。看街市忙碌,看后辈来去,看庭花凋零,看春草又绿,而思绪则时断时续、时喜时悲、时真时幻。</p>
<p>当然会产生越来越多的生理障碍,但即便障碍也构成一种让人仰视的形态,就像我们面对枝干斑驳的老树,老树上的枯藤残叶,也会感到诗的存在。<br>中青年的世界的强悍,也经常需要一些苍老的手来救助。平时不容易见到,一旦有事则及时伸出,救助过后又立即消失,神龙见首不见尾。这是一种早已退出社会主体的隐性文化和柔性文化,隐柔中沉积着岁月的硬度,能使后人一时启悟,如与天人对晤。老年的魅力,理应在这样的高位上偶尔显露。不要驱使,不要强求,不要哄抬,只让它们成为人生的写意笔墨,似淡似浓,似有似无。</p>
<p>长江的流程也像人的一生,在起始阶段总是充满着奇瑰和险峻,到了即将了结一生的晚年,怎么也得走向平缓和实在。</p>
<p>不要因为害怕被别人误会而等待理解。现代生活各自独立、万象共存。东家的柳树矮一点,不必向路人解释本来有长高的可能;西家的槐树高一点,也不必向邻居说明自己并没有独占风水的企图。</p>
<p>做一件新事,大家立即理解,那就不是新事;出一个高招,大家又立即理解,那也不是高招。没有争议的行为,肯定不是创造;没有争议的人物,肯定不是创造者。任何真正的创造都是对原有模式背离,对社会适应的突破,对民众习惯的挑战。如果眼巴巴地指望众人理解,创造的纯粹性必然会大大降低。平庸,正在前面招手。</p>
<p>回想一下,我们一生所做的比较像样的大事,连父母亲也未必能深刻理解。父母虽缔造了我们却理解不了我们,这便是进化。</p>
<p>人生不要光做加法。在人际交往上,经常减肥、排毒,才会轻轻松松地走以后的路。我们周围很多人,实在是被越积越厚的人际关系脂肪层堵塞住了,大家都能听到他们既满足又疲惫的喘息声。</p>
<p>向往峰巅,向往高度,结果峰巅只是一道刚能立足的狭地。不能横行,不能直走,只享一时俯视之乐,怎可长久驻足安坐?上已无路,下又艰难,我感到从未有过的孤独与惶恐。世间真正温煦的美色,都熨帖着大地,潜伏在深谷。君临万物的高度,到头来构成了自我嘲弄。我已看出了它的讥谑,于是急急地来试探下山的陡坡。人生真是艰难,不上高峰发现不了什么,上了高峰又抓住不了什么。看来,注定要不断地上坡下坡,上坡下坡。</p>
]]></content>
<summary type="html">
<![CDATA[<h2 id="u5E8F"><a href="#u5E8F" class="headerlink" title="序"></a>序</h2><blockquote>
<p> 高中时语文老师推荐读余秋雨的书,自此欲罢不能,然随着年龄的增长,工作压力和生活琐事日益增多,竟渐渐迷]]>
</summary>
<category term="余秋雨" scheme="http://sphenginx.github.io/tags/%E4%BD%99%E7%A7%8B%E9%9B%A8/"/>
<category term="成熟" scheme="http://sphenginx.github.io/tags/%E6%88%90%E7%86%9F/"/>
<category term="人生百态" scheme="http://sphenginx.github.io/categories/%E4%BA%BA%E7%94%9F%E7%99%BE%E6%80%81/"/>
</entry>
<entry>
<title><![CDATA[如何高效率的工作]]></title>
<link href="http://sphenginx.github.io/2016/10/14/how-to-work/"/>
<id>http://sphenginx.github.io/2016/10/14/how-to-work/</id>
<published>2016-10-14T12:03:01.000Z</published>
<updated>2016-11-08T09:38:00.061Z</updated>
<content type="html"><![CDATA[<h2 id="u4F60_u4E0D_u52AA_u529B_uFF0C_u8C01_u4E5F_u7ED9_u4E0D_u4E86_u4F60_u60F3_u8981_u7684_u751F_u6D3B"><a href="#u4F60_u4E0D_u52AA_u529B_uFF0C_u8C01_u4E5F_u7ED9_u4E0D_u4E86_u4F60_u60F3_u8981_u7684_u751F_u6D3B" class="headerlink" title="你不努力,谁也给不了你想要的生活"></a>你不努力,谁也给不了你想要的生活</h2><p>近被朋友圈刷屏了,简单的两个聊天记录,拿2000工资与20000工资的有什么区别?<strong>不论做什么,走心最重要!</strong></p>
<p>很多时候,我们失败都不是因为“硬件”不行,而是“软实力”欠佳。</p>
<p>若都是刚进公司的新人,大家能力是差不多的,随着时间的推移,情商高的往往都会比情商低的更容易得到赏识或提拔;所以,在技能相对稳定的情况下,我们一定要努力优化自己的处事方法。</p>
<p><strong>机会是留给有准备的人的,要别人推一把你才走一步,那你跟猪又有什么区别。</strong></p>
<hr>
<p>如图所示:3张图揭示人与人之间的差别!</p>
<h3 id="u60C5_u666F_u4E00"><a href="#u60C5_u666F_u4E00" class="headerlink" title="情景一"></a>情景一</h3><p><img src="http://sphenginx.github.io/images/work/1.png" alt="普通员工1"><br><img src="http://sphenginx.github.io/images/work/2.png" alt="普通员工2"></p>
<h3 id="u60C5_u666F_u4E8C"><a href="#u60C5_u666F_u4E8C" class="headerlink" title="情景二"></a>情景二</h3><p><img src="http://sphenginx.github.io/images/work/3.png" alt="优秀员工"></p>
<p>那么问题来了,</p>
<p>你能看出老员工和新员工之间的差别吗?</p>
<p><strong>如果你是老板,你更愿意聘用哪一个?</strong></p>
<h2 id="u4F18_u79C0_u5458_u5DE5_VS__u666E_u901A_u5458_u5DE5"><a href="#u4F18_u79C0_u5458_u5DE5_VS__u666E_u901A_u5458_u5DE5" class="headerlink" title="优秀员工 VS 普通员工"></a>优秀员工 VS 普通员工</h2><h3 id="u5173_u4E8E_u521A_u5165_u804C"><a href="#u5173_u4E8E_u521A_u5165_u804C" class="headerlink" title="关于刚入职"></a>关于刚入职</h3><table>
<thead>
<tr>
<th>普通员工</th>
<th>优秀员工</th>
</tr>
</thead>
<tbody>
<tr>
<td>看重工资的高低,在一无所长的前提下,没有想过学习丰富的工作经验和职业技能。</td>
<td>更看重宝贵的工作经验,踏踏实实的去学习业务技能,他相信只要有丰富的经验,以后无论到哪都能赢得高薪。</td>
</tr>
</tbody>
</table>
<h3 id="u5173_u4E8E_u5BF9_u5F85_u95EE_u9898"><a href="#u5173_u4E8E_u5BF9_u5F85_u95EE_u9898" class="headerlink" title="关于对待问题"></a>关于对待问题</h3><table>
<thead>
<tr>
<th>普通员工</th>
<th>优秀员工</th>
</tr>
</thead>
<tbody>
<tr>
<td>在工作中会发现各种各样的问题,对于问题他们往往以抱怨的态度去对待,而没有想方法去解决</td>
<td>在工作过程中,碰到问题会冷静的分析原因,并通过各种手段去解决,慢慢培养了一种解决问题的能力。</td>
</tr>
</tbody>
</table>
<h3 id="u5173_u4E8E_u6267_u884C_u529B"><a href="#u5173_u4E8E_u6267_u884C_u529B" class="headerlink" title="关于执行力"></a>关于执行力</h3><table>
<thead>
<tr>
<th>普通员工</th>
<th>优秀员工</th>
</tr>
</thead>
<tbody>
<tr>
<td>对于上司交代的问题本着能做就做,不能做就慢慢磨,执行效果较差。</td>
<td>上司交代的事情积极去解决,遇到问题会积极与上司沟通请示,执行效果好。</td>
</tr>
</tbody>
</table>
<h3 id="u5173_u4E8E_u4E2A_u6027"><a href="#u5173_u4E8E_u4E2A_u6027" class="headerlink" title="关于个性"></a>关于个性</h3><table>
<thead>
<tr>
<th>普通员工</th>
<th>优秀员工</th>
</tr>
</thead>
<tbody>
<tr>
<td>个性张扬,以自我为中心,不善于处理自己与同事领导的关系,往往给人一种很浮躁的感觉。</td>
<td>为人谦虚低调,能协调好与领导同事的关系,人际关系非常好。</td>
</tr>
</tbody>
</table>
<h3 id="u5173_u4E8E_u4E0B_u73ED_u540E"><a href="#u5173_u4E8E_u4E0B_u73ED_u540E" class="headerlink" title="关于下班后"></a>关于下班后</h3><table>
<thead>
<tr>
<th>普通员工</th>
<th>优秀员工</th>
</tr>
</thead>
<tbody>
<tr>
<td>下班后往往通过看电视、打打游戏等方式,度过一段休闲时光。</td>
<td>下班后会抽出时间回顾今天一天的工作内容,反思不足之处,并规划好第二天的工作内容。</td>
</tr>
</tbody>
</table>
<h3 id="u5173_u4E8E_u5DE5_u4F5C_u91CD_u70B9"><a href="#u5173_u4E8E_u5DE5_u4F5C_u91CD_u70B9" class="headerlink" title="关于工作重点"></a>关于工作重点</h3><table>
<thead>
<tr>
<th>普通员工</th>
<th>优秀员工</th>
</tr>
</thead>
<tbody>
<tr>
<td>工作杂乱无章,搞不清楚工作的核心内容,工作往往忙起来手足无措。</td>
<td>能很好的做好工作规划,找准核心工作内容,即使忙起来也能井然有序。</td>
</tr>
</tbody>
</table>
<h3 id="u5173_u4E8E_u5BA2_u6237_u6C9F_u901A"><a href="#u5173_u4E8E_u5BA2_u6237_u6C9F_u901A" class="headerlink" title="关于客户沟通"></a>关于客户沟通</h3><table>
<thead>
<tr>
<th>普通员工</th>
<th>优秀员工</th>
</tr>
</thead>
<tbody>
<tr>
<td>和客户沟通仅局限于单纯的送货收款,没有考虑到客户的实际需求,往往工作很辛苦,但是成效却很低。</td>
<td>能很好的处理与客户的客情关系,准确的找到客户实际需求,并结合客户需求达成销售。往往事半功倍。</td>
</tr>
</tbody>
</table>
<h3 id="u5173_u4E8E_u89C6_u754C"><a href="#u5173_u4E8E_u89C6_u754C" class="headerlink" title="关于视界"></a>关于视界</h3><table>
<thead>
<tr>
<th>普通员工</th>
<th>优秀员工</th>
</tr>
</thead>
<tbody>
<tr>
<td>缺乏宏观思考,经常纠结于某个终端问题,有时为了应对单个终端问题不惜提高政策从而影响了整个市场价格体系。</td>
<td>从市场整体角度出发,能很好的协调好各个渠道之间的市场问题,对于违反市场规律的个别终端坚决予以治理。</td>
</tr>
</tbody>
</table>
<h3 id="u5173_u4E8E_u6279_u8BC4"><a href="#u5173_u4E8E_u6279_u8BC4" class="headerlink" title="关于批评"></a>关于批评</h3><table>
<thead>
<tr>
<th>普通员工</th>
<th>优秀员工</th>
</tr>
</thead>
<tbody>
<tr>
<td>对忠言逆耳理解的不透彻,总认为自己想的是对的,把上司或资深前辈的意见或建议不当一回事,我行我素。</td>
<td>能谦虚的接受批评,认识到自己所犯错误在哪,并积极改正!</td>
</tr>
</tbody>
</table>
<h3 id="u5173_u4E8E_u804C_u4E1A_u89C4_u5212"><a href="#u5173_u4E8E_u804C_u4E1A_u89C4_u5212" class="headerlink" title="关于职业规划"></a>关于职业规划</h3><table>
<thead>
<tr>
<th>普通员工</th>
<th>优秀员工</th>
</tr>
</thead>
<tbody>
<tr>
<td>没有职业规划,对自己想要什么没概念,能做多久算多久,风风光光是一辈子,窝窝囊囊也是一辈子,得过且过。</td>
<td>有自己的职业规划,知道自己想要什么,也知道如何去努力。</td>
</tr>
</tbody>
</table>
<p><img src="http://sphenginx.github.io/images/work/0.png" alt="你不努力,谁也给不了你想要的生活"></p>
]]></content>
<summary type="html">
<![CDATA[<h2 id="u4F60_u4E0D_u52AA_u529B_uFF0C_u8C01_u4E5F_u7ED9_u4E0D_u4E86_u4F60_u60F3_u8981_u7684_u751F_u6D3B"><a href="#u4F60_u4E0D_u52AA_u529B_u]]>
</summary>
<category term="work" scheme="http://sphenginx.github.io/tags/work/"/>
<category term="工作" scheme="http://sphenginx.github.io/tags/%E5%B7%A5%E4%BD%9C/"/>
<category term="涨薪" scheme="http://sphenginx.github.io/tags/%E6%B6%A8%E8%96%AA/"/>
<category term="人生百态" scheme="http://sphenginx.github.io/categories/%E4%BA%BA%E7%94%9F%E7%99%BE%E6%80%81/"/>
</entry>
<entry>
<title><![CDATA[MySQL 中的 SELECT FOR UPDATE]]></title>
<link href="http://sphenginx.github.io/2016/09/18/select-for-update/"/>
<id>http://sphenginx.github.io/2016/09/18/select-for-update/</id>
<published>2016-09-18T08:03:01.000Z</published>
<updated>2016-09-19T03:20:05.418Z</updated>
<content type="html"><![CDATA[<h2 id="MySQL__u4F7F_u7528SELECT__u2026_FOR_UPDATE__u505A_u4E8B_u52A1_u5199_u5165_u524D_u7684_u786E_u8BA4"><a href="#MySQL__u4F7F_u7528SELECT__u2026_FOR_UPDATE__u505A_u4E8B_u52A1_u5199_u5165_u524D_u7684_u786E_u8BA4" class="headerlink" title="MySQL 使用SELECT … FOR UPDATE 做事务写入前的确认"></a>MySQL 使用SELECT … FOR UPDATE 做事务写入前的确认</h2><p>以MySQL 的InnoDB 为例,预设的Tansaction isolation level 为REPEATABLE READ,在SELECT 的读取锁定主要分为两种方式:</p>
<p><code>SELECT ... LOCK IN SHARE MODE</code> 、 <code>SELECT ... FOR UPDATE</code></p>
<p>这两种方式在事务(Transaction) 进行当中SELECT 到同一个数据表时,都必须等待其它事务数据被提交(Commit)后才会执行。而主要的不同在于LOCK IN SHARE MODE 在有一方事务要Update 同一个表单时很容易造成死锁 。</p>
<p>简单的说,如果SELECT 后面若要UPDATE 同一个表单,最好使用SELECT … UPDATE。</p>
<p>举个例子: 假设商品表单products 内有一个存放商品数量的quantity ,在订单成立之前必须先确定quantity 商品数量是否足够(quantity>0) ,然后才把数量更新为1。</p>
<p>不安全的做法:<br><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">SELECT quantity FROM products WHERE id=3; UPDATE products SET quantity = 1 WHERE id=3;</span><br></pre></td></tr></table></figure></p>
<p>为什么不安全呢?</p>
<p>少量的状况下或许不会有问题,但是大量的数据存取「铁定」会出问题。</p>
<p>如果我们需要在quantity>0 的情况下才能扣库存,假设程序在第一行SELECT 读到的quantity 是2 ,看起来数字没有错,但是当MySQL 正准备要UPDATE 的时候,可能已经有人把库存扣成0 了,但是程序却浑然不知,将错就错的UPDATE 下去了。</p>
<font color="red"><strong>因此必须透过的事务机制来确保读取及提交的数据都是正确的。</strong></font>
<p>于是我们在MySQL 就可以这样测试: (注1)<br><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">SET AUTOCOMMIT=0; BEGIN WORK; SELECT quantity FROM products WHERE id=3 FOR UPDATE; //此时products 数据中id=3 的数据被锁住(注3),其它事务必须等待此次事务 提交后才能执行 SELECT * FROM products WHERE id=3 FOR UPDATE; //(注2) 如此可以确保quantity 在别的事务读到的数字是正确的。 UPDATE products SET quantity = '1' WHERE id=3; COMMIT WORK;</span><br></pre></td></tr></table></figure></p>
<p>提交(Commit)写入数据库,products 解锁。</p>
<p>注1: BEGIN/COMMIT 为事务的起始及结束点,可使用二个以上的MySQL Command 视窗来交互观察锁定的状况。<br>注2: 在事务进行当中,只有SELECT … FOR UPDATE 或LOCK IN SHARE MODE 同一笔数据时会等待其它事务结束后才执行,一般SELECT … 则不受此影响。<br>注3: 由于InnoDB 预设为Row-level Lock,数据列的锁定可参考这篇。<br>注4: InnoDB 表单尽量不要使用LOCK TABLES 指令,若情非得已要使用,请先看官方对于InnoDB 使用LOCK TABLES 的说明,以免造成系统经常发生死锁。 </p>
<h2 id="MySQL_SELECT__u2026_FOR_UPDATE__u7684Row_Lock__u4E0ETable_Lock"><a href="#MySQL_SELECT__u2026_FOR_UPDATE__u7684Row_Lock__u4E0ETable_Lock" class="headerlink" title="MySQL SELECT … FOR UPDATE 的Row Lock 与Table Lock"></a>MySQL SELECT … FOR UPDATE 的Row Lock 与Table Lock</h2><blockquote>
<p> 上面介绍过SELECT … FOR UPDATE 的用法,不过锁定(Lock)的数据是判别就得要注意一下了。由于InnoDB 预设是Row-Level Lock,所以只有「明确」的指定主键,MySQL 才会执行Row lock (只锁住被选取的数据) ,否则MySQL 将会执行Table Lock (将整个数据表单给锁住)。</p>
</blockquote>
<p>举个例子:</p>
<p>假设有个表单products ,里面有id 跟name 二个栏位,id 是主键。</p>
<p>例1: (明确指定主键,并且有此数据,row lock)<br><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">SELECT * FROM products WHERE id='3' FOR UPDATE;</span><br></pre></td></tr></table></figure></p>
<p>例2: (明确指定主键,若查无此数据,无lock)<br><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">SELECT * FROM products WHERE id='-1' FOR UPDATE;</span><br></pre></td></tr></table></figure></p>
<p>例2: (无主键,table lock)<br><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">SELECT * FROM products WHERE name='Mouse' FOR UPDATE;</span><br></pre></td></tr></table></figure></p>
<p>例3: (主键不明确,table lock)<br><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">SELECT * FROM products WHERE id<>'3' FOR UPDATE;</span><br></pre></td></tr></table></figure></p>
<p>例4: (主键不明确,table lock)<br><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">SELECT * FROM products WHERE id LIKE '3' FOR UPDATE;</span><br></pre></td></tr></table></figure></p>
<p>注1: FOR UPDATE 仅适用于InnoDB,且必须在事务区块(BEGIN/COMMIT)中才能生效。<br>注2: 要测试锁定的状况,可以利用MySQL 的Command Mode ,开二个视窗来做测试。 </p>
<h2 id="u5176_u4ED6"><a href="#u5176_u4ED6" class="headerlink" title="其他"></a>其他</h2><p><a href="http://www.cnblogs.com/chenwenbiao/archive/2012/06/06/2537508.html" target="_blank" rel="external">转自 http://www.cnblogs.com/chenwenbiao/archive/2012/06/06/2537508.html</a></p>
]]></content>
<summary type="html">
<![CDATA[<h2 id="MySQL__u4F7F_u7528SELECT__u2026_FOR_UPDATE__u505A_u4E8B_u52A1_u5199_u5165_u524D_u7684_u786E_u8BA4"><a href="#MySQL__u4F7F_u7528SELEC]]>
</summary>
<category term="SELECT" scheme="http://sphenginx.github.io/tags/SELECT/"/>
<category term="Transaction" scheme="http://sphenginx.github.io/tags/Transaction/"/>
<category term="UPDATE" scheme="http://sphenginx.github.io/tags/UPDATE/"/>
<category term="mysql" scheme="http://sphenginx.github.io/tags/mysql/"/>
<category term="日薪越亿" scheme="http://sphenginx.github.io/categories/%E6%97%A5%E8%96%AA%E8%B6%8A%E4%BA%BF/"/>
</entry>
<entry>
<title><![CDATA[没有自制力的人有什么资格谈努力]]></title>
<link href="http://sphenginx.github.io/2016/08/08/do-not-work-hard-without-self-control/"/>
<id>http://sphenginx.github.io/2016/08/08/do-not-work-hard-without-self-control/</id>
<published>2016-08-08T01:27:40.000Z</published>
<updated>2016-08-09T01:45:49.596Z</updated>
<content type="html"><![CDATA[<h2 id="u4E00"><a href="#u4E00" class="headerlink" title="一"></a>一</h2><p>在周鱼的微博上看到他的一段话 <code>你可以追剧追一晚,只要你可以按时交上论文。你可以有丰富的夜生活,只要第二天你还能精神饱满的做好本职工作。放纵究竟是不是错,取决于你能不能为你的放纵负责。还是那句话,没有自制力的人不足以谈人生。</code></p>
<p>简直一语戳中,微博底下留言的人,无一不在哀嚎:<strong>膝盖中箭。</strong></p>
<p>自制力并不是什么新鲜词,说白了就是能够自觉控制自己的行动和情绪,集中注意力去达成自己原本的目标,而不受其他事情的干扰。</p>
<p>可是说起来容易,做起来真是太难了。</p>
<p>对大多数人来说,论文通常都是在deadline来临时,才匆匆忙忙拼凑完成的,而在这之前,是逍遥地看剧打游戏,约会逛街.</p>
<p>工作也是,今天做不完那就明天再做咯,反正工作永远也做不完,但聊天八卦要跟上、剁手购物不能错过秒杀,就连无效的朋友聚餐打着“社交”的旗号也不能不去……</p>
<p>每天冲击我们的信息太多,要做的事情也太多,我们的时间也被分割成碎片,然后被鸡零狗碎所侵占,自制力一点一点丧失。</p>
<p>我们每天好像做了很多事,但为什么最后又好像什么都没做?</p>
<p>每天好像忙得团团转,焦头烂额,但为什么最后还是顾此失彼?</p>
<p>我们立下一堆目标和计划,最后一个也没完成,我们急吼吼地说要多么努力,我们甚至还曾以为自己很努力,原来不过就是看上去很努力而已,最后的结果是,想要做的事,和本应该完成的事,都没有完成。</p>
<p>丧失自制力的后果是让我们对自己愤怒和质疑:我们有什么资格谈努力?</p>
<h2 id="u4E8C"><a href="#u4E8C" class="headerlink" title="二"></a>二</h2><p>我一个朋友,她的出版资格考试报了三回,可一次也没去,是的,她连考场都没进。</p>
<p>最后她生生从考初级熬到了可以考中级资格(毕业五年可以直接考中级),她无所谓地说:“哎呀,大不了我直接考中级不就得了。”</p>
<p>其实在我看来,她这话无异于自欺欺人,没有个三五年,她中级一样考不下来。</p>
<p>还记得我们一起报名考初级的情景。</p>
<p>她特别豪言壮语地立下学习目标,用多长时间复习《著作权法》,用多长时间学习出版实操知识点……时间规划得特别详细,如实按照这个计划来,备考的时间完全充足,甚至还可以在一轮复习完了后,再进行重点知识二轮复习。</p>
<p>但我们相约一起复习的第一个周末她就缺席了。原因是,她们公司不久后要组织去某著名山庄泡温泉,开季度总结会,她想买一套新的泳衣,顺便去商场逛街,趁着打折买买换季的新衣服。</p>
<p>她打电话邀我作陪,“乔乔,这个礼拜你陪我逛街,下个礼拜我们再开始学习好不好?”</p>
<p>我回她一个微信:“你这个行为就像口口声声喊着要减肥,却大吃大喝一顿,还美其名曰‘没有吃饱怎么有力气减肥呢’?”</p>
<p>让我意外,其实也意料之中的是,第二个周末,第三个周末,她总是有事,最后我只好独自一个人把最初定下的学习计划执行下去。</p>
<p>起初,她还有些负罪感,但次数多了也就轻易地,自我放纵了。</p>
<p>时间好像还有很多,所以眼前的诱惑,相比很久以后的考试来说,总是更有吸引力一些,也更重要一些。甚至,还会偶尔劝诫自己“人生苦短,不如快活”。</p>
<p>到最后,临到考前一个月,她才开始急了,临时抱佛脚各种狂背,可是那些法律条款和实操的内容,真不是一时半会儿就能背下来的。</p>
<p>压力太大,她一焦虑,效率低下,就又没有学习的动力了。最后索性连考场也没去。</p>
<p>是的,自制力差的人,永远都有最后一道护身符:大不了重头再来咯。</p>
<p>第二年,她一个人报考,考前依旧信誓旦旦:“去年没完成的计划,今年誓死也要完成。”</p>
<p>然而,第二年依旧,乃至第三年。</p>
<p>没有自制力的人,往往容易拖延症爆发,总是觉得时间还有,偶尔开个小差做点别的并不影响大局,直到deadline逼近时才乱了阵脚,才意识到自己过高地估计了自己hold住场面的能力。</p>
<p>其实我们没有完成的那些事,并不如我们放弃的那么轻松,它们在我们看来其实很重要,没写完的论文,没做完的工作,没有看完的书,没有认真听的报告,没有背的单词,而我们在开小差的时候,也并不是心无旁骛地快乐,心好像被悬着,我们真的有负罪感,没法好好地玩耍。</p>
<h2 id="u4E09"><a href="#u4E09" class="headerlink" title="三"></a>三</h2><p>真正地有自制力,是一种怎样的体验?<br> <br>学生时期,我们身边都有这样的学霸,他好像从来不用做作业,上课也不是埋头苦做笔记,下了课更不会呆在座位上,他们可以跟学渣一起聊热门的电视剧,讨论流行的八卦,他们……好像真的没有认真地学习,但我们永远不知道的是: 他们在家专注地写作业和复习,一个小时的学习效率顶别人两三个小时。自制力强,所以效率高;自制力强,所以学得快,玩儿得也嗨。<br> <br>毕业后,职场上我们身边也有这样的同事,他们好像上班也跟你一起聊天八卦,也偶尔偷偷淘宝刷微博,做PPT的时候也一样抱怨,赶不出方案时也一样抓狂,可是,和你不同的是,在最后他们好像总是被上天眷顾了一样,ppt做得比你好看,方案创意比你厉害,销售单子拿的比你多……你气不过,暗自嘟囔“他凭什么?”<br> <br>是啊,你刷微博是在看娱乐八卦和搞笑图片,别人是在找创意灵感;你抱怨这不行那不行的时候是在发脾气,别人却是在寻找解决问题的办法;你跟别人闲聊是真的在撩骚,而别人是通过聊天找到对方的销售需求……<br> <br><strong>自制力强的人,永远分得清楚主次,拎得清什么是本职,什么是玩乐。Deadline在没有自制力的人那里,是压力;在有自制力的人那里,是动力。这就是本质的区别。</strong></p>
<h2 id="u56DB"><a href="#u56DB" class="headerlink" title="四"></a>四</h2><p>你是不是也有这样的经历:<br> <br>家里书架上都摆满了你想看的书,可是一两个月前,你兴冲冲翻开的那本,现在还是停留在最初的几页;<br> <br>你下载了背英语单词的App扇贝,你原本是踌躇满志地制订了背考研单词的计划,一天背100个单词,几十天就搞定,可是单词你背了又忘,忘了又背,中间断了N天。<br> <br>你办了健身卡说是要去学游泳,可是别人的健身卡都要续费了,你的健身卡套餐却是在不用就要过期了……<br> <br>为什么开始的开始,我们本来是兴冲冲要去做的事,到后来总是不了了之地烂尾?<br> <br>或许,我们缺乏自制力的原因之一就是,其实你内心深处,就是不在意,不那么想做,所以才会动力缺缺,一直拖延,一旦有什么别的事情干扰,你的专注力就无法维持。<br> <br>而什么是努力?吃喝玩乐睡,用不着努力,这些事是本能,是消遣。<br> <br>称得上努力的事,都是反本能反人性的:为了完成一个课题,你会起早贪黑;为了做那份你最想做的工作,上下班路上四五个小时你也无所谓;为了看完你想看的书,你会放弃参加无效的社交聚会……<br> <br><strong>亦舒曾说过,爱得不够,才借口多多。简直真理,套用过来,你不想做一件事,才会给自己找这样那样的理由。</strong><br> <br>所以,当我们在谈努力的时候,请扪心自问一下,你到底有多想做那件事?到底有多想成功?为了做成那件事,你到底能做到怎样的付出和拼命?<br> <br>因为没有自制力的人是没有资格谈努力的。</p>
]]></content>
<summary type="html">
<![CDATA[<h2 id="u4E00"><a href="#u4E00" class="headerlink" title="一"></a>一</h2><p>在周鱼的微博上看到他的一段话 <code>你可以追剧追一晚,只要你可以按时交上论文。你可以有丰富的夜生活,只要第二天你还能精神饱满的]]>
</summary>
<category term="努力" scheme="http://sphenginx.github.io/tags/%E5%8A%AA%E5%8A%9B/"/>
<category term="自制力" scheme="http://sphenginx.github.io/tags/%E8%87%AA%E5%88%B6%E5%8A%9B/"/>
<category term="日薪越亿" scheme="http://sphenginx.github.io/categories/%E6%97%A5%E8%96%AA%E8%B6%8A%E4%BA%BF/"/>
</entry>
<entry>
<title><![CDATA[如何用管理的思维,规划好自己的人生?]]></title>
<link href="http://sphenginx.github.io/2016/07/18/self-management/"/>
<id>http://sphenginx.github.io/2016/07/18/self-management/</id>
<published>2016-07-18T10:03:01.000Z</published>
<updated>2016-07-19T07:35:27.072Z</updated>
<content type="html"><![CDATA[<h2 id="u524D_u8BB0"><a href="#u524D_u8BB0" class="headerlink" title="前记"></a>前记</h2><p>如果要我选出大学最应该掌握的一项技能,毫无疑问,一定是做规划的能力。</p>
<p>为什么这么说呢?</p>
<p>我在之前的一篇文章里说过,不要以为进入了大学就可以放松了,大学只是另一条起跑线,而且,比高中要严峻得多。</p>
<p>原因很简单:不同于高中,大学里的一切,完全靠自己的主动性和驱动力。优秀的人,早在大一、大二,就已经清楚自己想要什么,开始集中精力往规划好的方向冲刺了。如果你等到大四才开始行动,其实就已经晚了。</p>
<p>举个栗子,有些朋友想进广告公司,但如果你等到毕业才去投简历,你会发现:广告公司根本不要没有经验的人,尤其是国际4A。那么,你不得不先到其他行业曲线救国,或者干脆放弃这个方向——你看,比起大二、大三就在4A里面实习,毕业后顺利成章留下来的,你比别人晚了多少?</p>
<p>再比如,有个朋友想进咨询行业(真事),结果到了临近毕业,才发现:优秀的咨询公司,不但对专业有着非常狭窄的要求(金融、计算机等),最低学历也是硕士,普通本科连面试的可能都没有,怎么办?如果早几年知道这件事,一早就可以转专业了,再不济,也可以提前准备考个研。</p>
<p>所以,为什么要做好规划?<strong>因为,我们人生当中的许多决策和选择,都要点满许多前置技能才会出</strong>现。如果你没有事先做好准备,你要么就只能花更多的时间去弥补,要么就只能像所有平庸的人一样,在那些门槛最低的选择中挑选和徘徊。</p>
<p>更进一步的是,很多时候,我们遇到的许多困境,乃至于使我们的人生变得平庸乏味的罪魁祸首,<strong>其实,都是因为我们活得太过随意。</strong></p>
<p>比如,我经常收到这样的私信:</p>
<ul>
<li><p>「大学学了个不喜欢的专业,一直很抵触,毕业之后也不知道做什么,就这样晃荡了一年,好无奈……」</p>
</li>
<li><p>「是不是我太眼高手低了?一年里换了好几份工作,每一份都待不久,现在很焦虑……」</p>
</li>
<li><p>「我一点都不喜欢现在的工作,但是又没有能力跳出来,每天都很忙,觉得未来的日子好迷茫……」</p>
</li>
</ul>
<p>其实,不满意现状并不可怕,可怕的是我们不知道该往什么方向改变。</p>
<p>这样的后果是什么?就像身在一个巨大的迷宫里,看不见周围的路线,日复一日地活在焦虑和迷茫之中,不断地往左往右试探着迈出步子,到头来却发现兜了一个巨大的圈子。就算能走出去,也是靠着运气,回过头看,更不知道走了多少冤枉路。</p>
<p>所以,每当遇到这种情况,我总会告诉他们,先尽最大的时间和精力,想清楚方向和规划。</p>
<p>在你没有一个清晰的——至少是初步的规划之前,一切的努力都是无意义的。它们只会成为大量的试错成本,成为在迷宫里一次次兜圈子的脚印,徒耗精力。</p>
<p>这篇文章,会结合项目管理的思维,谈谈如何做好人生里面,每一个阶段的规划。</p>
<h2 id="u4E00_u3001_u613F_u666F_uFF1A_u6211_u60F3_u6210_u4E3A_u4EC0_u4E48_u6837_u7684_u4EBA_uFF1F"><a href="#u4E00_u3001_u613F_u666F_uFF1A_u6211_u60F3_u6210_u4E3A_u4EC0_u4E48_u6837_u7684_u4EBA_uFF1F" class="headerlink" title="一、愿景:我想成为什么样的人?"></a>一、愿景:我想成为什么样的人?</h2><p>讲一个故事吧。</p>
<blockquote>
<p> 「我在店里吃早餐,看见有个女人跟店主起了争执。好像是店主少放了一颗蛋,她要求退钱,店主不肯。旁边有个女人,估计是她的朋友,一直在劝解。</p>
<p> 吵着吵着,那个女人突然坐下,捂住脸,哭了出来。</p>
<p> 她朋友吓了一跳,忙不迭地跟她说:不就一个蛋嘛,哭什么,咱们不要就是了。</p>
<p> 她抽泣着说,我不是哭这个,我是伤心,为什么我都30多了,却还要为了一个蛋跟别人吵架?这不是我想要的生活。」</p>
</blockquote>
<p>尽管作者的笔调多少带着一点促狭和调侃,但却给我留下了非常深刻的印象。</p>
<p>有多少人就像这样,曾对生活怀着各种各样的梦想和憧憬,却被现实一次又一次地迎头棒击,磨蚀锐气,最终成为自己以前最讨厌的那种人?</p>
<p>如果你不希望这样,如果你希望能够自己掌控自己的生活,那么,你可以先问自己这个问题:</p>
<p><strong>10年以后,我想成为一个什么样的人?</strong></p>
<p>你是想成为时尚前沿的焦点,出入时装周、酒会;还是想拥有自己的一间小店,一家工作室,享受充实而快节奏的事业;抑或是成为一名旅行美食撰稿人,天天飞往各地寻觅美食;又或者,是想安稳下来,拥有一间不大的房子,享受恬静的家庭生活?</p>
<p>无须进行过多的思考,相信自己的内心,捕捉住第一时间浮现出来的碎片——可能是一些形容词,一个场景,一种氛围,一些物质——将它们写在纸上,作为主干,然后,填充进必要的脉络、骨架,慢慢完善,直至将这种生活状态勾勒完整。</p>
<p>这个过程可能会花上几天,不要急,尽量遵从自己的内心。尽量写得更具体一些。</p>
<p>然后,准备一本空白的笔记本,打开第一页,将它写上去。</p>
<p>它将成为你往后一切努力的方向和根源。</p>
<h2 id="u4E8C_u3001_u95E8_u69DB_uFF1A_u6211_u8BE5_u6EE1_u8DB3_u4EC0_u4E48_u6837_u7684_u6761_u4EF6_uFF1F"><a href="#u4E8C_u3001_u95E8_u69DB_uFF1A_u6211_u8BE5_u6EE1_u8DB3_u4EC0_u4E48_u6837_u7684_u6761_u4EF6_uFF1F" class="headerlink" title="二、门槛:我该满足什么样的条件?"></a>二、门槛:我该满足什么样的条件?</h2><p>第一步的结果,只是帮助我们梳理出了自己想达到的生活状态。需要将它明确下来,进行分解,才能落实到后续的行动之中。</p>
<p>请打开笔记本,在第二页尽可能地罗列出你所知道的、达成目标需要满足的条件。</p>
<p>以开一间咖啡店为例,你需要满足的条件,可能是这样的:(未必准确,只是一个参考)</p>
<ul>
<li><p>一笔至少30万元的启动资金(视城市和地段而定。包括租金、装修以及前几个月的必要开支等)。</p>
</li>
<li><p>咖啡的相关知识。</p>
</li>
<li><p>店铺运营、资金管理、会计等基本商业知识。</p>
</li>
<li><p>市场营销及推广的基本知识。</p>
</li>
<li><p>平面设计、空间设计的基本知识(店面、LOGO设计和店内布局)。</p>
</li>
<li><p>有竞争优势的媒体资源和人脉关系。</p>
</li>
<li><p>稳定可靠的供货渠道。</p>
</li>
<li><p>大量的成熟案例参考资料。</p>
</li>
<li><p>……</p>
</li>
</ul>
<p>这样一来,你需要做什么,就非常清晰了。「能否在10年内开一家咖啡馆」,就变成「能否在10年内满足这些条件」。</p>
<p>不要急于求成,一开始你列出的条件,可能很不完整、不严谨,慢慢来。有疑问的地方,就去网上搜索资料,去知乎提问,或者请教对这方面比较熟悉的人,对这一页反复修改、增补,直到趋于完善为止。</p>
<h2 id="u4E09_u3001_u8DEF_u5F84_uFF1A_u6211_u8BE5_u5982_u4F55_u6EE1_u8DB3_u8FD9_u4E9B_u6761_u4EF6_uFF1F"><a href="#u4E09_u3001_u8DEF_u5F84_uFF1A_u6211_u8BE5_u5982_u4F55_u6EE1_u8DB3_u8FD9_u4E9B_u6761_u4EF6_uFF1F" class="headerlink" title="三、路径:我该如何满足这些条件?"></a>三、路径:我该如何满足这些条件?</h2><p>这是整个规划里面最重要的一步。</p>
<p>第二步列出的条件中,每一个问题,都有不同的解决方法。比如:</p>
<ul>
<li><p>会计和账目管理是一项非常繁琐的工作,你可以自己来,也可以跟朋友合伙、由他来负责这部分,也可以雇佣一位员工帮你分担;</p>
</li>
<li><p>店面设计、LOGO设计,你可以请朋友帮忙,也可以委托给专业的设计公司;</p>
</li>
<li><p>一开始的启动资金,你可以向家里人求助,可以向银行贷款,也可以自己一步步攒齐</p>
</li>
</ul>
<p>诸如此类。</p>
<p>不同的解决方法,会有不同的要求,要根据你的实际情况来处理。</p>
<ul>
<li><p>如果你家境良好,没有太多资金方面的压力,那显然,你就可以挑选一份比较轻松的工作,把省下来的时间和精力,去看市场营销方面的书籍,学习推广和运营知识,甚至到咖啡馆里面打工、积累经验,都可以。</p>
</li>
<li><p>如果你家境一般,打算靠自己攒齐启动资金,那你可能就得选择比较辛苦、加班较多,但收入也相对较高的工作。或者在业余时间接一些外包和私单,平时也多注意开源节流,以攒齐存款为第一优先级。</p>
</li>
<li><p>如果你的朋友里面有管理和财务方面的专业人才,关系也足够好,你就可以把这一块完全交给他,把自己的精力聚集在其他方面。</p>
</li>
<li><p>又或者,如果你打算在推广上面花大力气,那是不是可以选择新媒体相关的行业,积累这方面的经验和人际资源,为将来打好铺垫?</p>
</li>
<li><p>……</p>
</li>
</ul>
<p>翻开笔记本的第三页,把你的这些思考过程,详细地写下来。</p>
<ul>
<li><p>我拥有什么样的资源和优势?</p>
</li>
<li><p>我需要聚焦和关注哪些最核心的条件?</p>
</li>
<li><p>我可以采取什么方法解决它们?</p>
</li>
</ul>
<p>仔细思考这些问题,大量地去查找信息,在这个基础上,提炼出一份概要的「计划」,并对它反复进行打磨。</p>
<p>这一步的意义在于,<strong>只做那些对长远规划有益的事情。</strong></p>
<p>比如,我在之前的文章里提过,不要把时间浪费在低回报的兼职上。但是,如果你的长远目标是开一家咖啡店,那么到咖啡店里兼职有何不可呢?这个时候,它的回报就不是简单的金钱了,而是成为你整个规划必不可少的一环。</p>
<p>再比如,许多人一到周末,要么睡一天,要么逛街、玩游戏,这样没有什么问题,但是,如果你有一个长远的规划和方案,你是一定不会容忍自己这样的。你会去图书馆看书,会去练习技能,会早起去健身。</p>
<p>因为你清楚地知道,按照你的计划,只有这样,才能离你的梦想更近一步。</p>
<h2 id="u56DB_u3001_u91CF_u5316_uFF1A_u6211_u8981_u5B9E_u73B0_u4EC0_u4E48_u8FDB_u5EA6_uFF1F"><a href="#u56DB_u3001_u91CF_u5316_uFF1A_u6211_u8981_u5B9E_u73B0_u4EC0_u4E48_u8FDB_u5EA6_uFF1F" class="headerlink" title="四、量化:我要实现什么进度?"></a>四、量化:我要实现什么进度?</h2><p>为什么有些人制订了计划,却总是得不到落实,有些人却可以一步步朝着计划前进?</p>
<p>很大程度上,是由于计划本身的「有效性」。</p>
<p>什么是有效的计划呢?有一个通用的原则,叫做<strong>SMART原则</strong>。亦即<strong>「具体、可衡量、有可行性、有相关性、有时间期限」</strong>。</p>
<p>刨去可行性和相关性这两个显而易见的原则(目标必须有可能实现、目标必须与整体规划和其他目标相关),可以看出,最核心的部分,就是「量化」。用一句话来概括就是:<strong>我需要在什么时间点,达成什么样的进度?</strong></p>
<p>举个最简单的例子:</p>
<ul>
<li><p>「我要写一部小说」就不是一个计划;</p>
</li>
<li><p>「我要在3个月内完成一部60万字的小说,平均每周不少于5000字。」 就是一个初步的计划;</p>
</li>
<li><p>「我要在半年内完成一部小说,前3个月用于构思和准备素材,后3个月专注写作,平均每周不少于5000字,总字数不少于60万字。发布之后,在1个月内获得100个订阅,并且总体评价中好评需要超过60%。」 就是一个很完善的计划了。</p>
</li>
</ul>
<p>同样,「我要学习市场营销知识」只是一句空洞的话,如果要使之成为计划,可以这样设置:</p>
<blockquote>
<p> 「我要在1年内读完20本市场营销相关的专业书籍;每晚至少读30页书,学习1-3个知识点;每周至少写一篇不少于3000字的学习心得。」</p>
</blockquote>
<p>这样,就是一份有效、可执行的计划了。</p>
<p>请在笔记本上,翻开下一页,把确定下来的计划一条条列上去。</p>
<p>如果你有兴趣,可以做一份表格:横轴是每一项计划,纵轴是每一天的日期,再标出相应的进度和时间点。然后,每一天按照计划去「打卡」:今天读了25页书,就写上25;今天背了30个单词,就写上30。诸如此类。让自己对自己的执行情况、进度实现情况都能一目了然。</p>
<p>原则上,计划确立之后,不要频繁地去改动它。所以,一开始制订的时候,要根据实际情况控制好强度,最好设置在「需要付出一定努力就能够达到」的程度。这样才能对自己起到鞭策和激励的作用。</p>
<h2 id="u4E94_u3001_u53CD_u9988_uFF1A_u6211_u7684_u89C4_u5212_u5408_u7406_u5417_uFF1F"><a href="#u4E94_u3001_u53CD_u9988_uFF1A_u6211_u7684_u89C4_u5212_u5408_u7406_u5417_uFF1F" class="headerlink" title="五、反馈:我的规划合理吗?"></a>五、反馈:我的规划合理吗?</h2><p>人毕竟不是全知全能的,不可能一蹴而就。所以,在按照计划执行的时候,做好每一天的记录。试行一段时间之后,再根据这段时间的实际情况,对下一段时间的计划进行调整。</p>
<p>一般来说,1-3个月重新制订一次计划比较常见。以背单词为例,如果第一个月你给自己规定的计划是每天50个单词,1个月之后,你发现没有一天能达到目标,最多也不过30个单词,那么第二个月你就可以将目标设置为30,类似这样。</p>
<p>同样,在实行前文所说的长远规划时,如果你发现规划有误,或者有更好的方式可以满足条件,都可以及时对规划进行修改和调整。</p>
<p>末了,再多说几点。</p>
<p>首先,这是一个思维方式,亦即<strong>「规划-列出条件-找出方案-分解量化-反馈检查」</strong>。你可以把它应用到生活中的方方面面。比如,10年能不能变成1年、3年、5年,甚至半年?当然都可以。按照你想解决的实际问题来调整就好。</p>
<p>然后,如果你不知道开咖啡店需要多少钱,需要学习什么知识,怎么办?你可以在网上搜索资料,实在找不到的,去问身边的人(或者通过他们去问他们的朋友),去知乎和在行上找专业人士请教,或者,直接找一家咖啡店,跟老板搞好关系,跟他闲聊,都可以。获得信息的方法无穷无尽,不要止步于这个障碍上。</p>
<p>最后,讲个故事,给大家一点信心吧。</p>
<p>我有个朋友,大学的时候,每天回到宿舍就是玩游戏,周末也一直宅着。大四的时候,他去了一家游戏公司实习,做了两个月就辞职了。</p>
<p>「我不喜欢那种环境。」他说。「团队,同事,办公室,每天做的事情,我都不喜欢。太混乱,太low。」</p>
<p>后来呢?他回家休息了两年,学英语,考雅思,两年后,考进英国某排名前五的大学,读了个管理学硕士。回国之后,参加某跨国IT咨询公司的面试,在一片计算机专业的海归硕士和专业人士之中杀出重围,顺利拿到了助理顾问的职位。现在已经是某个team的leader。</p>
<p><strong>种一棵树最好的时间是十年前,其次就是现在。</strong></p>
<p>本文转自知乎专栏<a href="https://zhuanlan.zhihu.com/p/21627399" target="_blank" rel="external">https://zhuanlan.zhihu.com/p/21627399</a></p>
]]></content>
<summary type="html">
<![CDATA[<h2 id="u524D_u8BB0"><a href="#u524D_u8BB0" class="headerlink" title="前记"></a>前记</h2><p>如果要我选出大学最应该掌握的一项技能,毫无疑问,一定是做规划的能力。</p>
<p>为什么这么说呢?</]]>
</summary>
<category term="plan" scheme="http://sphenginx.github.io/tags/plan/"/>
<category term="管理" scheme="http://sphenginx.github.io/tags/%E7%AE%A1%E7%90%86/"/>
<category term="日薪越亿" scheme="http://sphenginx.github.io/categories/%E6%97%A5%E8%96%AA%E8%B6%8A%E4%BA%BF/"/>
</entry>
<entry>
<title><![CDATA[PHP 底层的运行机制与原理]]></title>
<link href="http://sphenginx.github.io/2016/07/11/php-theory/"/>
<id>http://sphenginx.github.io/2016/07/11/php-theory/</id>
<published>2016-07-11T01:27:40.000Z</published>
<updated>2016-07-12T03:20:46.147Z</updated>
<content type="html"><![CDATA[<h2 id="u524D_u8A00"><a href="#u524D_u8A00" class="headerlink" title="前言"></a>前言</h2><p>PHP说简单,但是要精通也不是一件简单的事。我们除了会使用之外,还得知道它底层的工作原理。</p>
<p>PHP是一种适用于web开发的动态语言。具体点说,就是一个用C语言实现包含大量组件的软件框架。更狭义点看,可以把它认为是一个强大的UI框架。</p>
<p>了解PHP底层实现的目的是什么?动态语言要像用好首先得了解它,内存管理、框架模型值得我们借鉴,通过扩展开发实现更多更强大的功能,优化我们程序的性能。</p>
<h2 id="PHP_u7684_u8BBE_u8BA1_u7406_u5FF5_u53CA_u7279_u70B9"><a href="#PHP_u7684_u8BBE_u8BA1_u7406_u5FF5_u53CA_u7279_u70B9" class="headerlink" title="PHP的设计理念及特点"></a>PHP的设计理念及特点</h2><ul>
<li>多进程模型:由于PHP是多进程模型,不同请求间互不干涉,这样保证了一个请求挂掉不会对全盘服务造成影响,当然,随着时代发展,PHP也早已支持多线程模型。</li>
<li>弱类型语言:和C/C++、Java、C#等语言不同,PHP是一门弱类型语言。一个变量的类型并不是一开始就确定不变,运行中才会确定并可能发生隐式或显式的类型转换,这种机制的灵活性在web开发中非常方便、高效,具体会在后面PHP变量中详述。</li>
<li>引擎(Zend)+组件(ext)的模式降低内部耦合。</li>
<li>中间层(sapi)隔绝web server和PHP。</li>
<li>语法简单灵活,没有太多规范。缺点导致风格混杂,但再差的程序员也不会写出太离谱危害全局的程序。</li>
</ul>
<h2 id="PHP_u7684_u56DB_u5C42_u4F53_u7CFB"><a href="#PHP_u7684_u56DB_u5C42_u4F53_u7CFB" class="headerlink" title="PHP的四层体系"></a>PHP的四层体系</h2><p>PHP的核心架构如下图:</p>
<p><img src="http://sphenginx.github.io/images/php/theory.jpg" alt="PHP 核心架构图"></p>
<p>从图上可以看出,PHP从下到上是一个4层体系:</p>
<ul>
<li>Zend引擎:Zend整体用纯C实现,是PHP的内核部分,它将PHP代码翻译(词法、语法解析等一系列编译过程)为可执行opcode的处理并实现相应的处理方法、实现了基本的数据结构(如hashtable、oo)、内存分配及管理、提供了相应的api方法供外部调用,是一切的核心,所有的外围功能均围绕Zend实现。</li>
<li>Extensions:围绕着Zend引擎,extensions通过组件式的方式提供各种基础服务,我们常见的各种内置函数(如array系列)、标准库等都是通过extension来实现,用户也可以根据需要实现自己的extension以达到功能扩展、性能优化等目的(如贴吧正在使用的PHP中间层、富文本解析就是extension的典型应用)。</li>
<li>Sapi:Sapi全称是Server Application Programming Interface,也就是服务端应用编程接口,Sapi通过一系列钩子函数,使得PHP可以和外围交互数据,这是PHP非常优雅和成功的一个设计,通过sapi成功的将PHP本身和上层应用解耦隔离,PHP可以不再考虑如何针对不同应用进行兼容,而应用本身也可以针对自己的特点实现不同的处理方式。</li>
<li>上层应用:这就是我们平时编写的PHP程序,通过不同的sapi方式得到各种各样的应用模式,如通过webserver实现web应用、在命令行下以脚本方式运行等等。</li>
</ul>
<p>如果PHP是一辆车,那么车的框架就是PHP本身,Zend是车的引擎(发动机),Ext下面的各种组件就是车的轮子,Sapi可以看做是公路,车可以跑在不同类型的公路上,而一次PHP程序的执行就是汽车跑在公路上。因此,我们需要:性能优异的引擎+合适的车轮+正确的跑道。</p>
<h2 id="Sapi"><a href="#Sapi" class="headerlink" title="Sapi"></a>Sapi</h2><p>如前所述,Sapi通过通过一系列的接口,使得外部应用可以和PHP交换数据并可以根据不同应用特点实现特定的处理方法,我们常见的一些sapi有:</p>
<ul>
<li>apache2handler:这是以apache作为webserver,采用mod_PHP模式运行时候的处理方式,也是现在应用最广泛的一种。</li>
<li>cgi:这是webserver和PHP直接的另一种交互方式,也就是大名鼎鼎的fastcgi协议,在最近今年fastcgi+PHP得到越来越多的应用,也是异步webserver所唯一支持的方式。</li>
<li>cli:命令行调用的应用模式</li>
</ul>
<h2 id="PHP_u7684_u6267_u884C_u6D41_u7A0B_26amp_3Bopcode"><a href="#PHP_u7684_u6267_u884C_u6D41_u7A0B_26amp_3Bopcode" class="headerlink" title="PHP的执行流程&opcode"></a>PHP的执行流程&opcode</h2><p>我们先来看看PHP代码的执行所经过的流程。</p>
<p><img src="http://sphenginx.github.io/images/php/opcode.jpg" alt="opcode"></p>
<p>从图上可以看到,PHP实现了一个典型的动态语言执行过程:拿到一段代码后,经过词法解析、语法解析等阶段后,源程序会被翻译成一个个指令(opcodes),然后ZEND虚拟机顺次执行这些指令完成操作。PHP本身是用C实现的,因此最终调用的也都是C的函数,实际上,我们可以把PHP看做是一个C开发的软件。</p>
<p>PHP的执行的核心是翻译出来的一条一条指令,也即opcode。</p>
<p>Opcode是PHP程序执行的最基本单位。一个opcode由两个参数(op1,op2)、返回值和处理函数组成。PHP程序最终被翻译为一组opcode处理函数的顺序执行。</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></pre></td><td class="code"><pre><span class="line">ZEND_ASSIGN_SPEC_CV_CV_HANDLER : 变量分配 (<span class="variable">$a</span>=<span class="variable">$b</span>)</span><br><span class="line">ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER:函数调用</span><br><span class="line">ZEND_CONCAT_SPEC_CV_CV_HANDLER:字符串拼接 <span class="variable">$a</span>.<span class="variable">$b</span></span><br><span class="line">ZEND_ADD_SPEC_CV_CONST_HANDLER: 加法运算 <span class="variable">$a</span>+<span class="number">2</span></span><br><span class="line">ZEND_IS_EQUAL_SPEC_CV_CONST:判断相等 <span class="variable">$a</span>==<span class="number">1</span></span><br><span class="line">ZEND_IS_IDENTICAL_SPEC_CV_CONST:判断相等 <span class="variable">$a</span>===<span class="number">1</span></span><br></pre></td></tr></table></figure></p>
<h2 id="HashTable__u2014__u6838_u5FC3_u6570_u636E_u7ED3_u6784"><a href="#HashTable__u2014__u6838_u5FC3_u6570_u636E_u7ED3_u6784" class="headerlink" title="HashTable — 核心数据结构"></a>HashTable — 核心数据结构</h2><p>HashTable是zend的核心数据结构,在PHP里面几乎并用来实现所有常见功能,我们知道的PHP数组即是其典型应用,此外,在zend内部,如函数符号表、全局变量等也都是基于hash table来实现。</p>
<p>PHP的hash table具有如下特点:</p>
<ul>
<li>支持典型的key->value查询</li>
<li>可以当做数组使用</li>
<li>添加、删除节点是O(1)复杂度</li>
<li>key支持混合类型:同时存在关联数组合索引数组</li>
<li>Value支持混合类型:array (“string”,2332)</li>
<li>支持线性遍历:如foreach</li>
</ul>
<p>Zend hash table实现了典型的hash表散列结构,同时通过附加一个双向链表,提供了正向、反向遍历数组的功能。其结构如下图:<br><img src="http://sphenginx.github.io/images/php/hashtable.jpg" alt="hashTable"></p>
<ul>
<li>可以看到,在hash table中既有key->value形式的散列结构,也有双向链表模式,使得它能够非常方便的支持快速查找和线性遍历。<br>散列结构:Zend的散列结构是典型的hash表模型,通过链表的方式来解决冲突。需要注意的是zend的hash table是一个自增长的数据结构,当hash表数目满了之后,其本身会动态以2倍的方式扩容并重新元素位置。初始大小均为8。另外,在进行key->value快速查找时候,zend本身还做了一些优化,通过空间换时间的方式加快速度。比如在每个元素中都会用一个变量nKeyLength标识key的长度以作快速判定。</li>
<li>双向链表:Zend hash table通过一个链表结构,实现了元素的线性遍历。理论上,做遍历使用单向链表就够了,之所以使用双向链表,主要目的是为了快速删除,避免遍历。Zend hash table是一种复合型的结构,作为数组使用时,即支持常见的关联数组也能够作为顺序索引数字来使用,甚至允许2者的混合。</li>
<li><p>PHP关联数组:关联数组是典型的hash_table应用。一次查询过程经过如下几步(从代码可以看出,这是一个常见的hash查询过程并增加一些快速判定加速查找。):</p>
<figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">getKeyHashValue h;</span><br><span class="line">index = n & nTableMask;</span><br><span class="line">Bucket *p = arBucket[index];</span><br><span class="line"><span class="keyword">while</span> (p) {</span><br><span class="line"> <span class="keyword">if</span> ((p->h == h) && (p->nKeyLength == nKeyLength)) {</span><br><span class="line"> <span class="keyword">RETURN</span> p->data; </span><br><span class="line"> }</span><br><span class="line"> p=p->next;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">RETURN</span> FALTURE;</span><br></pre></td></tr></table></figure>
</li>
<li><p>PHP索引数组:索引数组就是我们常见的数组,通过下标访问。例如 \$arr[0],Zend HashTable内部进行了归一化处理,对于index类型key同样分配了hash值和nKeyLength(为0)。内部成员变量nNextFreeElement就是当前分配到的最大id,每次push后自动加一。正是这种归一化处理,PHP才能够实现关联和非关联的混合。由于push操作的特殊性,索引key在PHP数组中先后顺序并不是通过下标大小来决定,而是由push的先后决定。例如 \$arr[1] = 2; \$arr[2] = 3;对于double类型的key,Zend HashTable会将他当做索引key处理。</p>
</li>
</ul>
<h2 id="PHP_u53D8_u91CF"><a href="#PHP_u53D8_u91CF" class="headerlink" title="PHP变量"></a>PHP变量</h2><p>PHP是一门弱类型语言,本身不严格区分变量的类型。PHP在变量申明的时候不需要指定类型。PHP在程序运行期间可能进行变量类型的隐示转换。和其他强类型语言一样,程序中也可以进行显示的类型转换。PHP变量可以分为简单类型(int、string、bool)、集合类型(array resource object)和常量(const)。以上所有的变量在底层都是同一种结构 zval。</p>
<p>Zval是zend中另一个非常重要的数据结构,用来标识并实现PHP变量,其数据结构如下:<br><img src="http://sphenginx.github.io/images/php/zval.jpg" alt="zval"></p>
<p>Zval主要由三部分组成:</p>
<ul>
<li>type:指定了变量所述的类型(整数、字符串、数组等)</li>
<li>refcount&is_ref:用来实现引用计数(后面具体介绍)</li>
<li>value:核心部分,存储了变量的实际数据</li>
</ul>
<p>Zvalue是用来保存一个变量的实际数据。因为要存储多种类型,所以zvalue是一个union,也由此实现了弱类型。</p>
<p>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></pre></td><td class="code"><pre><span class="line">IS_LONG -> lvalue</span><br><span class="line">IS_DOUBLE -> dvalue</span><br><span class="line">IS_ARRAY -> ht</span><br><span class="line">IS_STRING -> str</span><br><span class="line">IS_RESOURCE -> lvalue</span><br></pre></td></tr></table></figure></p>
<p>引用计数在内存回收、字符串操作等地方使用非常广泛。PHP中的变量就是引用计数的典型应用。Zval的引用计数通过成员变量is_ref和ref_count实现,通过引用计数,多个变量可以共享同一份数据。避免频繁拷贝带来的大量消耗。</p>
<p>在进行赋值操作时,zend将变量指向相同的zval同时ref_count++,在unset操作时,对应的ref_count-1。只有ref_count减为0时才会真正执行销毁操作。如果是引用赋值,则zend会修改is_ref为1。</p>
<p>PHP变量通过引用计数实现变量共享数据,那如果改变其中一个变量值呢?当试图写入一个变量时,Zend若发现该变量指向的zval被多个变量共享,则为其复制一份ref_count为1的zval,并递减原zval的refcount,这个过程称为“zval分离”。可见,只有在有写操作发生时zend才进行拷贝操作,因此也叫copy-on-write(写时拷贝)</p>
<p>对于引用型变量,其要求和非引用型相反,引用赋值的变量间必须是捆绑的,修改一个变量就修改了所有捆绑变量。</p>
<p>整数、浮点数是PHP中的基础类型之一,也是一个简单型变量。对于整数和浮点数,在zvalue中直接存储对应的值。其类型分别是long和double。</p>
<p>从zvalue结构中可以看出,对于整数类型,和c等强类型语言不同,PHP是不区分int、unsigned int、long、long long等类型的,对它来说,整数只有一种类型也就是long。由此,可以看出,在PHP里面,整数的取值范围是由编译器位数来决定而不是固定不变的。</p>
<p>对于浮点数,类似整数,它也不区分float和double而是统一只有double一种类型。</p>
<p>在PHP中,如果整数范围越界了怎么办?这种情况下会自动转换为double类型,这个一定要小心,很多trick都是由此产生。</p>
<p>和整数一样,字符变量也是PHP中的基础类型和简单型变量。通过zvalue结构可以看出,在PHP中,字符串是由由指向实际数据的指针和长度结构体组成,这点和c++中的string比较类似。由于通过一个实际变量表示长度,和c不同,它的字符串可以是2进制数据(包含\0),同时在PHP中,求字符串长度strlen是O(1)操作。</p>
<p>在新增、修改、追加字符串操作时,PHP都会重新分配内存生成新的字符串。最后,出于安全考虑,PHP在生成一个字符串时末尾仍然会添加\0</p>
<p>常见的字符串拼接方式及速度比较:</p>
<p>假设有如下4个变量:<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="variable">$strA</span> = <span class="string">'123'</span>; </span><br><span class="line"><span class="variable">$strB</span> = <span class="string">'456'</span>; </span><br><span class="line"><span class="variable">$intA</span> = <span class="number">123</span>; </span><br><span class="line"><span class="variable">$intB</span> = <span class="number">456</span>;</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></pre></td><td class="code"><pre><span class="line"><span class="variable">$res</span> = <span class="variable">$strA</span>.<span class="variable">$strB</span>和<span class="variable">$res</span> = “<span class="variable">$strA</span><span class="variable">$strB</span>”</span><br><span class="line">这种情况下,zend会重新malloc一块内存并进行相应处理,其速度一般</span><br><span class="line"><span class="variable">$strA</span> = <span class="variable">$strA</span>.<span class="variable">$strB</span></span><br><span class="line">这种是速度最快的,zend会在当前strA基础上直接relloc,避免重复拷贝</span><br><span class="line"><span class="variable">$res</span> = <span class="variable">$intA</span>.<span class="variable">$intB</span></span><br><span class="line">这种速度较慢,因为需要做隐式的格式转换,实际编写程序中也应该注意尽量避免</span><br><span class="line"><span class="variable">$strA</span> = sprintf (“%s%s”,<span class="variable">$strA</span>.<span class="variable">$strB</span>);</span><br><span class="line">这会是最慢的一种方式,因为sprintf在PHP中并不是一个语言结构,本身对于格式识别和处理就需要耗费比较多时间,另外本身机制也是malloc。不过sprintf的方式最具可读性,实际中可以根据具体情况灵活选择。</span><br></pre></td></tr></table></figure></p>
<p>PHP的数组通过Zend HashTable来天然实现。</p>
<p>foreach操作如何实现?对一个数组的foreach就是通过遍历hashtable中的双向链表完成。对于索引数组,通过foreach遍历效率比for高很多,省去了key->value的查找。count操作直接调用HashTable->NumOfElements,O(1)操作。对于’123’这样的字符串,zend会转换为其整数形式。\$arr[‘123’]和\$arr[123]是等价的</p>
<p>资源类型变量是PHP中最复杂的一种变量,也是一种复合型结构。</p>
<p>PHP的zval可以表示广泛的数据类型,但是对于自定义的数据类型却很难充分描述。由于没有有效的方式描绘这些复合结构,因此也没有办法对它们使用传统的操作符。要解决这个问题,只需要通过一个本质上任意的标识符(label)引用指针,这种方式被称为资源。</p>
<p>在zval中,对于resource,lval作为指针来使用,直接指向资源所在的地址。Resource可以是任意的复合结构,我们熟悉的mysqli、fsock、memcached等都是资源。</p>
<p>如何使用资源:</p>
<ul>
<li>注册:对于一个自定义的数据类型,要想将它作为资源。首先需要进行注册,zend会为它分配全局唯一标示。</li>
<li>获取一个资源变量:对于资源,zend维护了一个id->实际数据的hash_tale。对于一个resource,在zval中只记录了它的id。fetch的时候通过id在hash_table中找到具体的值返回。</li>
<li>资源销毁:资源的数据类型是多种多样的。Zend本身没有办法销毁它。因此需要用户在注册资源的时候提供销毁函数。当unset资源时,zend调用相应的函数完成析构。同时从全局资源表中删除它。</li>
</ul>
<p>资源可以长期驻留,不只是在所有引用它的变量超出作用域之后,甚至是在一个请求结束了并且新的请求产生之后。这些资源称为持久资源,因为它们贯通SAPI的整个生命周期持续存在,除非特意销毁。很多情况下,持久化资源可以在一定程度上提高性能。比如我们常见的mysql_pconnect ,持久化资源通过pemalloc分配内存,这样在请求结束的时候不会释放。 对zend来说,对两者本身并不区分。</p>
<p>PHP中的局部变量和全局变量是如何实现的?对于一个请求,任意时刻PHP都可以看到两个符号表(symbol_table和active_symbol_table),其中前者用来维护全局变量。后者是一个指针,指向当前活动的变量符号表,当程序进入到某个函数中时,zend就会为它分配一个符号表x同时将active_symbol_table指向a。通过这样的方式实现全局、局部变量的区分。</p>
<p>获取变量值:PHP的符号表是通过hash_table实现的,对于每个变量都分配唯一标识,获取的时候根据标识从表中找到相应zval返回。</p>
<p>函数中使用全局变量:在函数中,我们可以通过显式申明global来使用全局变量。在active_symbol_table中创建symbol_table中同名变量的引用,如果symbol_table中没有同名变量则会先创建。</p>
<h2 id="u5176_u4ED6"><a href="#u5176_u4ED6" class="headerlink" title="其他"></a>其他</h2><p>原文转自:<a href="http://www.nowamagic.net/librarys/veda/detail/102" target="_blank" rel="external">http://www.nowamagic.net/librarys/veda/detail/102</a></p>
]]></content>
<summary type="html">
<![CDATA[<h2 id="u524D_u8A00"><a href="#u524D_u8A00" class="headerlink" title="前言"></a>前言</h2><p>PHP说简单,但是要精通也不是一件简单的事。我们除了会使用之外,还得知道它底层的工作原理。</p>
<p]]>
</summary>
<category term="php" scheme="http://sphenginx.github.io/tags/php/"/>
<category term="theory" scheme="http://sphenginx.github.io/tags/theory/"/>
<category term="日薪越亿" scheme="http://sphenginx.github.io/categories/%E6%97%A5%E8%96%AA%E8%B6%8A%E4%BA%BF/"/>
</entry>
<entry>
<title><![CDATA[为了项目上线而加班,真有必要吗?]]></title>
<link href="http://sphenginx.github.io/2016/05/05/why-overtime-doesnt-work/"/>
<id>http://sphenginx.github.io/2016/05/05/why-overtime-doesnt-work/</id>
<published>2016-05-05T07:05:01.000Z</published>
<updated>2016-05-05T06:54:08.569Z</updated>
<content type="html"><![CDATA[<p><img src="http://sphenginx.github.io/images/overtime.jpg" alt="I has to work overtime again today"></p>
<p>大家都知道:软件项目的加班可能真是有百害而无一利,但总还有些时候,有些人有侥幸心理,或是现实情况实在无法让步,比如项目必须在某个日期上线; 在这些情况下,应该跟团队沟通些什么?Quora资深软件工程师Edmond Lau在自己的一篇博客中,给出了自己的看法。这篇博客名为<a href="http://www.theeffectiveengineer.com/blog/why-overtime-doesnt-work" target="_blank" rel="external">《为了满足项目上线日期要求,我该怎么告诉我的团队工作更多时间?》</a>。</p>
<p>文章一开始,Edmond指出:</p>
<blockquote>
<p>在试图告诉团队要加班之前,一定要确保一点:为了保证上线日期,你有一个切实可行的计划。否则,从长远来看的最佳策略是:根据团队当前开发能力和效率,重新定义要上线的功能;或者将截止日期重新调整为更现实的时间。</p>
</blockquote>
<p>接下来,Edmond列举了自己的亲身经验。他曾参与过两个持续多月大型项目,而且团队成员都是高手,专注投入在这两个项目上。为了在某个日期之前上线,工程经理要求团队加班工作,每周60到70个小时。可是项目最后还是没有按时完成。Edmond这样回顾项目的后果:</p>
<blockquote>
<p>这样的方式让一些团队成员筋疲力尽,有些人后来离开了,其他人用了很久才恢复过来。这两个项目的情况都无法判断:加班是否真能加快进度,加班的决策在当时也许很合理,但是长远来看,两只团队都深受其害。我们从这两个项目中学到惨痛的教训:<code>不管你多么希望项目在某个日期前完成,都对它能否做到这一点毫无帮助。不要将积极思考与现实的乐观主义混为一谈。</code></p>
</blockquote>
<p>Edmond列举了几个加班无助于项目尽快交付的原因:</p>
<ul>
<li>工作更多时间,每小时的效率将会降低。</li>
</ul>
<blockquote>
<p>如果你的团队已经习惯了每周40小时工作的生活节奏,而且一年来都是如此,那么很可能他们加班的效率会低于平常,甚至可能产生负面影响。疲累和睡眠减少会伤害认知功能,而且降低工作质量。</p>
</blockquote>
<p>他还列举了150年以来的研究文献,证明这一点,而且有些文献甚至说明:如果加班过多,</p>
<blockquote>
<p>有问题的工作累计带来的负面影响,会导致项目完成日期延迟,甚至比同样的团队按照每周40小时的工作节奏完成得还要晚。</p>
</blockquote>
<ul>
<li>很可能你现在落后的时间进度比你以为的还要多。</li>
</ul>
<blockquote>
<p>在工程中,做出准确的项目估算非常难以做到。进度已经晚了,说明上个月的工作就估算得不够。所以,可能过去的工作估算少了,更有可能的是:整个项目都估算少了,包括剩下几个月的工作。</p>
<p>我们在项目开始时估算得要比项目结束时准确,因为开始时的工作重点放在可以深入理解的工作之上;到结束时,团队常常低估整合测试用去的时间> ,而且每个没有预料到的问题都会让进度延后一周甚至更多。这些效应叠加起来会产生更多延迟。</p>
</blockquote>
<p>他引用了《人月神话》里面的话:</p>
<blockquote>
<p>特别是没有为系统测试留出足够时间,这会带来灾难性后果。因为延迟是在项目日程结束时来临的,除非交付日期快到了,没人会意识到进度上的问题。</p>
</blockquote>
<ul>
<li>额外的工作时间会让团队精疲力竭。<br>Edmond引用了《人件》中的一个症状:“undertime”,也就是说:跟随加班而来的,常常是员工为了要补偿生活方面的损失,而在工作中耗费时间去做与工作无关之事。</li>
</ul>
<blockquote>
<p>我们的经验指出:额外工作时间的积极影响被大大夸大了,而其负面影响却从未有人考量。负面影响可能十分严重:错误、倦怠、失误不断增多、补偿用的“undertime”等等。</p>
</blockquote>
<ul>
<li><p>额外的工作时间会伤害团队士气。<br>在Edmond看来,加班之前,可能团队每个人都有自己的方式来完成每周40小时的工作,而且还能保证团队的凝聚力。一旦要加班,可能某些人就要多完成一些不能多加班的人要做的事情,这会影响彼此之间的关系,以前开心的团队,现在可能就不开心了。</p>
</li>
<li><p>管理向截止日期的冲刺,需要耗费更多管理开销。</p>
</li>
</ul>
<blockquote>
<p>为了管理额外工作而举行更多站立会议和其他会议,这很常见,因为你希望团队要彼此沟通,保证每个人都在做正确的事情。然而,这种额外的沟通开销常常不会放在工作估算中。</p>
</blockquote>
<ul>
<li>向截止日期的冲刺,会刺激产生更多技术债务。<br>Edmond认为:为了赶进度而加班,几乎不可避免地会令得团队找捷径。而且在面临更多项目压力的情况下,这些技术债务很可能越积越多,将来一定要付出更多成本偿还。</li>
</ul>
<p>不过,总有些现实情况不可避免,真到那时候,Edmond建议在沟通时要强调一下因素。</p>
<ul>
<li>要理解为什么进度落了这么远,找出根本原因,还要与团队沟通。</li>
</ul>
<blockquote>
<p>没赶上进度,是因为人们偷懒,还是因为项目要比想象的复杂,要占用更多时间?如果不能理解根本原因,也就不能有信心同样的问题不会在未来几个月出现。</p>
</blockquote>
<ul>
<li>向团队说明更可行的项目计划和时间进度,说明为什么要加班才能真正赶上上线日期,还要说明怎么做。</li>
</ul>
<blockquote>
<p>仅仅告诉团队他们落后了还不够,如果不能得出更详细、更明确的计划达成目标,这就是一个警告信号,说明你比你以为的情况更落后。</p>
</blockquote>
<ul>
<li>确保团队每个人都能理解、认同你的新进度安排。</li>
</ul>
<blockquote>
<p>如果关键成员不相信你的时间表可行,那就得好好想想:你可能无法在新的指定日期前完成你想完成的工作。要是无法做到所有人都认可,那么可能只有某些人认同加班,除了团队中会有不公平的感觉之外,可能你还是无法达成最后完成日期。</p>
</blockquote>
<ul>
<li>重点放在项目、团队或是组织的整体工作目标上,说明为什么按时上线如此重要。</li>
</ul>
<blockquote>
<p>如果你无法把团队融合在一起,这就是另一个警讯:说明不是所有人都像你这么有动力去加班。</p>
</blockquote>
<p>最后,Edmond指出:</p>
<blockquote>
<p>如果,在接下来冲刺的两个月时间里,你发现实际进度比修正后的还要延迟,那就准备放弃这个冲刺吧。接受现实,知道你可能是在马拉松的半程发起了冲刺,而终点线比你想的要远得多。不再可能让团队更努力去解决问题了。减少损失,不妨想想怎么制订一个应急计划应对后续问题。</p>
<p>错过截止日期很糟糕,但要是错过了截止日期,而且让团队精疲力尽,而且没有应急计划,这就更糟糕了。</p>
</blockquote>
<p>译文出处: <a href="http://www.infoq.com/cn/news/2013/08/how-to-tell-team-to-overtime" target="_blank" rel="external">InfoQ</a></p>
]]></content>
<summary type="html">
<![CDATA[<p><img src="http://sphenginx.github.io/images/overtime.jpg" alt="I has to work overtime again today"></p>
<p>大家都知道:软件项目的加班可能真是有百害而无一利,但总还有些]]>
</summary>
<category term="上线" scheme="http://sphenginx.github.io/tags/%E4%B8%8A%E7%BA%BF/"/>
<category term="加班" scheme="http://sphenginx.github.io/tags/%E5%8A%A0%E7%8F%AD/"/>
<category term="日薪越亿" scheme="http://sphenginx.github.io/categories/%E6%97%A5%E8%96%AA%E8%B6%8A%E4%BA%BF/"/>
</entry>
<entry>
<title><![CDATA[编程能力层次模型]]></title>
<link href="http://sphenginx.github.io/2016/01/05/code-ability/"/>
<id>http://sphenginx.github.io/2016/01/05/code-ability/</id>
<published>2016-01-05T07:03:01.000Z</published>
<updated>2016-01-10T02:32:41.614Z</updated>
<content type="html"><![CDATA[<h2 id="u524D_u8A00"><a href="#u524D_u8A00" class="headerlink" title="前言"></a>前言</h2><p>程序员的编程技能随着经验的积累,会逐步提高。我认为编程能力可以分为一些层次。<br>下面通过两个维度展开编程能力层次模型的讨论。<br>一个维度是编程技能层次,另一个维度是领域知识层次。 </p>
<h2 id="u7F16_u7A0B_u6280_u80FD_u5C42_u6B21"><a href="#u7F16_u7A0B_u6280_u80FD_u5C42_u6B21" class="headerlink" title="编程技能层次"></a>编程技能层次</h2><p>编程技能层次,指的程序员设计和编写程序的能力。这是程序员的根本。</p>
<h3 id="0_u6BB5_u2014_u975E_u7A0B_u5E8F_u5458_uFF1A"><a href="#0_u6BB5_u2014_u975E_u7A0B_u5E8F_u5458_uFF1A" class="headerlink" title="0段—非程序员:"></a>0段—非程序员:</h3><p>初学编程者,遇到问题,完全是懵懵懂懂,不知道该怎么编程解决问题。也就是说,还是门外汉,还不能称之为“程序员”。计算机在他面前还是一个神秘的黑匣子。</p>
<h3 id="1_u6BB5_u2014_u57FA_u7840_u7A0B_u5E8F_u5458_uFF1A"><a href="#1_u6BB5_u2014_u57FA_u7840_u7A0B_u5E8F_u5458_uFF1A" class="headerlink" title="1段—基础程序员:"></a>1段—基础程序员:</h3><p>学习过一段时间编程后,接到任务,可以编写程序完成任务。<br>编写出来的代码,正常情况下是能够工作的,但在实际运行中,碰到一些特殊条件就会出现各类BUG。也就是说,具备了开发Demo软件的能力,但开发的软件真正交付给客户使用,恐怕会被客户骂死。<br>程序员程序是写好了,但到底为什么它有时能正常工作,有时又不行,程序员自己也不知道。<br>运行中遇到了bug,或者需求改变,需要修改代码或者添加代码,很快程序就变得结构混乱,代码膨胀,bug丛生。很快,就连最初的开发者自己也不愿意接手维护这个程序了。 </p>
<h3 id="2_u6BB5_u2014_u6570_u636E_u7ED3_u6784_uFF1A"><a href="#2_u6BB5_u2014_u6570_u636E_u7ED3_u6784_uFF1A" class="headerlink" title="2段—数据结构:"></a>2段—数据结构:</h3><p>经过一段时间的编程实践后,程序员会认识到“数据结构+算法=程序”这一古训的含义。他们会使用算法来解决问题。进而,他们会认识到,算法本质上是依附于数据结构的,好的数据结构一旦设计出来,那么好的算法也会应运而生。<br>设计错误的数据结构,不可能生长出好的算法。<br>记得某一位外国先贤曾经说过:“给我看你的数据结构!” </p>
<h3 id="3_u6BB5_u2014_u9762_u5411_u5BF9_u8C61_uFF1A"><a href="#3_u6BB5_u2014_u9762_u5411_u5BF9_u8C61_uFF1A" class="headerlink" title="3段—面向对象:"></a>3段—面向对象:</h3><p>再之后,程序员就会领略面向对象程序设计的强大威力。大多数现代编程语言都是支持面向对象的。但并不是说,你使用面向对象编程语言编程,你用上了类,甚至继承了类,你就是在写面向对象的代码了。<br>我曾经见过很多用Java,Python,Ruby写的面向过程的代码。<br>只有你掌握了接口,掌握了多态,掌握了类和类,对象和对象之间的关系,你才真正掌握了面向对象编程技术。<br>就算你用的是传统的不支持面向对象的编程语言,只要你心中有“对象”,你依然可以开发出面向对象的程序。<br>如,我用C语言编程的时候,会有意识的使用面向对象的技巧来编写和设计程序。用struct来模拟类,把同一类概念的函数放在一起模拟类。如果你怀疑用C语言是否能编写出面向对象的代码,你可以看一下Linux内核,它是用C语言编写的,但你也可以看到它的源代码字里行间散发出的浓浓的“对象”的味道。 </p>
<p><strong>真正掌握面向对象编程技术并不容易。</strong></p>
<p>在我的技术生涯中,有两个坎让我最感头疼。 </p>
<ol>
<li><p>一个坎是Dos向Windows开发的变迁过程中,框架的概念,很长一段时间我都理解不了。Dos时代,都是对函数库的调用,你的程序主动调用函数。Windows时代,则换成了框架。就算是你的main程序,其实也是被框架调用的。UI线程会从操作系统获取消息,然后发送给你的程序来处理。Java程序员熟悉的Spring框架,也是这样一个反向调用的框架。<br>现在因为“框架”这个术语显得很高大上,因此很多“类库”/“函数库”都自称为“框架”。在我看来这都是名称的滥用。<br>“类库”/“函数库”就是我写的代码调用它们。<br>“框架”就是我注册回调函数到框架,框架来调用我写的函数。 </p>
</li>
<li><p>另一个坎就是面向对象。很长一段时间我都不知道应该怎么设计类和类之间的关系,不能很好的设计出类层次结构来。<br>我记得当时看到一本外国大牛的书,他讲了一个很简单、很实用的面向对象设计技巧:“叙述问题。然后把其中的名词找出来,用来构建类。把其中的动词找出来,用来构建类的方法”。虽然这个技巧挺管用的,但也太草根了点,没有理论依据,也不严谨。如果问题叙述的不好,那么获得的类系统就会是有问题的。 </p>
</li>
</ol>
<p>掌握面向对象思想的途径应该有很多种,我是从关系数据库中获得了灵感来理解和掌握面向对象设计思想的。<br>在我看来,关系数据库的表,其实就是一个类,每一行记录就是一个类的实例,也就是对象。表之间的关系,就是类之间的关系。O-Rmapping技术(如Hibernate),用于从面向对象代码到数据库表之间的映射,这也说明了类和表确实是逻辑上等价的。<br>既然数据库设计和类设计是等价的,那么要设计面向对象系统,只需要使用关系数据库的设计技巧即可。<br>关系数据库表结构设计是很简单的: </p>
<ol>
<li>识别表和表之间的关系,也就是类和类之间的关系。是一对一,一对多,多对一,还是多对多。这就是类之间的关系。</li>
<li>识别表的字段。一个对象当然有无数多的属性(如,人:身高,体重,性别,年龄,姓名,身份证号,驾驶证号,银行卡号,护照号,港澳通行证号,工号,病史,婚史etc),我们写程序需要记录的只是我们关心的属性。这些关心的属性,就是表的字段,也就是类的属性。“弱水三千,我取一瓢饮”!</li>
</ol>
<h3 id="4_u6BB5_u2014_u8BBE_u8BA1_u6A21_u5F0F_uFF1A"><a href="#4_u6BB5_u2014_u8BBE_u8BA1_u6A21_u5F0F_uFF1A" class="headerlink" title="4段—设计模式:"></a>4段—设计模式:</h3><p>曾经在网上看到这样一句话:“没有十万行代码量,就不要跟我谈什么设计模式”。深以为然。<br>记得第一次看Gof的设计模式那本书的时候,发现虽然以前并不知道设计模式,但在实际编程过程中,其实还是自觉使用了一些设计模式。设计模式是编程的客观规律,不是谁发明的,而是一些早期的资深程序员首先发现的。<br>不用设计模式,你也可以写出满足需求的程序来。但是,一旦后续需求变化,那么你的程序没有足够的柔韧性,将难以为继。而真实的程序,交付客户后,一定会有进一步的需求反馈。而后续版本的开发,也一定会增加需求。这是程序员无法回避的现实。 </p>
<p><strong>写UI程序,不论是Web,Desktop,Mobile,Game,一定要使用MVC设计模式。否则你的程序面对后续变化的UI需求,将无以为继。</strong></p>
<p><strong>设计模式,最重要的思想就是解耦,通过接口来解耦。</strong>这样,如果将来需求变化,那么只需要提供一个新的实现类即可。<br>主要的设计模式,其实都是面向对象的。因此,可以认为设计模式是面向对象的高级阶段。只有掌握了设计模式,才能认为是真正彻底掌握了面向对象设计技巧。 </p>
<p>我学习一门新语言时(包括非面向对象语言,如函数式编程语言),总是会在了解了其语法后,看一下各类设计模式在这门语言中是如何实现的。这也是学习编程语言的一个窍门。</p>
<h3 id="5_u6BB5_u2013_u8BED_u8A00_u4E13_u5BB6_uFF1A"><a href="#5_u6BB5_u2013_u8BED_u8A00_u4E13_u5BB6_uFF1A" class="headerlink" title="5段–语言专家:"></a>5段–语言专家:</h3><p>经过一段时间的编程实践,程序员对某一种常用的编程语言已经相当精通了。有些人还成了“语言律师”,擅长向其他程序员讲解语言的用法和各种坑。<br>这一阶段的程序员,常常是自己所用语言的忠实信徒,常在社区和论坛上和其他语言的使用者争论哪一种语言是最好的编程语言。他们认为自己所用的语言是世界上最好的编程语言,没有之一。他们认为,自己所用的编程语言适用于所有场景。他们眼中,只有锤子,因此会把所有任务都当成是钉子。</p>
<h3 id="6_u6BB5_u2013_u591A_u8BED_u8A00_u4E13_u5BB6_uFF1A"><a href="#6_u6BB5_u2013_u591A_u8BED_u8A00_u4E13_u5BB6_uFF1A" class="headerlink" title="6段–多语言专家:"></a>6段–多语言专家:</h3><p>这一个阶段的程序员,因为工作关系,或者纯粹是因为对技术的兴趣,已经学习和掌握了好几种编程语言。已经领略了不同编程语言不同的设计思路,对每种语言的长处和短处有了更多的了解。<br>他们现在认为,编程语言并不是最重要的,编程语言不过是基本功而已。<br>他们现在会根据不同的任务需求,或者不同的资源来选择不同的编程语言来解决问题,不再会因为没有使用某一种喜爱的编程语言开发而埋怨。 </p>
<p>编程语言有很多种流派和思想,有一些编程语言同时支持多种编程范式。</p>
<h4 id="u9759_u6001_u7C7B_u578B_u7F16_u7A0B_u8303_u5F0F"><a href="#u9759_u6001_u7C7B_u578B_u7F16_u7A0B_u8303_u5F0F" class="headerlink" title="静态类型编程范式"></a>静态类型编程范式</h4><p>采用静态类型编程范式的编程语言,其变量需要明确指定类型。代表语言:<code>C,C++,Pascal,Objective-C,Java,C#,VB.NET,Swif,Golang</code>。</p>
<p><strong>这样做的好处是:</strong> </p>
<ol>
<li>编译器可以在编译时就能找出类型错误。 </li>
<li>编译器编译时知道类型信息,就可以提高性能。 </li>
</ol>
<p>这种范式认为,程序员肯定知道变量的类型,你丫要是不知道变量的类型,那你就别混了!编译时,程序会报错。<br>Swift和Go语言都是静态类型编程语言,但它们都不需要明确指定类型,而是可以通过推断由编译器自动确定其类型。 </p>
<h4 id="u52A8_u6001_u7C7B_u578B_u7F16_u7A0B_u8303_u5F0F"><a href="#u52A8_u6001_u7C7B_u578B_u7F16_u7A0B_u8303_u5F0F" class="headerlink" title="动态类型编程范式"></a>动态类型编程范式</h4><p>采用静态类型编程范式的编程语言,其变量不需要明确指定类型。任意变量,可以指向任意类型的对象。代表语言:<code>Python,Ruby,JavaScript</code>。 </p>
<p>动态类型的哲学可以用鸭子类型(英语:ducktyping)这个概念来概括。JamesWhitcombRiley提出的鸭子测试可以这样表述:“当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。”</p>
<p>这种范式认为,程序员肯定知道变量的类型和它支持的方法和属性,你丫要是不知道变量的类型,那你就别混了!运行时程序会崩溃!程序崩溃怨谁?怨你自己呗,你不是合格的程序员!</p>
<p><strong>动态类型的好处是:</strong><br>不需要明确定义接口和抽象类型。只要一个类型支持需要的方法和属性,那么就OK。程序会相当灵活和简单。C++,Java,C#视之为命脉的接口/基类,在动态语言这里都视如无物!</p>
<p><strong>缺点是:</strong> </p>
<ol>
<li>如果类型不对,编译器也无法找到错误,而是运行时程序崩溃。</li>
<li>因为编译器不知道变量的类型,因此无法优化性能。</li>
</ol>
<h4 id="u9762_u5411_u5BF9_u8C61_u7F16_u7A0B_u8303_u5F0F"><a href="#u9762_u5411_u5BF9_u8C61_u7F16_u7A0B_u8303_u5F0F" class="headerlink" title="面向对象编程范式"></a>面向对象编程范式</h4><p>面向对象编程范式,从上世纪70年代末开始兴起。它支持类和类的实例作为封装代码的模块。代表语言:<code>Smalltalk,C++,Objective-C,Java,C#,VB.NET,Swift,Go,Python,Ruby,ActionScritp,OCaml</code>.</p>
<p>早期编程语言都是面向过程的。就是顺序,条件,循环,构成一个个函数。随着代码规模的增大,人们发现有必要对代码进行模块化。一个概念对应的代码放在一个文件中,这样便于并发开发和进行代码管理。</p>
<p>人们还发现了“程序=数据结构+算法”的规律。因此,一个概念对应的数据结构和函数应该放在一个文件中。这就是类的概念。</p>
<p>面向对象编程范式,确实极大地提高了生产效率,因此得到了广泛的应用,因此在语言层面支持面向对象编程范式的语言是极多的。</p>
<p>C语言尽管在语言层面上并不支持面向对象编程范式,但现代的C语言开发都会应用面向对象的模块化思想,把同一类的数据结构和函数放在一个文件中,采用类似的命名方式。</p>
<p>毕竟C语言没有在语言层面上支持面向对象,因此就有很多程序员想给C语言添加面向对象支持。其中的代表是C++和Objective-C。</p>
<p>C++是一种新的语言,但大部分语言元素是和C兼容的。</p>
<p>Objective-C是完全兼容的C的。Objective-C是给C添加了薄薄的一层语法糖以支持接口(就是其他语言的类)和协议(就是其他语言的接口)。甚至,Objective-C一开始的实现,就是一个C语言的预编译器。Objective-C坦白讲,除了添加的语法不太符合C流外,实际上其面向对象系统设计是相当精妙的。乔布斯早年慧眼识珠,把Objective-C收人囊中,因为封闭于Apple/NextStep系统内,因此少有人知。随着iOs系统的普及,Objective-C近几年才名满天下。</p>
<h4 id="u51FD_u6570_u5F0F_u7F16_u7A0B_u8303_u5F0F"><a href="#u51FD_u6570_u5F0F_u7F16_u7A0B_u8303_u5F0F" class="headerlink" title="函数式编程范式"></a>函数式编程范式</h4><p>函数式编程范式,是一些数学家发明的编程语言,他们认为程序就是数学函数嘛。代表语言:<code>Lisp,Erlang,JavaScript,OCaml,Prog</code>。</p>
<p>有很多大牛极力鼓吹过函数式编程语言,认为其极具革命性。但我认为他们过高估计了函数式编程范式的威力,我并不认为函数式编程范式相对于面向对象编程范式有何高明之处。</p>
<p>函数式编程语言,核心就是函数,它们没有Class类的概念。但它的函数又不是传统面向过程语言的函数,它的函数支持“闭包”的概念。</p>
<p>在我看来,函数式编程语言的函数,也就是“闭包”,说白了,其实就是“类”。编程语言发展到今天,就是需要模块化,就是需要把“数据结构”和“算法”结合起来。不论何种语言,不把它们结合起来的编程方式,都是没有出路的。</p>
<p>面向对象编程语言,用类把“数据结构”和“算法”结合起来。类的核心是“数据结构”,也就是其“属性”,而不是“算法”,其“函数”。在类中,是函数依附于属性。</p>
<p>而函数式编程语言,用闭包把“数据结构”和“算法”结合起来。是函数能够抓取外部的字段。是“属性”依附于“函数”。</p>
<p>“类”本质上和“闭包”是等价的。现在很多面向对象编程语言都加上了对闭包的支持。观察其代码,我们可以发现,它们实际上都是用“类”来实现“闭包”的。</p>
<p>“类”和“闭包”谁更易用?明显是“类”。</p>
<p>而“闭包”更简洁一些,因此“闭包”在面向对象编程语言中常用来替换匿名类。只有一个函数的类,写成一个类太麻烦,不如写成闭包,更加简洁。</p>
<p>吐槽一下OCaml语言,其前身Caml语言本身是一种挺好的函数式语言,硬生生添加了一套完整的面向对象机制,同时支持面向对象和函数式编程范式,很容易像C++一样脑裂的。</p>
<p>也有很多面向对象语言控看着JavaScript嫌烦,总是想把面向对象支持添加到JavaScript上。ActionScript就是其中一种尝试。我用过,真的是和Java没多少区别了。</p>
<p>再吐槽一下ExtJS。当初选型Web前端开发框架时比较了ExtJS和JQuery。</p>
<p>ExtJS明显是Java高手开发的,硬生生用JavaScript模拟Swing的设计思想,搞了一套UI库。</p>
<p>JQuery开发者明显是领悟了JavaScript的函数式编程范式,依据JavaScript的动态函数式编程语言的特点打造了一套UI库,立刻秒杀ExtJS。</p>
<p>由ExtJS和JQuery的故事,我们可以看到多语言编程能力是多么的重要。ExtJS的作者精通并喜爱Java,因此他把手术刀JavaScript当做锤子Java使,一通乱敲,费力不讨好。</p>
<p>函数式编程语言,还有尾递归等一些小技巧。尾递归可以不用栈,防止递归调用时栈溢出。</p>
<h4 id="u6A21_u677F_u7F16_u7A0B_u8303_u5F0F"><a href="#u6A21_u677F_u7F16_u7A0B_u8303_u5F0F" class="headerlink" title="模板编程范式"></a>模板编程范式</h4><p>模板编程,就是把类型作为参数,一套函数可以支持任意多种类型。代表语言:<code>C++</code>。</p>
<p>模板编程的需求,是在C++开发容器库的时候发明的。因为容器需要保存任意类型的对象,因此就有了泛型的需求。</p>
<p>C++的模板编程,是在编译时,根据源码中的使用情况,创建对应类型的代码。除了C++这种方式,Java,C#也有类似的机制,叫做“泛型”,但它们的实现方式和C++的模板很不同。它们的编译器不会生成新的代码,而是使用强制类型转换的方式实现。</p>
<p>在没有模板/泛型的编程语言中,怎样在容器中存放对象呢?存取公共基类类型(Java,C#)的对象,或者void*指针(C)即可,取出时自己强制类型转换为实际类型。动态类型语言,不关心类型,更是无所谓了,随便什么对象直接往容器里扔进去,取出来直接用即可。</p>
<p>一些C++高手又在模板的基础上搞出了“模板元编程”。因为模板编程,就是C++的编译器搞定的嘛,模板元编程就是让编译器运算,编译完结果也就算出来了。我不知道除了研究和炫技,这玩意有啥用?</p>
<h4 id="u5C0F_u7ED3"><a href="#u5C0F_u7ED3" class="headerlink" title="小结"></a>小结</h4><p>一门语言是否值得学习,我认为有几个标准:</p>
<ol>
<li>是否要用,要用就得学,这么没有疑问的。毕竟我们都要吃饭的嘛。 </li>
<li>其语言特性是否给你耳目一新的感觉。如果是,那就值回票价了。如Go语言废掉了异常,改用返回多值。我深以为然。我其实已经主动不用异常好多年了。因为,我觉得既然C不支持异常也活得很好,为什么需要异常呢?出错了,返回错误码。无法挽回的错误,直接Abort程序就可以嘛!而且,异常实际上是违反面向过程编程原则的。一个函数应该只有一个入口一个出口。抛出异常就多了出口了。 </li>
<li>是否擅长某一个领域。如果你手里只有一把锤子,那么你就只能把所有任务都当做钉子猛锤一通。但如果工具箱里有多种工具,那面对不同的任务就得心应手多了。 </li>
</ol>
<h3 id="7_u6BB5_u2014_u67B6_u6784_u8BBE_u8BA1"><a href="#7_u6BB5_u2014_u67B6_u6784_u8BBE_u8BA1" class="headerlink" title="7段—架构设计"></a>7段—架构设计</h3><p>还需要掌握架构设计的能力,才能设计出优秀的软件。架构设计有一些技巧:</p>
<h4 id="1_u3001_u5206_u5C42"><a href="#1_u3001_u5206_u5C42" class="headerlink" title="1、分层"></a>1、分层</h4><p>一个软件通常分为: </p>
<blockquote>
<p>表现层–UI部分<br>接口层–后台服务的通讯接口部分<br>服务层–实际服务部分<br>存储层—持久化存储部分,存储到文件或者数据库。 </p>
</blockquote>
<p>分层的软件,可以解耦各个模块,支持并行开发,易于修改,易于提升性能。</p>
<h4 id="2_u3001SOA"><a href="#2_u3001SOA" class="headerlink" title="2、SOA"></a>2、SOA</h4><p>模块之间通过网络通讯互相连接,松耦合。每一个模块可以独立部署,可以增加部署实例从而提高性能。每一个模块可以使用不同的语言和平台开发,可以重用之前开发的服务。SOA,常用协议有WebService,REST,JSON-RPC等。</p>
<h4 id="3_u3001_u6027_u80FD_u74F6_u9888"><a href="#3_u3001_u6027_u80FD_u74F6_u9888" class="headerlink" title="3、性能瓶颈"></a>3、性能瓶颈</h4><p>1). 化同步为异步。<br>用内存队列(Redis),工作流引擎(JBpm)等实现。内存队列容易丢失数据,但是速度快。工作流引擎会把请求保存到数据库中。<br>通过化同步请求为异步请求,基本上99.99%的性能问题都可以解决。</p>
<p>2). 用单机并行硬件处理。<br>如,使用GPU,FPGA等硬件来处理,提高性能。</p>
<p>3). 用集群计算机来处理。<br>如,Hadoop集群,用多台计算机来并行处理数据。<br>自己的软件栈中,也可以把一个模块部署多份,并行处理。</p>
<p>4). 用cache来满足请求。常用的内容加热cache后,大量的用户请求都只是内存读取数据而已,性能会得到很大的提升。<br>cache是上帝算法,记得好像它的性能只比最佳性能低一些,就好像你是上帝,能够预见未来一样。现在X86CPU遇到了主频限制,CPU提升性能的主要途径就是增加高速Cache了。</p>
<h4 id="4_u3001_u5927_u7CFB_u7EDF_u5C0F_u505A"><a href="#4_u3001_u5927_u7CFB_u7EDF_u5C0F_u505A" class="headerlink" title="4、大系统小做"></a>4、大系统小做</h4><p>遇到大型系统不要慌,把它切分成多个模块,用多个小程序,通过SOA协作来解决。这秉承了Unix的设计思想。Unix上开发了大量单一目的的小程序,它主张用户通过管道来让多个小程序协作,解决用户的需求。当然,管道方式通讯限制太多,不够灵活。因此,现在我们可以通过URI,通过SOA的方式来让多个程序协作。Andorid和iOS上的应用程序,现在都是通过URI实现协作的。这也算是Unix设计思想的现代发展吧?!</p>
<h4 id="5_u3001Sharding_u5207_u7247"><a href="#5_u3001Sharding_u5207_u7247" class="headerlink" title="5、Sharding切片"></a>5、Sharding切片</h4><p>现在有一个潮流,就是去IOE。I-IBM大型机,O-Oracle数据库,E-EMC存储。之前,大型系统常用IOE去架构,在大型机上部署一个Oracle数据库,Oracle数据库用EMC存储保存数据。IOE是当今最强的计算机,数据库和存储。但他们面对海量系统也有抗不住的一天。</p>
<p>Oracle数据库是Shareeverything的,它可以在一个计算机集群(服务器节点不能超过16个)上运行。计算机集群都共用一个存储。</p>
<p>去IOE运动,标志着ShareEverything模式的破产。必须使用ShareNothing,系统才能无限扩展。</p>
<p>用MySQL数据库就可以应付任意规模的数据了。前提是,你会Sharding分片。把大系统切分成若干个小系统,切分到若干台廉价服务器和存储上。更Modern一些,就是切分到大量虚拟机上。</p>
<p>如,铁道部的12306网站。我们知道火车票都是从属于某一列列车的。那么我们把每一个列车作为一个单元来切分,就可以把12306网站切分成几千个模块。一台虚拟机可以承载若干个模块。当某些列车成为性能瓶颈之后,就可以把它们迁移到独立的虚拟机上。即使最终有部分列出服务不可用,系统也不会完全不可用。</p>
<p>12306网站,只有一个全局的部分,就是用户登录。这个可以交给第三方负责。如可以让用户用微信,微博,qq等账户登录。</p>
<p>也可以自己实现用户登录服务。还是用切片的方式用多台Redis服务器提供服务。Redis服务器存储每一个登录用户的sessionId和userId,角色,权限等信息。sessionId是随机生成的,可选择其部分bit用于标识它在哪一个Redis服务器上。用户登录后,把sessionId发给客户。用户每次请求时把sessionId发回给服务器。服务器把sessionId发给Redis服务器查询得到其用户信息,对用户请求进行处理。如果在redis服务器上找不到sessionId,则让用户去登录。即使所有注册用户同时登陆,也不需要太多的内存。而且,可以在session内存过多时,删除最早登陆的用户的session,强制他再次登陆。同时活跃的用户数不会太多。</p>
<h2 id="u9886_u57DF_u77E5_u8BC6_u5C42_u6B21"><a href="#u9886_u57DF_u77E5_u8BC6_u5C42_u6B21" class="headerlink" title="领域知识层次"></a>领域知识层次</h2><p>前面的所有层次,都是关注编程本身的技能,说白了,就是基本功,本身并不能产生太大的价值。但有太多的程序员浪费太多的时间在那些筑基的层次上。</p>
<p>有些程序员特别喜欢钻研编程语言,每有一种新的编程语言出来或者旧语言被热炒,就会投入精力进去研究。我就是其中之一,浪费了很多精力在编程语言上,在奇技淫巧上。</p>
<p>我觉得C++语言是一个特别大的坑。刚开始是作为面向对象的C被开发的。后来发现了模板编程,就大力鼓吹模板编程和进一步的模板元编程。最近又推出了C++11,C++14等新标准,进一步添加了很多新东西,函数式编程,类型推断等。C++过分复杂,太多的坑消耗了大量程序员的大量精力。我使用C++时,只使用面向对象部分和模板部分,其他过于精深的特性都不使用。</p>
<p>计算机科学是一个面相当广泛的学科,有很多领域知识需要和值得我们深入研究,我们才能写出有价值的程序来。软件必须要和行业结合起来,要落地才有价值。仅仅研究编程技巧,不懂领域知识是写不出有价值的程序的。</p>
<p><strong>计算机科学领域有很多,列举一些如下:</strong></p>
<ul>
<li><p>存储—-块设备,文件系统,集群文件系统,分布式文件系统,光纤SCSI,iSCSI,RAID等。</p>
</li>
<li><p>网络—-以太网,光纤网,蜂窝网络,WIFI,VLAN等。</p>
</li>
<li><p>计算机体系结构,主要就是CPU指令集。x86,ARM等。</p>
</li>
<li><p>USB协议。需要知道URB包。</p>
</li>
<li><p>PCI协议,PCI-E协议。现代计算机的外设都是PCI协议和PCI-E协议的。显卡现在全是通过 PCI-E协议连接到计算机上的。相对来说减少了很多需要学习的知识。搞虚拟化就需要深入掌握PCI协议。</p>
</li>
<li><p>图像处理–图像压缩,视频实时编码等。</p>
</li>
<li><p>3D游戏</p>
</li>
<li><p>关系数据库</p>
</li>
<li><p>NoSQL数据库</p>
</li>
<li><p>操作系统</p>
</li>
<li><p>分布式操作系统</p>
</li>
<li><p>编译原理</p>
</li>
<li><p>机器学习–现在大数据要用哦!</p>
</li>
</ul>
<p>了解这些领域知识,也包括了解该领域现有的商用硬件、商用软件和开源软件。很多时候,你要完成的工作,已经有现成的工具了。你只要使用现成的工具就可以完成任务,不需要进行开发。有时候,只需要组合现有的工具,写一些脚本就可以完成任务。</p>
<p>如,我一次要实现一个双向同步任务。找到了一个优秀的开源软件Unison,编写一下配置文件就圆满地完成了任务。不需要编写任何代码。</p>
<p>还有一次,要做高可用,用Python调用了几个开源软件就轻松实现了。</p>
<p>编写安装程序,定制操作系统,知道了操作系统的领域知识,写几行脚本就可以轻松搞定。</p>
<p>不具备领域知识的人,就可能不得不进行大量无谓的开发,甚至开发很久之后才发现,这根本就是一条死路。</p>
<p>另外,扎实的领域知识,可以大大提高编程调试、查错的能力。知道编译器和编程语言运行时工作原理,就能快速根据编译错误和警告信息修改代码。</p>
<p>知道操作系统底层运行机制,就能快速找到运行时错误的问题根源。如,有一次我编写一个windows升级服务程序。它是一个windows服务,需要执行dos脚本,这个脚本会替换掉这个windows服务本身。发现有时脚本执行无效,查了一晚上,发现当windows服务安装后,第一次启动就执行脚本时就会有权限问题,log都正确,但实际执行这个脚本没有任何效果。但一旦windows服务程序启动一次之后就ok。这必然是windows操作系统底层安全机制的问题,因为我对Windows内核了解不多,因此花了很长时间才发现这个问题,并对造成这个问题的根源并不清楚。</p>
<h3 id="0_u6BB5_u2014_u9886_u57DF_u77E5_u8BC6_u83DC_u9E1F"><a href="#0_u6BB5_u2014_u9886_u57DF_u77E5_u8BC6_u83DC_u9E1F" class="headerlink" title="0段—领域知识菜鸟"></a>0段—领域知识菜鸟</h3><p>对领域知识没有多少认知,通过搜索引擎找到一些该领域的软件和硬件的介绍性文章,按照文章指示配置和使用软件。勉强能够使用现有软硬件。</p>
<h3 id="1_u6BB5_u2014_u9886_u57DF_u77E5_u8BC6_u884C_u5BB6"><a href="#1_u6BB5_u2014_u9886_u57DF_u77E5_u8BC6_u884C_u5BB6" class="headerlink" title="1段—领域知识行家"></a>1段—领域知识行家</h3><p>了解领域内常用硬件,深入掌握领域内常用软件的配置和使用技巧。能够使用现有软硬件熟练搭建解决方案,能够解决实际工作中遇到的种种问题。</p>
<h3 id="2_u6BB5_u2014_u9886_u57DF_u77E5_u8BC6_u4E13_u5BB6"><a href="#2_u6BB5_u2014_u9886_u57DF_u77E5_u8BC6_u4E13_u5BB6" class="headerlink" title="2段—领域知识专家"></a>2段—领域知识专家</h3><p>当你不仅仅掌握了该领域的软件和工具,知道怎么用,还知道其原理,“知其然,也知其所以然”,就是该领域的知识专家了。</p>
<p>你知道网络协议的原理,你才能在网络出现问题时知道是哪里可能出现了问题。是mac冲突,ip冲突,还是网络环路?</p>
<p>你知道存储的原理,你才能知道为什么这种存储方式不适合虚拟化,那种存储方式适合虚拟化,另一种方式适合资料备份。</p>
<p>你知道PCI协议,你才能知道你怎样才能虚拟化一个硬件设备。</p>
<p>你知道网卡硬件协议,你才能模拟出一个虚拟机能正常使用的虚拟网卡。</p>
<p>你知道视频编码格式和原理,才能知道什么视频格式占用带宽最少,什么视频格式占用CPU最少。</p>
<p>你了解IntelVT/Amd V指令集,才能知道虚拟化是怎样实现的。</p>
<p>你明白工作流其实就是状态机,在遇到复杂工作流程时,你才能知道怎样设计满足要求的工作流引擎。</p>
<h3 id="3_u6BB5_u2014_u79D1_u5B66_u5BB6"><a href="#3_u6BB5_u2014_u79D1_u5B66_u5BB6" class="headerlink" title="3段—科学家"></a>3段—科学家</h3><p>你是领域知识专家,但你的知识都是来自于书本,来自于其他人的。</p>
<p>如果你满足于当领域知识专家,你只能拾人牙慧,永远别想超越。别人的研究成果,未必愿意告诉你。当别人告诉你的时候,它可能已经发现了更新的理论,并且新一代产品可能马上就要发布了。</p>
<p>科学家是探索未知,勇于创新的人,是推动人类社会进步的人。</p>
<p>传说,思科的一位高管曾经半开玩笑地说过:“如果思科停止了新技术的研发,华为就会找不着方向”。这是在嘲笑华为只是处在领域知识专家的水平,只能山寨无法超越。我不知道华为的实际情况,但希望现在的华为已经走到了领跑者的位置。</p>
<p>欧文·雅各布斯发现了CDMA码分多址的原理,并发现它在通讯上大有可为,组建了高通公司。高通公司主要以专利授权费为生,它雇佣了大量科学家在通讯领域展开研究。有人说高通是专利流氓。这些人不明白知识的价值。在他们眼里,Windows的合理价格就应该是5元钱,一张光盘的价格。iPhone就应该是1000多元裸机的价格。高通是专利流氓,那你也流氓一个CDMA,LTE出来给我看看!</p>
<p>X86芯片在设计上没有考虑虚拟化。因此会有所谓的“虚拟化漏洞”出现。就是说,一些CPU特权指令执行时,在虚拟机环境下不会抛出异常,因此就无法切换到Host。这样,X86芯片上就无法运行虚拟机。</p>
<p>VmWare公司是由美国的几位科学家在1998年创建的。他们发现可以使用二进制翻译的技术,在X86计算机上运行虚拟机。</p>
<p>Xen虚拟化软件也是几位科学家发明的。他们发现只要修改虚拟机操作系统和Host操作系统的内核,在需要执行“虚拟化漏洞”指令时直接调用Host的功能,就可以实现虚拟化,而且大大提高了虚拟机的运行性能。</p>
<p>后来,Intel为自己的芯片添加了IntelVT指令集,Amd为自己的芯片添加了AmdV指令集,弥补了“虚拟化漏洞”。于是就有了KVM虚拟机软件,它直接用CPU硬件指令实现虚拟化。</p>
<p>KVM在执行CPU指令时,是直接在物理CPU上运行的,因此效率极高。但是,虚拟机运行虚拟外设时,就必须用软件模拟,因此虚拟机的IO访问速度很慢。</p>
<p>IBM科学家RustyRussell,借鉴了Xen的研发经验,创建了VirtIO技术。就是在虚拟机中编写一套PCI虚拟设备和驱动,这套虚拟PCI设备有一块虚拟设备内存。这个虚拟设备内存Host是可以访问的,虚拟机通过VirtIO驱动程序也可以访问。也就是一块内存在虚拟机和Host中共享,这就解决了虚拟机的IO性能问题。</p>
<p><strong>再讲一个搜索引擎的故事:</strong></p>
<blockquote>
<p>很久以前,我要给一个程序添加搜索功能。刚开始使用sql查询实现,发现实在太慢了。后来找了开源的Lucene项目。它使用反向索引技术,通过在文件中创建反向索引,大大提高了搜索速度。</p>
<p>Google的两位创始人发现了html中link的秘密,他们发现可以通过html页面的link关系来为每一个html页面设置权重。也就是PageRank算法。于是,Google的自动搜索引擎击败了Yahoo人工分类的搜索引擎。</p>
<p>OK,利用反向索引技术和PageRank,以及一个简单的html爬虫机器人,我们就可以创建一个搜索引擎了。但是,互联网很大,每天产生大量新网页,要为整个互联网建立反向索引是很困难的。</p>
<p>若干年后Google又公开了三篇论文:Googlefs,Mapreduce,Bigtable。于是Lucene项目的开发者根据Google的Mapreduce论文开发了Hadoop项目。MapReduce就是使用大量计算机存储数据并计算,最后汇总结果。使用Hadoop+反向索引+PageRank,就可以创建搜索引擎了。Yahoo,Baidu等公司纷纷基于Hadoop开发了自己的搜索引擎。</p>
<p>但是,其他公司的搜索引擎效果还是没法和Google相比。这一点我们程序员最清楚。像我,就总是翻墙出去,只为了Google一下。</p>
<p>Google黑板报上发表了吴军博士的一些文章,其中介绍了很多机器学习方面的知识。从文中可以知道,Google其实使用机器学习来分析搜集到的页面。Google明显不会把这个公式公开出来。即使有一天Google真的公开了这个公式,那么可以想见Google肯定又研发出了更加犀利的秘籍,山寨货的搜索引擎效果还是比不上Google的。</p>
</blockquote>
<p>山寨是通向创新的必由之路。在成为领域的领头羊和领导者之前,必然要经过学习,模仿的阶段。但要成为行业的老大,成为Champion,必须勇于弯道超车,勇敢地走上创新之路,成为真正的科学家,真正的大牛!</p>
<h2 id="u603B_u7ED3"><a href="#u603B_u7ED3" class="headerlink" title="总结"></a>总结</h2><p>编程能力可分为两个维度:一个是编程技能水平,另一个是领域知识水平。</p>
<p>有些程序员可能把精力都花在提升编程技能上了,领域知识知之甚少,这其实在日常工作中也是极其有害的。有些需求可能早已经有了现成、开源免费的解决方案,或者只需要组合几个现有软件就可以快速搞定,而他们却不得不自己花大量时间去开发。另外,缺少领域知识,在程序出现非预期状况时,很难快速定位到问题的根源,很难解决bug。</p>
<blockquote>
<p>来源:良少的博客(@虚拟化良少)<br>链接:<a href="http://blog.csdn.net/shendl/article/details/43835421" target="_blank" rel="external">http://blog.csdn.net/shendl/article/details/43835421</a></p>
</blockquote>
]]></content>
<summary type="html">
<![CDATA[<h2 id="u524D_u8A00"><a href="#u524D_u8A00" class="headerlink" title="前言"></a>前言</h2><p>程序员的编程技能随着经验的积累,会逐步提高。我认为编程能力可以分为一些层次。<br>下面通过两个维度展开]]>
</summary>
<category term="编程能力" scheme="http://sphenginx.github.io/tags/%E7%BC%96%E7%A8%8B%E8%83%BD%E5%8A%9B/"/>
<category term="日薪越亿" scheme="http://sphenginx.github.io/categories/%E6%97%A5%E8%96%AA%E8%B6%8A%E4%BA%BF/"/>
</entry>
<entry>
<title><![CDATA[如何在Lumen框架下写一个自己的Log类?]]></title>
<link href="http://sphenginx.github.io/2015/12/18/ioc/"/>
<id>http://sphenginx.github.io/2015/12/18/ioc/</id>
<published>2015-12-18T08:03:01.000Z</published>
<updated>2015-12-18T08:31:47.016Z</updated>
<content type="html"><![CDATA[<h2 id="u524D_u8BB0"><a href="#u524D_u8BB0" class="headerlink" title="前记"></a>前记</h2><p>今天在使用<strong>lumen</strong>自带的类Log的时候,发现每次记录一个Log,总会在<code>storage/logs/lumen.log</code>文件末尾追加一条记录,那么问题来了,时间久了,lumen.log 这个文件就会非常大,而且也不利于管理,于是打算写一个自己的log类,在各位网友博客小伙伴的帮助下,终于完成了,记录一下写Log的历程,希望能帮助一些后来打算改造Log类的小伙伴吧。</p>
<h2 id="Lumen"><a href="#Lumen" class="headerlink" title="Lumen"></a>Lumen</h2><p>开始前,先让我们了解下lumen:</p>
<p>Lumen 是一个由 Laravel 元件搭建而成的微框架, 由 Laravel 官方维护. Lumen 为速度而生, 是当前最快的 PHP 框架之一, 甚至比类似的微框架 Silex 速度还要快.</p>
<p>Lumen 比其他微框架的优点是, 构建在 Laravel 之上, 使其具备 Laravel 强大的功能, 如 路由, 依赖注入, Eloquent ORM, 数据库迁移管理, 队列和计划任务等.</p>
<p>Laravel 本来就是一个功能齐全, 速度飞快的框架, 但是 Lumen 因为去除了很多 Laravel 的配置和可自定义的选项, 速度越加飞快, 毫秒必争.</p>
<p>飞快的速度, 再加上 Laravel 非常方便的功能, 使用 Lumen 开发应用会是非常愉悦的体验.</p>
<p>Lumen 专为微服务或者 API 设计, 举个例子, 如果你的应用里面有部分业务逻辑的请求频率比较高, 就可以单独把这部分业务逻辑拿出来, 使用 Lumen 来构建一个小 App.</p>
<p>因为 Lumen 是对 Laravel 优化了框架的加载机制, 所以 Lumen 对资源的要求少很多.</p>
<p>当然, 你可以使用 队列系统 与你的主 Laravel 应用进行交互. Laravel 和 Lumen 从一开始就是设计成能一起很好的工作, 并且, 配合使用, 允许你构架一个强大的, 以微服务为驱动的应用程序.</p>
<p>Lumen 同时也非常适用于构建 API 接口, 此类型的应用通常情况下不需要具备 全栈框架 的所有功能, 如 HTTP 会话管理, Cookies, 和模版系统.</p>
<h2 id="u5386_u7A0B"><a href="#u5386_u7A0B" class="headerlink" title="历程"></a>历程</h2><p>简单的了解了Lumen,那么接下来就来介绍Log的封装过程吧,在介绍前,各位看官如果对lumen的加载机制不清楚,不妨看下这篇文章:<a href="https://phphub.org/topics/769" target="_blank" rel="external">Laravel 架构中的 Container/ServiceProvider/Facade</a>。</p>
<h3 id="u4E86_u89E3_u7CFB_u7EDF_u7684Log_u7C7B"><a href="#u4E86_u89E3_u7CFB_u7EDF_u7684Log_u7C7B" class="headerlink" title="了解系统的Log类"></a>了解系统的Log类</h3><p>Lumen文档 <a href="http://laravelacademy.org/post/465.html" target="_blank" rel="external">错误和日志</a> 介绍了如何使用Lumen的错误和日志类,而且该日志记录器提供了<a href="http://tools.ietf.org/html/rfc5424" target="_blank" rel="external">RFC 5424</a>中定义的七种日志级别:<code>alert, critical, error,warning, notice, info 和 debug</code>。我们看到以下代码<br><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">use</span> <span class="title">Log</span>;</span><br></pre></td></tr></table></figure></p>
<p>既然Log类可以直接应用,说明Lumen在初始化的时候就定义了 Log 的 <code>namespace</code> 或者 起了 Log的 <code>aliases</code>, 首先找namespace,没有找到定义Log 的 namespace的地方,那肯定是起了 Log 的别名,找了些资料,终于发现Log的加载流程:</p>
<ol>
<li>根目录下<code>bootstrap\app.php</code>文件有一行代码:<figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$app</span>->withFacades();</span><br></pre></td></tr></table></figure>
</li>
</ol>
<p>这一行是调用 <code>vendor\laravel\lumen-framework\src\Application->withFacades()</code> 方法,会加载Lumen的一些Facades,下面列了 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><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span><br><span class="line"> * Create a new Lumen application instance.</span><br><span class="line"> *</span><br><span class="line"> * <span class="doctag">@param</span> string|null $basePath</span><br><span class="line"> * <span class="doctag">@return</span> void</span><br><span class="line"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span><span class="params">(<span class="variable">$basePath</span> = null)</span></span><br><span class="line"></span>{</span><br><span class="line"> date_default_timezone_set(env(<span class="string">'APP_TIMEZONE'</span>, <span class="string">'Asia/Chongqing'</span>));</span><br><span class="line"></span><br><span class="line"> <span class="variable">$this</span>->basePath = <span class="variable">$basePath</span>;</span><br><span class="line"> <span class="variable">$this</span>->bootstrapContainer();</span><br><span class="line"> <span class="variable">$this</span>->registerErrorHandling();</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span><br><span class="line"> * Bootstrap the application container.</span><br><span class="line"> *</span><br><span class="line"> * <span class="doctag">@return</span> void</span><br><span class="line"> */</span></span><br><span class="line"><span class="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">bootstrapContainer</span><span class="params">()</span></span><br><span class="line"></span>{</span><br><span class="line"> <span class="keyword">static</span>::setInstance(<span class="variable">$this</span>);</span><br><span class="line"></span><br><span class="line"> <span class="variable">$this</span>->instance(<span class="string">'app'</span>, <span class="variable">$this</span>);</span><br><span class="line"> <span class="variable">$this</span>->instance(<span class="string">'path'</span>, <span class="variable">$this</span>->path());</span><br><span class="line"></span><br><span class="line"> <span class="variable">$this</span>->registerContainerAliases();</span><br><span class="line">}</span><br><span class="line"><span class="comment">/**</span><br><span class="line"> * Register the facades for the application.</span><br><span class="line"> *</span><br><span class="line"> * <span class="doctag">@return</span> void</span><br><span class="line"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">withFacades</span><span class="params">()</span></span><br><span class="line"></span>{</span><br><span class="line"> Facade::setFacadeApplication(<span class="variable">$this</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (! <span class="keyword">static</span>::<span class="variable">$aliasesRegistered</span>) {</span><br><span class="line"> <span class="keyword">static</span>::<span class="variable">$aliasesRegistered</span> = <span class="keyword">true</span>;</span><br><span class="line"></span><br><span class="line"> class_alias(<span class="string">'Illuminate\Support\Facades\App'</span>, <span class="string">'App'</span>);</span><br><span class="line"> class_alias(<span class="string">'Illuminate\Support\Facades\Auth'</span>, <span class="string">'Auth'</span>);</span><br><span class="line"> class_alias(<span class="string">'Illuminate\Support\Facades\Bus'</span>, <span class="string">'Bus'</span>);</span><br><span class="line"> class_alias(<span class="string">'Illuminate\Support\Facades\DB'</span>, <span class="string">'DB'</span>);</span><br><span class="line"> class_alias(<span class="string">'Illuminate\Support\Facades\Cache'</span>, <span class="string">'Cache'</span>);</span><br><span class="line"> class_alias(<span class="string">'Illuminate\Support\Facades\Cookie'</span>, <span class="string">'Cookie'</span>);</span><br><span class="line"> class_alias(<span class="string">'Illuminate\Support\Facades\Crypt'</span>, <span class="string">'Crypt'</span>);</span><br><span class="line"> class_alias(<span class="string">'Illuminate\Support\Facades\Event'</span>, <span class="string">'Event'</span>);</span><br><span class="line"> class_alias(<span class="string">'Illuminate\Support\Facades\Hash'</span>, <span class="string">'Hash'</span>);</span><br><span class="line"> class_alias(<span class="string">'Illuminate\Support\Facades\Log'</span>, <span class="string">'Log'</span>);</span><br><span class="line"> class_alias(<span class="string">'Illuminate\Support\Facades\Mail'</span>, <span class="string">'Mail'</span>);</span><br><span class="line"> class_alias(<span class="string">'Illuminate\Support\Facades\Queue'</span>, <span class="string">'Queue'</span>);</span><br><span class="line"> class_alias(<span class="string">'Illuminate\Support\Facades\Request'</span>, <span class="string">'Request'</span>);</span><br><span class="line"> class_alias(<span class="string">'Illuminate\Support\Facades\Schema'</span>, <span class="string">'Schema'</span>);</span><br><span class="line"> class_alias(<span class="string">'Illuminate\Support\Facades\Session'</span>, <span class="string">'Session'</span>);</span><br><span class="line"> class_alias(<span class="string">'Illuminate\Support\Facades\Storage'</span>, <span class="string">'Storage'</span>);</span><br><span class="line"> class_alias(<span class="string">'Illuminate\Support\Facades\Validator'</span>, <span class="string">'Validator'</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span><br><span class="line"> * Register container bindings for the application.</span><br><span class="line"> *</span><br><span class="line"> * <span class="doctag">@return</span> void</span><br><span class="line"> */</span></span><br><span class="line"><span class="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">registerLogBindings</span><span class="params">()</span></span><br><span class="line"></span>{</span><br><span class="line"> <span class="variable">$this</span>->singleton(<span class="string">'Psr\Log\LoggerInterface'</span>, <span class="function"><span class="keyword">function</span> <span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> Logger(<span class="string">'lumen'</span>, [<span class="variable">$this</span>->getMonologHandler()]);</span><br><span class="line"> });</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span><br><span class="line"> * Get the Monolog handler for the application.</span><br><span class="line"> *</span><br><span class="line"> * <span class="doctag">@return</span> \Monolog\Handler\AbstractHandler</span><br><span class="line"> */</span></span><br><span class="line"><span class="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">getMonologHandler</span><span class="params">()</span></span><br><span class="line"></span>{</span><br><span class="line"> <span class="keyword">return</span> (<span class="keyword">new</span> StreamHandler(storage_path(<span class="string">'logs/lumen.log'</span>), Logger::DEBUG))</span><br><span class="line"> ->setFormatter(<span class="keyword">new</span> LineFormatter(<span class="keyword">null</span>, <span class="keyword">null</span>, <span class="keyword">true</span>, <span class="keyword">true</span>));</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span><br><span class="line"> * Register the core container aliases.</span><br><span class="line"> *</span><br><span class="line"> * <span class="doctag">@return</span> void</span><br><span class="line"> */</span></span><br><span class="line"><span class="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">registerContainerAliases</span><span class="params">()</span></span><br><span class="line"></span>{</span><br><span class="line"> <span class="variable">$this</span>->aliases = [</span><br><span class="line"> <span class="string">'Illuminate\Contracts\Foundation\Application'</span> => <span class="string">'app'</span>,</span><br><span class="line"> <span class="string">'Illuminate\Contracts\Auth\Guard'</span> => <span class="string">'auth.driver'</span>,</span><br><span class="line"> <span class="string">'Illuminate\Contracts\Auth\PasswordBroker'</span> => <span class="string">'auth.password'</span>,</span><br><span class="line"> <span class="string">'Illuminate\Contracts\Cache\Factory'</span> => <span class="string">'cache'</span>,</span><br><span class="line"> <span class="string">'Illuminate\Contracts\Cache\Repository'</span> => <span class="string">'cache.store'</span>,</span><br><span class="line"> <span class="string">'Illuminate\Contracts\Config\Repository'</span> => <span class="string">'config'</span>,</span><br><span class="line"> <span class="string">'Illuminate\Container\Container'</span> => <span class="string">'app'</span>,</span><br><span class="line"> <span class="string">'Illuminate\Contracts\Container\Container'</span> => <span class="string">'app'</span>,</span><br><span class="line"> <span class="string">'Illuminate\Contracts\Cookie\Factory'</span> => <span class="string">'cookie'</span>,</span><br><span class="line"> <span class="string">'Illuminate\Contracts\Cookie\QueueingFactory'</span> => <span class="string">'cookie'</span>,</span><br><span class="line"> <span class="string">'Illuminate\Contracts\Encryption\Encrypter'</span> => <span class="string">'encrypter'</span>,</span><br><span class="line"> <span class="string">'Illuminate\Contracts\Events\Dispatcher'</span> => <span class="string">'events'</span>,</span><br><span class="line"> <span class="string">'Illuminate\Contracts\Filesystem\Factory'</span> => <span class="string">'filesystem'</span>,</span><br><span class="line"> <span class="string">'Illuminate\Contracts\Hashing\Hasher'</span> => <span class="string">'hash'</span>,</span><br><span class="line"> <span class="string">'log'</span> => <span class="string">'Psr\Log\LoggerInterface'</span>,</span><br><span class="line"> <span class="string">'Illuminate\Contracts\Mail\Mailer'</span> => <span class="string">'mailer'</span>,</span><br><span class="line"> <span class="string">'Illuminate\Contracts\Queue\Factory'</span> => <span class="string">'queue'</span>,</span><br><span class="line"> <span class="string">'Illuminate\Contracts\Queue\Queue'</span> => <span class="string">'queue.connection'</span>,</span><br><span class="line"> <span class="string">'Illuminate\Redis\Database'</span> => <span class="string">'redis'</span>,</span><br><span class="line"> <span class="string">'Illuminate\Contracts\Redis\Database'</span> => <span class="string">'redis'</span>,</span><br><span class="line"> <span class="string">'request'</span> => <span class="string">'Illuminate\Http\Request'</span>,</span><br><span class="line"> <span class="string">'Illuminate\Session\SessionManager'</span> => <span class="string">'session'</span>,</span><br><span class="line"> <span class="string">'Illuminate\Contracts\View\Factory'</span> => <span class="string">'view'</span>,</span><br><span class="line"> ];</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span><br><span class="line"> * The available container bindings and their respective load methods.</span><br><span class="line"> *</span><br><span class="line"> * <span class="doctag">@var</span> array</span><br><span class="line"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="variable">$availableBindings</span> = [</span><br><span class="line"> <span class="string">'auth'</span> => <span class="string">'registerAuthBindings'</span>,</span><br><span class="line"> <span class="string">'auth.driver'</span> => <span class="string">'registerAuthBindings'</span>,</span><br><span class="line"> <span class="string">'Illuminate\Contracts\Auth\Guard'</span> => <span class="string">'registerAuthBindings'</span>,</span><br><span class="line"> <span class="string">'auth.password'</span> => <span class="string">'registerAuthBindings'</span>,</span><br><span class="line"> <span class="string">'Illuminate\Contracts\Auth\PasswordBroker'</span> => <span class="string">'registerAuthBindings'</span>,</span><br><span class="line"> <span class="string">'Illuminate\Contracts\Broadcasting\Broadcaster'</span> => <span class="string">'registerBroadcastingBindings'</span>,</span><br><span class="line"> <span class="string">'Illuminate\Contracts\Bus\Dispatcher'</span> => <span class="string">'registerBusBindings'</span>,</span><br><span class="line"> <span class="string">'cache'</span> => <span class="string">'registerCacheBindings'</span>,</span><br><span class="line"> <span class="string">'Illuminate\Contracts\Cache\Factory'</span> => <span class="string">'registerCacheBindings'</span>,</span><br><span class="line"> <span class="string">'Illuminate\Contracts\Cache\Repository'</span> => <span class="string">'registerCacheBindings'</span>,</span><br><span class="line"> <span class="string">'config'</span> => <span class="string">'registerConfigBindings'</span>,</span><br><span class="line"> <span class="string">'composer'</span> => <span class="string">'registerComposerBindings'</span>,</span><br><span class="line"> <span class="string">'cookie'</span> => <span class="string">'registerCookieBindings'</span>,</span><br><span class="line"> <span class="string">'Illuminate\Contracts\Cookie\Factory'</span> => <span class="string">'registerCookieBindings'</span>,</span><br><span class="line"> <span class="string">'Illuminate\Contracts\Cookie\QueueingFactory'</span> => <span class="string">'registerCookieBindings'</span>,</span><br><span class="line"> <span class="string">'db'</span> => <span class="string">'registerDatabaseBindings'</span>,</span><br><span class="line"> <span class="string">'Illuminate\Database\Eloquent\Factory'</span> => <span class="string">'registerDatabaseBindings'</span>,</span><br><span class="line"> <span class="string">'encrypter'</span> => <span class="string">'registerEncrypterBindings'</span>,</span><br><span class="line"> <span class="string">'Illuminate\Contracts\Encryption\Encrypter'</span> => <span class="string">'registerEncrypterBindings'</span>,</span><br><span class="line"> <span class="string">'events'</span> => <span class="string">'registerEventBindings'</span>,</span><br><span class="line"> <span class="string">'Illuminate\Contracts\Events\Dispatcher'</span> => <span class="string">'registerEventBindings'</span>,</span><br><span class="line"> <span class="string">'Illuminate\Contracts\Debug\ExceptionHandler'</span> => <span class="string">'registerErrorBindings'</span>,</span><br><span class="line"> <span class="string">'files'</span> => <span class="string">'registerFilesBindings'</span>,</span><br><span class="line"> <span class="string">'filesystem'</span> => <span class="string">'registerFilesBindings'</span>,</span><br><span class="line"> <span class="string">'Illuminate\Contracts\Filesystem\Factory'</span> => <span class="string">'registerFilesBindings'</span>,</span><br><span class="line"> <span class="string">'hash'</span> => <span class="string">'registerHashBindings'</span>,</span><br><span class="line"> <span class="string">'Illuminate\Contracts\Hashing\Hasher'</span> => <span class="string">'registerHashBindings'</span>,</span><br><span class="line"> <span class="string">'log'</span> => <span class="string">'registerLogBindings'</span>,</span><br><span class="line"> <span class="string">'Psr\Log\LoggerInterface'</span> => <span class="string">'registerLogBindings'</span>,</span><br><span class="line"> <span class="string">'mailer'</span> => <span class="string">'registerMailBindings'</span>,</span><br><span class="line"> <span class="string">'Illuminate\Contracts\Mail\Mailer'</span> => <span class="string">'registerMailBindings'</span>,</span><br><span class="line"> <span class="string">'queue'</span> => <span class="string">'registerQueueBindings'</span>,</span><br><span class="line"> <span class="string">'queue.connection'</span> => <span class="string">'registerQueueBindings'</span>,</span><br><span class="line"> <span class="string">'Illuminate\Contracts\Queue\Factory'</span> => <span class="string">'registerQueueBindings'</span>,</span><br><span class="line"> <span class="string">'Illuminate\Contracts\Queue\Queue'</span> => <span class="string">'registerQueueBindings'</span>,</span><br><span class="line"> <span class="string">'redis'</span> => <span class="string">'registerRedisBindings'</span>,</span><br><span class="line"> <span class="string">'request'</span> => <span class="string">'registerRequestBindings'</span>,</span><br><span class="line"> <span class="string">'Illuminate\Http\Request'</span> => <span class="string">'registerRequestBindings'</span>,</span><br><span class="line"> <span class="string">'session'</span> => <span class="string">'registerSessionBindings'</span>,</span><br><span class="line"> <span class="string">'session.store'</span> => <span class="string">'registerSessionBindings'</span>,</span><br><span class="line"> <span class="string">'Illuminate\Session\SessionManager'</span> => <span class="string">'registerSessionBindings'</span>,</span><br><span class="line"> <span class="string">'translator'</span> => <span class="string">'registerTranslationBindings'</span>,</span><br><span class="line"> <span class="string">'url'</span> => <span class="string">'registerUrlGeneratorBindings'</span>,</span><br><span class="line"> <span class="string">'validator'</span> => <span class="string">'registerValidatorBindings'</span>,</span><br><span class="line"> <span class="string">'view'</span> => <span class="string">'registerViewBindings'</span>,</span><br><span class="line"> <span class="string">'Illuminate\Contracts\View\Factory'</span> => <span class="string">'registerViewBindings'</span>,</span><br><span class="line">];</span><br></pre></td></tr></table></figure>
<ol>
<li>通过看源码,我们发现有这么一个变量 <code>$availableBindings</code>, log最终是 <code>Monolog\Logger</code>类。如果看官不明白,可以参照上文中的<code>Facade</code>的原理链接,了解一下lumen的机制。</li>
</ol>
<h2 id="u96C6_u6210_u81EA_u5DF1_u7684Log_u7C7B"><a href="#u96C6_u6210_u81EA_u5DF1_u7684Log_u7C7B" class="headerlink" title="集成自己的Log类"></a>集成自己的Log类</h2><p>上文我们明白了Log既然是加载了 <code>Monolog\Logger</code> 类,那我们可以集成一个自己的Log类,最终代码如下<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></pre></td><td class="code"><pre><span class="line"><span class="preprocessor"><?php</span></span><br><span class="line"><span class="comment">/*</span><br><span class="line"> * To change this license header, choose License Headers in Project Properties.</span><br><span class="line"> * To change this template file, choose Tools | Templates</span><br><span class="line"> * and open the template in the editor.</span><br><span class="line"> * default log directory is storage/api/</span><br><span class="line"> * default log name format is YYYY-mm-dd.log</span><br><span class="line"> */</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> <span class="title">App</span>\<span class="title">Sphenginx</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">use</span> <span class="title">Monolog</span>\<span class="title">Logger</span>;</span><br><span class="line"><span class="keyword">use</span> <span class="title">Monolog</span>\<span class="title">Handler</span>\<span class="title">StreamHandler</span>;</span><br><span class="line"><span class="keyword">use</span> <span class="title">Monolog</span>\<span class="title">Formatter</span>\<span class="title">LineFormatter</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span><br><span class="line"> * user defined Log class, with StreamHandler and LineFormatter </span><br><span class="line"> *</span><br><span class="line"> * <span class="doctag">@author</span> Sphenginx</span><br><span class="line"> */</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Log</span> </span><br><span class="line"></span>{</span><br><span class="line"></span><br><span class="line"> <span class="comment">//define static log instance.</span></span><br><span class="line"> <span class="keyword">protected</span> <span class="keyword">static</span> <span class="variable">$_log_instance</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span><br><span class="line"> * 获取log实例</span><br><span class="line"> *</span><br><span class="line"> * <span class="doctag">@return</span> obj</span><br><span class="line"> * <span class="doctag">@author</span> Sphenginx</span><br><span class="line"> **/</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">getLogInstance</span><span class="params">()</span></span><br><span class="line"> </span>{</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">static</span>::<span class="variable">$_log_instance</span> === <span class="keyword">null</span>) {</span><br><span class="line"> <span class="keyword">static</span>::<span class="variable">$_log_instance</span> = <span class="keyword">new</span> Logger(<span class="string">'Sphenginx'</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">static</span>::<span class="variable">$_log_instance</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span><br><span class="line"> * Handle dynamic, static calls to the object.</span><br><span class="line"> *</span><br><span class="line"> * <span class="doctag">@param</span> string $method 可用方法: debug|info|notice|warning|error|critical|alert|emergency 可调用的方法详见 Monolog\Logger 类</span><br><span class="line"> * <span class="doctag">@param</span> array $args 调用参数</span><br><span class="line"> * <span class="doctag">@return</span> mixed</span><br><span class="line"> * <span class="doctag">@author</span> Sphenginx</span><br><span class="line"> */</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">(<span class="variable">$method</span>, <span class="variable">$args</span>)</span></span><br><span class="line"> </span>{</span><br><span class="line"> <span class="variable">$instance</span> = <span class="keyword">static</span>::getLogInstance();</span><br><span class="line"></span><br><span class="line"> <span class="comment">//组织参数信息</span></span><br><span class="line"> <span class="variable">$message</span> = <span class="variable">$args</span>[<span class="number">0</span>];</span><br><span class="line"> <span class="variable">$context</span> = <span class="keyword">isset</span>(<span class="variable">$args</span>[<span class="number">1</span>]) ? <span class="variable">$args</span>[<span class="number">1</span>] : [];</span><br><span class="line"> <span class="variable">$path</span> = <span class="keyword">isset</span>(<span class="variable">$args</span>[<span class="number">2</span>]) ? <span class="variable">$args</span>[<span class="number">2</span>] : <span class="string">'api/'</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">//设置日志处理手柄,默认为写入文件(还有mail、console、db、redis等方式,详见Monolog\handler 目录)</span></span><br><span class="line"> <span class="variable">$handler</span> = <span class="keyword">new</span> StreamHandler(storage_path(<span class="variable">$path</span>) . date(<span class="string">'Y-m-d'</span>).<span class="string">'.log'</span>);</span><br><span class="line"></span><br><span class="line"> <span class="comment">//设置输出格式LineFormatter(Monolog\Formatter\LineFormatter), ignore context and extra</span></span><br><span class="line"> <span class="variable">$handler</span>->setFormatter(<span class="keyword">new</span> LineFormatter(<span class="keyword">null</span>, <span class="keyword">null</span>, <span class="keyword">true</span>, <span class="keyword">true</span>));</span><br><span class="line"></span><br><span class="line"> <span class="variable">$instance</span>->pushHandler(<span class="variable">$handler</span>);</span><br><span class="line"> <span class="variable">$instance</span>-><span class="variable">$method</span>(<span class="variable">$message</span>, <span class="variable">$context</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>说明下,<code>__callStatic</code> 方法是php5.3+以来 非常方便的一个魔术方法。</p>
<h2 id="More_Info"><a href="#More_Info" class="headerlink" title="More Info"></a>More Info</h2><ul>
<li><a href="http://laravelacademy.org/docs/lumen" target="_blank" rel="external">Lumen中文文档</a></li>
<li><a href="http://coolshell.cn/articles/9949.html" target="_blank" rel="external">IoC/DIP其实是一种管理思想</a></li>
</ul>
]]></content>
<summary type="html">
<![CDATA[<h2 id="u524D_u8BB0"><a href="#u524D_u8BB0" class="headerlink" title="前记"></a>前记</h2><p>今天在使用<strong>lumen</strong>自带的类Log的时候,发现每次记录一个Log,总会]]>
</summary>
<category term="Log" scheme="http://sphenginx.github.io/tags/Log/"/>
<category term="ioc" scheme="http://sphenginx.github.io/tags/ioc/"/>
<category term="lumen" scheme="http://sphenginx.github.io/tags/lumen/"/>
<category term="日薪越亿" scheme="http://sphenginx.github.io/categories/%E6%97%A5%E8%96%AA%E8%B6%8A%E4%BA%BF/"/>
</entry>
<entry>
<title><![CDATA[我眼里的架构师]]></title>