JellyBool

17773 经验值

实在见笑了,Docker + Jenkins + Saltstack这三个我都没接触过。

此文章仅是Laravist群中Abraham同学在日常聊天对PHP、对Laravel、对项目的一些杂谈的简单整理.

Abraham,给人感觉是一位在PHP语言方面理解比较深的人

laravel以及MVC

1.个人粗浅的理解,所谓业务逻辑就是验证表单,发短信,发邮件,查询转成数据库sql等等,这些除了数据库查询之外常用的东西,也包括构造页面的标题了,或者 ajax 接口生成 json 结果这些琐碎的事。

2 这些东西不该被写在控制器中的原因是根据SOLID原则,类的职责必须是单一的,不该让一个类知道太多的事,也有人管这叫“关注分离”(seprate concerned),当然这是设计模式的思想,落实到实践中的好处有很多。 

据个栗子,例如你的应用有照片、文章、笑话等等很多栏目,用户可以在每个栏目下发布对应的内容,你想在它们发送完内容后自动给他们发送一封 email。 

如果写在控制器中, 一是违背 dry 原则, 每个控制器中都要有重复的代码, 十分不利于维护,日后你想更换 email 的发送服务,则要修改每个控制器中的 email 发送代码;二 是 email 发送类和控制器类是紧耦合的, 你无法独立去测试其中任何一个部分,你想测试 email 是否跑通就要去执行控制器类, 想测试控制器是否正常工作则必须得有 email 类, 如果项目很大,两个部分是不同的人完成的,工作进度不一样,这样会极大影响开发效率。  控制器依赖 email, 正确的做法是把 email 接口独立出来(先写接口),再去用一个发送类实现他,然后把接口注入到控制器,这样控制器无需关心email 类的细节,只知道那个接口能发送 email 就足够。

在Laravel中,对于这些发邮件之类的可以新建个 service 、或者是 你的 app 名之类的目录, 或者是 repository 目录。 控制器需要依赖他的时候用 laravel 的服务容器在参数中注入他。

正常情况下,控制器代码行数太多,比如多于 10 行。 或者是控制器中有 if 之类的判断,都是不合格的、 要让控制器傻到,接收请求,调用对应组件赋值给变量,把变量传进view 就好。

</blockquote>

2.理清了路由模型绑定的逻辑,非常智能。先以数组注册所有绑定, 键为路由变量名,值是闭包。调用控制器之前,判断路由是不是命中了模型绑定,如果命中,执行闭包, 注意这里, 返回的类型是什么, 调用控制器的时候,就反射到哪个参数上。

3.资料库不是必须得加, 小的控制器能直接在里查询数据库就挺好。 以下几种情况,可以考虑加 Repository。

1) 是你要测试控制器的方法,让 orm 和控制器隔离写测试方便

2) 隔离方法之间的责任,降低复杂度,方便维护

我是第二点, 因为要加缓存, 如果把读缓存,判断缓存生效之类的动作写在控制器方法里,对一个只是用来转发的控制器方法来说,他知道太多内容了。

但是中间加资料库, 就可以在资料库中处理这些细节。控制器和资料库之间,都知道资料库实现了特定的接口就行。

不管系统用不用缓存,资料库只要实现对应的接口,控制器在任何时候都不需要修改、 如果要维护和数据有关的东西, 也知道只去找资料库、

先理解“数据流”该怎么处理,就可以更好地理解MVC。正常的数据流应该是这样的M--->C---->V。M是数据提供者,所以业务逻辑应该在M里。C只是分发数据流,以只有一个作用,解耦M和V,让数据和视图分离。

一个功能点一个目录,里面存放和他有关的一切信息,包括 Eloquent 类。

缓存简介

L1是页面级缓存,L2是APC缓存(php5.3以后没有APC了,用鸟哥的yac吧),L3是Redis缓存。缓存全部没命中才会到数据库的,数据库根本就没几个读写。缓存也不敢按时间或者LRU淘汰的,是另外有php命令行的进程推送缓存更新。

opcode缓存自然也是有的,连自动检查php文件修改更新opcode都要关掉,只能通过另外一个进程手动更新opcode。

应该有参数可以控制模板编译缓存(这句话整理者实在不懂)

至于文件缓存不好,试试文件系统下分256*256级目录,里面有好几万个文件的时候,性能有多糟糕。直接上redis吧,虽然有点网络开销

正式项目应该都会有代码发布系统吧,不会直接ftp或者scp传文件吧在发布系统里,统一控制重新编译就可以。关掉各种编译文件的更新检查。 

git commit hook + phing

上传图片

图片上传过来,强制处理一次,用ImageMagick处理,所谓的原图也是压缩成大小相等的图片,删掉原图,exif信息存数据库,这样才安全

代码图片事例 --- (整理者:我的注释跟他比起来就是渣)

图片重力旋转

图片的 Exif 中有个Orientation 字段,用来存放照片方向。手机拍照有重力感应,所以照片都带有这个信息,手机的图库会正确识别显示拍照方向,显示出来。所以你要么在PHP识别旋转存储并且去掉exif,要么原样不动保留exif留给前端js显示的时候根据exif信息旋转。

UPYUN:

过年分享的小插件和开源项目及建议

https://github.com/hirak/prestissimo

composer 的并行下载插件,原理是先并行下载,再从缓存里恢复。

极大提升 update 速度。

官方提供的 laravel/laravel 只是基础,你可以按需自由调整。

比如:https://github.com/laravel/spark

这是 laravel 作者写的项目,虽然没 release,但大家尽量学习下。

通常大家划分目录按以下几种形式(可以同时采用多种)。

1,体现在前台的功能模块(比如邮件,授权,多步认证)

2,体现在编程中的基础通能(文件处理,队列操作之类的)

3,设计模式命名目录,一眼就知道目录作用

这如果展开了说,那就要说的太多了。总之目标就是,保证同一个目录,只放同一类东西。 出了一个问题,知道去哪个目录找文件。提高维护的方便程度。## Mysql 数据表MyISAM还是innodb

从长远角度看,改成innodb后面的可维护性将大大提高

1、MYISAM表锁,性能影响比较大,访问量大的时候尤其明显。

2、MYISAM很容易crash,修复后可能导致数据丢失。

3、MYISAM只能将索引load到内存,不像innodb,innodb索引和数据都可以load到内存。

4、CDB这边对innodb做了专门的优化,innodb比MYISAM更适合在CDB上跑。

实际项目的某些功能看法

1.耦合处理

比如你要给全站的文章进行网址唯一化,根据标题去自动生成拼音网址,存在 slug 列中。 此时垃圾的写法就是在控制器里每个涉及到的方法(增加、修改)都把标题生成拼音,一起存进去,这样当控制器中存在大量其它代码时(缓存、验证等等),a 是会变得臃肿难以维护, b 是控制器类中的修改、增加方法耦合太严重,要改得一起改。 这时候最好的办法是把 slug 过程独立出来。 如果在 serviceprovider 中 listen eloquent.saving* ,用独立的类处理,这样日后你修改 slug 方式,甚至不用改动控制器里的代码。

2.功能是否写在控制器</h4>

你的会员注册、 订单确认、 都要发送验证邮件时,写在控制器里是灾难的。详情和上面差不多。

php 框架里的事件机制基本都是四人帮“观察者模式”的简单实现,建议直接去读理论原文。 看点设计模式对写出好代码很重要,laravel 框架本身应用了 5 - 10 种设计模式,对于理解作者的设计也很重要。

可维护性强。 你可以任何更换 slug 类,而完全不用碰 控制器。也不用非得判断, 你可以在 provider 里 listen 一个自定义事件,注册和订单时 fire , 名字可以随便起。  eloquent 只是默认提供的。

3.在线人数统计

如果你不想用 redis,那继续用 mysql session,按时间查找按用户id去重count一下也行。考虑到性能,可以不对时间加索引,配置个crontab每分钟执行一次,把去重count的结果缓存到某个表的某个字段里。如果用redis,可以找一个单独的 redis 库,访问最频繁的几个页面加入写在线人数的代码,key为 用户uId,value 随便写或者写一些其他需要的信息,ttl 设置成 60 秒。用户过来,通过 pipline 或者 multi 写入 key - value 和 expire。获取在线人数就是 dbsize 这个库,如果访问频率非常高的页面获取在线人数,也可以配置 crontab 把 dbsize 的结果缓存。

Laravel的Eloquent和Facade(整理者水平不够看源代码萌萌的)eloquent 的默认触发事件是基于 laravel 的事件机制,并不是只有使用数据库才可以用事件。 你可以在程序任何地方触发时间,并且用对应的监听器进行处理。 你可以读一下 eloquent 的基类 model.php, 里面的 saving 其实就是 fire 这个函数的封装。 讨论是很难懂的,最好直接看源码.

Facade 是一个快速调用对象的方法,省掉了你实例化的过程(底层使用的是 loc 自动邦你 new xxx),框架本身需要更好的测试(不必测试 facade 调用是否成功),所以都是原生写法。

但 facade 这个组件本身也经过成熟测试,所以你可以在客户端代码尽情使用。

为什么laravel中有的函数根本显示不出来,提示不了,但是还是可以使用呢!比如latest(),无论是使用静态方法,还是使用对象调用,phpstorm都不能提示有这个方法,可是竟然能用

阅读面向对象

Tip:Eloquent注意点

$redis = \Redis::connection();</p><p>$catelist = $redis->get($foo)

先写 sql 再写 Eloquent,防止 Eloquent 用着爽,数据库遭殃。。。

你的取一条随机记录应该是这样大概

select user_id from table where id >= floor(rand() * max(id))

插播一句想用好 Eloquent 必须得知道方法链中的每个方法的返回值类型是什么。 不然第一个方法 返回数千个记录, 紧接着又进行集合操作。 我觉得运气不好的话,php 甚至会内存超限。

<h2>针对Laravel某些功能不如意</h2>

框架是基于接口的,如果某个功能框架默认的源码不能实现。 找到相应的实现,可以整个重写,也可以继承他。然后在配置文件里把 provider 替换掉

Guard 这个类是最容易替换的。这算是一个类似控制器的东西,里面注入了各种依赖。 你简单的继承它,把对应的方法覆写就行。看了下 config/app.php ,貌似没有 Guard , 如果想改 auth 部分, 看来只能重写 AuthServiceProvider 了。

这里面有个 registerAuthenticator() 方法, 在这个方法里做手脚即可,把里面的 UserServiceProvider 和 Guard 任意替换成你自己的实现,希望我说明白了。

主要是配置文件里只暴露一个 AuthServiceProvider ,如果要动 guard 就得覆写我上面说的方法。

如果想取个 salt 什么的,重写默认的 EloquentUserProvider,然后把 config/auth.php 里的 Eloquent 改成自己的。

日常学习进阶

静态工场, 单例模式, 都要求构造方法私有。没事多看看设计模式吧,对写程序帮助真的挺大的。我的建议是把 martin fowlor 的博客的所有文章都读了。他是 java 大牛,属于设计模式的教父级人物,言简意赅。

原文由 郑方方 创作 来自:http://www.jianshu.com/p/fd8b72b3d7d7

此文章仅是Laravist群中Little同学在日常聊天对PHP、对Laravel、对项目的一些杂谈的简单整理.但因本人在最开始记录的时候没有把little和abraham两个人的一些杂谈备注,所以有些写错归属

Little是一位经历过许多项目的工程师,谈吐之间,都能感受到超越语言从而对项目的理解


对七牛云等看法

考虑把 imagemagick 的工作放到七牛上, webserver 运行图片处理总是感觉怪怪的;

不要过分依赖某种云,最好不要用这些云私有的方法。万一遇到什么问题需要紧急迁移是个麻烦事。

嗯,我是先写接口。 imageimagick 和七牛的实现各写一份,可以瞬间切换的。

朋友的业务用SAE,用了私有的KV缓存,遇到故障根本迁移不出来,只能等那边解决,故障了一天多,如果当时是用通用的Redis,大不了云服务故障了,自己分分钟拉一个Docker部署Redis恢复的快,数据也能导出来。

必须得这样不然没办法用云服务呀,比如说七牛哪天被ddos,上传失效,能瞬间转移到别的平台才行。

建议手头有站的如果用云存储,不要只用一个,得用另外一个公司的做备份。

突发事件与处理

一次是公司的一个备案被竞争对手搞的注销了,没有备案,国内运营商根据HTTP头检测就直接封了,80/8080/8000端口什么的都不行。一时半会儿肯定备案不上,换域名也不现实,数据量大也短时间迁移不到国外。想用国外的nginx反向代理回国内,还是会被机房识别HTTP协议拦截。

最后想了个办法,两个机房路由器,配置 IP Sec 隧道,域名解析到香港,从香港机器nginx反向代理,走路由器间内网通信到国内机房的LVS,花了半小时搞定,速度还没有太大影响。

数据库查询与设计

前提,前台业务不要联合查询。管理后台业务应该独立一个从库,从从库里随便怎么查。统计业务大部分不需要实时的,也是从独立的从库里定时更新数据到统计表或者缓存。

而前台业务要用到联合查询,很大一部分情况是数据表字段设计不合理

在不重新设计表结构的情况下,如果查询条件只在一张表。那大部分left join联合查询,应该转换成php用两次查询,一次按条件从a表查,一次用php聚合,到b表WHERE id IN

中间表命名规范


两单词 中间用 2 (to) 连接,或者后面加 _map 或者 _relation 这样的,选定一种方式作为整个项目的表命名规范


用户增长过快可能的结果

假定你的项目用户数量是线性稳定增长,那么对数据库的压力可能会几何倍增长,并不是线性的。而且很有可能你的用户数可能成对数增长趋势,数据库的压力增加幅度更加不得了。做个主从读写分离,当时可能有效果,可是过不了几天,你会发现可能又到瓶颈了。然后尝试再增加一台从库,等不了几天,一主二从都可能够呛了,怎么办,再加从库 主从延迟又大了。然后再怎么办呢?水平拆分,拆库,拆表分散到不同的机器?

当你确定是数据库瓶颈的时候,基本上可以确定是架构问题了,经过简单的优化扩容,优化几个非常耗时导致表锁的SQL语句能顶一两个月不出问题,就要考虑重构了,要不然半年之后妥妥的再挂掉。

课外知识:不同语言之间如何通信

各个部门不一样,业务场景需求不一样,个人喜好不一样。

php一般用来写页面,数据部门一般用c写,搜索部门喜欢用java写。

跟不同部门协调,经常使用的一些方法:

同步调用:

1、提供API通信

a. REST

b. SOAP

c. JSON-RPC

d. XML-RPC

e. Protobuf

f. Thrift

...

2、私有TCP、UDP协议,双方自行约定协议体,二进制通信

3、进程间IPC通信

4、PHP扩展(C或C++)

5、exec/cmd执行命令行

6、队列系统同步返回

a. RabbitMQ 同步模式

b. Gearman

...

异步调用:

1、队列系统

a. RabbitMQ

b. Redis lpush/rpop

c. Beanstalkd

d. Kafka

e. ZeroMQ

2、借助共享存储系统

a. 共享内存 shmop

b. 文件系统

c. 缓存系统 redis/memcache

d. 数据库系统 mysql/pgsql/sqlite

整理者真的该去撞豆腐


课外知识:HLS简介

HLS是目前主流的直播技术,没什么问题。本质上就是一堆的 h.263 压缩的视频文件 + m3u8 索引文件,按几秒一个时间片这样生成很多 .ts 视频文件,文件通过 HTTP 协议传输。

兼容性也挺好的,PC主流播放器都支持,PC上的Chrome、Firefox、IE10、Edge浏览器都用HTML5支持,IE9以下可以借用JW Player(Flash)支持,iOS的iPhone、iPad原生支持。安卓比较糟糕,基本不行。

HLS遇到卡顿,先检查服务器生成的一堆 .ts 文件,是否连续,手动下载过来播放连续的话,基本上就是网络问题了。

如果网络不行,HLS可以用CDN的

原文由 郑方方 创作 来自:http://www.jianshu.com/p/fe889858df03

应该就是服务器的重写问题了。你可以google一下,或者直接使用serve就行

讲的什么。有一个部署的涉及到,其他好像没有吧

这怎么普及。。。。最终还是得看自己的吧

恩,我个人通常的做法是这个的:

$discussion = Discussion::find(1);
$comments = $discussion->comments;

在视图当中:

@if(count($comments) > 0)

看你是怎么获取的吧,没记错应该不是这样的啊