PHPer这样写代码也许更优雅
来源:互联网 发布:刺客信条mac能玩吗 编辑:程序博客网 时间:2024/05/17 04:45
PHPer这样写代码也许更优雅
前言
转眼间成为一名PHPer已经快整整两年了,在这期间也对如何写出可读性高,
便于扩展的代码有了一些自己的想法。
使用引用
场景一:遍历一个数组获取新的数据结构
也许你会这样写:
12345678910111213141516171819202122232425262728
// 申明一个新的数组,组装成你想要的数据$tmp = [];foreach ($arr as $k => $v) {// 取出你想要的数据$tmp[$k]['youwant'] = $v['youwant'];...// 一系列判断得到你想要的数据if (...) {$tmp[$k]['youwantbyjudge'] = 'TIGERB';}...}// 最后得要你想要的数组$tmp-------------------------------------------------------// 也许你觉着上面的写法不是很好,那我们下面换种写法foreach ($arr as $k => $v) {// 一系列判断得到你想要的数据if (...) {// 复写值为你想要的$arr[$k]['youwantbyjudge'] = 'TIGERB'}...// 干掉你不想要的结构unset($arr[$k]['youwantdel']);}// 最后我们得到我们的目标数组$arr
接下来我们使用引用值:
123456789101112
foreach ($arr as &$v) {// 一系列判断得到你想要的数据if (...) {// 复写值为你想要的$v['youwantbyjudge'] = 'TIGERB'}...// 干掉你不想要的结构unset($v['youwantdel']);}unset($v);// 最后我们得到我们的目标数组$arr
使用引用是不是使我们的代码更加的简洁,除此之外相对于第一种写法,我们节省了内存空间,
尤其是再操作一个大数组时效果是及其明显的。
场景二:传递一个值到一个函数中获取新的值
基本和数组遍历一致,我们只需要声明这个函数的这个参数为引用即可,如下:
12345678910
function decorate(&$arr = []) {# code...}$arr = [....];// 调用函数decorate($arr);// 如上即得到新的值$arr,好处还是节省内存空间
使用try…catch…
假如有下面一段逻辑:
123456789101112131415161718192021222324252627282930313233343536373839
class UserModel{public function login($username = '', $password = ''){code...if (...) {// 用户不存在return -1;}code...if (...) {// 密码错误return -2;}code...}}class UserController{public function login($username = '', $password = ''){$model = new UserModel();$res = $model->login($username, $password);if ($res === -1) {return ['code' => '404','message' => '用户不存在'];}if ($res === -2) {return ['code' => '400','message' => '密码错误'];}code...}}
我们用try…catch…改写后:
1234567891011121314151617181920212223242526272829303132
class UserModel{public function login($username = '', $password = ''){code...if (...) {// 用户不存在throw new Exception('用户不存在', '404');}code...}}class UserController{public function login($username = '', $password = ''){try {$model = new UserModel();$res = $model->login($username, $password);// 如果需要的话,我们可以在这里统一commit数据库事务// $db->commit();} catch (Exception $e) {// 如果需要的话,我们可以在这里统一rollback数据库事务// $db->rollback();return ['code' => $e->getCode(),'message' => $e->getMessage()]}}}
通过使用try…catch…使我们的代码逻辑更加清晰,try…里只需要关注业务正常的情况,
异常的处理统一在catch中。所以,我们在写上游代码时异常直接抛出即可。
使用匿名函数
构建函数或方法内部的代码块
假如我们有一段逻辑,在一个函数或者方法里我们需要格式化数据,但是这个格式化数据的
代码片段出现了多次,如果我们直接写可能会想下面这样:
12345678
function doSomething(...) {...// 格式化代码段......// 格式化代码段[重复的代码]...}
我相信大多数的人应该不会像上面这么写,可能都会像下面这样:
12345678910111213
function doSomething(...) {...format(...);...format(...);...}// 再声明一个格式花代码的函数或方法function format() {// 格式化代码段...}
上面这样的写法没有任何的问题,最小单元化我们的代码片段,但是如果这个format函数或
者方法只是doSomething使用呢?我通常会像下面这么写,为什么?
因为我认为在这种上下文的环境中format和doSomething的一个子集。
123456789101112
function doSomething() {...$package = function (...) use (...) { // 同样use后面的参数也可以传引用// 格式化代码段...};...package(...);...package(...);...}
实现类的【懒加载】和实现设计模式的【最少知道原则】
假如有下面这段代码:
12345678910111213141516171819202122232425
class One{private $instance;// 类One内部依赖了类Two// 不符合设计模式的最少知道原则public function __construct(){$this->intance = new Two();}public function doSomething(){if (...) {// 如果某种情况调用类Two的实例方法$this->instance->do(...);}...}}...$instance = new One();$instance->doSomething();...
上面的写法有什么问题?
- 不符合设计模式的最少知道原则,类One内部直接依赖了类Two
- 类Two的实例不是所有的上下文都会用到,所以浪费了资源,
- 有人说搞个单例,但是解决不了实例化了不用的尴尬
所以我们使用匿名函数解决上面的问题,下面我们这么改写:
12345678910111213141516171819202122232425262728
class One{private $closure;public function __construct(Closure $closure){$this->closure = $closure;}public function doSomething(){if (...) {// 用的时候再实例化// 实现懒加载$instance = $this->closure();$instance->do(...)}...}}...$instance = new One(function () {// 类One外部依赖了类Tworeturn new Two();});$instance->doSomething();...
减少对if…else…的使用
如果你碰见下面这种类型的代码,那一定是个黑洞。
123456789101112131415
function doSomething() {if (...) {if (...) {...} esle {...}} else {if (...) {...} esle {...}}}
提前return异常
细心的你可能会发现上面这种情况,可能绝大多数else代码里都是在处理异常情况,
更有可能这个异常代码特别简单,通常我会这么去做:
12345678910111213141516171819202122232425262728293031
// 如果是在一个函数里面我会先处理异常的情况,然后提前return代码,最后再执行正常的逻辑function doSomething() {if (...) {// 异常情况return ...;}if (...) {// 异常情况return ...;}// 正常逻辑...}// 同样,如果是在一个类里面我会先处理异常的情况,然后先抛出异常class One{public function doSomething(){if (...) {// 异常情况throw new Exception(...);}if (...) {// 异常情况throw new Exception(...);}// 正常逻辑...}}
关联数组做map
如果我们在客户端做决策,通常我们会判断不同的上下文在选择不同策略,通常会像下面一样使用if或者switch判断:
123456789101112131415
class One{public function doSomething(){if (...) {$instance = new A();} elseif (...) {$instance = new A();} else {$instance = new C();}$instance->doSomething(...);...}}
上面的写法通常会出现大量的if语句或者switch语句,通常我会使用一个map来映射不同的策略,像下面这样:
123456789101112131415
class One{private $map = ['a' => 'namespace\A', // 带上命名空间,因为变量是动态的'b' => 'namespace\B','c' => 'namespace\C'];public function doSomething(){...$instance = new $this->map[$strategy];// $strategy是'a'或'b'或'c'$instance->doSomething(...);...}}
使用接口
为什么要使用接口?极大的便于后期的扩展和代码的可读性,例如设计一个优惠系统,
不同的商品只是在不同的优惠策略下具备不同的优惠行为,我们定义一个优惠行为的接口,
最后对这个接口编程即可,伪代码如下
123456789101112131415161718
Interface Promotion{public function promote(...);}class OnePromotion implement Promotion{public function doSomething(...){...}}class TwoPromotion implement Promotion{public function doSomething(...){...}}
控制器拒绝直接的DB操作
最后我想说的是永远拒绝在你的Controller里直接操作DB,为什么?我们的程序绝
大多数的操作基本都是增删改查,可能是查询的where条件和字段不同,所以有时候
我们可以抽象的把对数据库增删改查的方法写到model中,通过参数暴露我们的where,
fields条件。通常这样可以很大程度的提高效率和代码复用。比如像下面这样:
12345678910
class DemoModel implement Model{public function getMultiDate($where = [], $fields = ['id'], $orderby = 'id asc'){$this->where($where)->field($fields)->orderby($orderby)->get();}}
最后
如果有写的不对的地方,欢迎大家指正,THX~
Easy PHP:一个极速轻量级的PHP全栈框架
- PHPer这样写代码也许更优雅
- 代码这样写更优雅(Python版)
- 代码这样写更优雅(Python 版)
- 代码这样写不止于优雅(Python版)
- 代码这样写不止于优雅(Python版)
- 也许,这样理解HTTPS更容易
- 也许,这样理解HTTPS更容易
- 也许这样理解 HTTPS 更容易
- 也许,这样理解HTTPS更容易
- 也许,这样理解HTTPS更容易
- 也许,这样理解HTTPS更容易
- 也许这样理解 HTTPS 更容易
- 也许这样理解 HTTPS 更容易
- 也许这样理解 HTTPS 更容易
- CSS 黑魔法小技巧,让你少写不必要的JS,代码更优雅
- CSS 黑魔法小技巧,让你少写不必要的JS,代码更优雅
- 程序员这样写代码
- 程序员这样写代码
- Hibernate一级缓存
- 2017.5.27测试 4.截取
- 【C# 】双击一行触发事件
- MyEclipse修改 @author默认值
- 脚本作业
- PHPer这样写代码也许更优雅
- 全局变量、局部变量、静态全局变量、静态局部变量在内存里的区别
- GitHub 入门教程一
- springMvc通过Map形式接收多个参数form表单数据
- Broadcast面试详解
- RabbitMQ安装和使用(二)
- android studio 开发opencv时不安装相关的apk的方法
- InnoDB 1.1.X(MySQL5.5)数据预热 --- 持续更新
- [BZOJ 3112][Zjoi2013]防守战线:单纯形