优化分支结构,向“简、并、雅”看齐
优化分支结构,简化代码,提高可读性
好久没有写文了,毕竟人是越来越懒的。
之前写过一文,说的是 减少if-else的滥用,提高代码可读性。里面提到了用if-return、表驱动等多种方法来代替if-else,可是具体该怎么用以及改进的方式并不是那些清晰。今天说的这个其实还是一样的,不过在此基础上,又添加了一些内容。
注意:此文所阐述的内容仅为个人意见,仅供参考。此文所提供的例子仅作示范使用,不针对任何人。认为胡说八道的,建议右上角
先来看一组代码节选:
class zipFile
{
protected $zip;
protected $root;
protected $ignored_names;
public function __construct()
{
$this->zip = new ZipArchive;
}
public function unzip($zipfile, $path)
{
if ($this->zip->open($zipfile) === true) {
//能否打开该压缩文件
$file_tmp = @fopen($zipfile, "rb");
$bin = fread($file_tmp, 15);
//读取文件头,15字节
fclose($file_tmp);
//关闭该文件
if (true === $this->getTypeList($bin)) {
//判断是否为压缩文件,只对压缩文件进行处理
$result = $this->zip->extractTo($path);
//开始解压,成功返回true
$this->zip->close();
//关闭引用
return $result;
//返回结果
} else {
return false;
//不是压缩文件,返回false
}
}
return false;
//不能打开压缩文件,返回false;
}
....etc...
}
从名字上可以看的出来,这个代码片段是一个非常简单的利用php来实现解压文件的的class,这里有一个公共方法unzip,就是具体实现文件解压功能。通读一下实现的步骤:
有什么问题?
当我提出这个问题的时候,肯定有人会说:“这能有什么问题,逻辑很清楚,跑一下代码也跑得出来,没什么问题”。是的,逻辑很清楚,可是,恰恰是逻辑上出了一些小问题。第一个判断那里,如果能打开文件,说明该文件一定是压缩文件,那么第二个判断就是没有必要的。再来,从代码上面看,使用if-return确实也算比较清晰。那么,“问题在哪里呢?”,或者说,“真的存在问题么?”。假设代码逻辑是正确的,也就是默认两个判断都是有效判断,除开这个,还有问题吗?
还有!
if ($this->zip->open($zipfile) === true) {
//能否打开该压缩文件
//...etc...
if (true === $this->getTypeList($bin)) {
//判断是否为压缩文件,只对压缩文件进行处理
//...etc...
return $result;
//返回结果
} else {
return false;
//不是压缩文件,返回false
}
}
return false;
再来一个更加精简的版本
if(){
if () {
return Boolean($result);
}
else {
return false
}
}
return false
看出来问题了吗?我想应该是看出来了。if-return 和if-else是可以独立使用的,也就是说,在使用了 if-return 的情况下, if-else是没有必要的。换句话说,上面这个代码可以这样简化
if(){
if () {
return Boolean($result);
}
//else: other content here
//...etc...
return false;
}
return false
这样就算结束了?并没有!还可以简化
if(){
if () {
return Boolean($result);
}
//else: other content here
//...etc...
}
return false
这个时候来比较一下两段代码的逻辑
从这张图中,可以看出使用if-return确实有助于简化逻辑,不过简化的量得看写代码的人如何去书写。说白了,就是代码习惯的问题。上面这个例子,看上去可读性也很不错了。
按道理来说,你以为到这里差不多就结束了。可是这还并没有到"优化分支结构"这个地步。
事实上,if-return除了简化代码外,还有一个好处就是“优化分支结构”或者叫做调整分支结构。
影响代码可读性的,大多就是因为你在无尽的滥用大括号,无尽的嵌套各种分支结构。
所以利用if-return优化好分支结构,也是一个很好的方式。将代码进行如下改写:
public function unzip($zipfile, $path)
{
if ($this->zip->open($zipfile) === false) {
return false;
}
$file_tmp = @fopen($zipfile, "rb");
$bin = fread($file_tmp, 15);
fclose($file_tmp);
if (true === $this->getTypeList($bin)) {
return false;
}
$result = $this->zip->extractTo($path);
$this->zip->close();
return $result;
}
从上面这个代码片段可以看出,其实多个代码嵌套的分支结构,是可以合理的利用if-return转换为平行(顺序)结构的,平行结构强调的就是从上到下,自然而然。比起无尽的嵌套,减少了很多不必要步骤,读下来,可能更加一目了然。这种思想源于“及时止损”,数学里面有个最不利原则,优先考虑最差的情况,然后逐步筛选出期望达到的目的。当然,不同的人有不同的书写习惯和风格,没有必要为了简化步骤而简化步骤。
个人认为,php代码要写出较高质量,还是要从“简、并、雅”出发。
简是简化逻辑(也即简化代码)、简一功能(简单且功能单一,即高内聚低耦合)、简明注释(简单扼要的描述目的、参数、返回等信息)
并是代码风格统一、注释与功能统一、具备一定前瞻性(预见未来变化)
雅是代码符合规范(特定或约定的代码书写风格标准),代码具有较高三性(可读性可维护性可写性)
可能你会有以下问题:
- 循环里面怎么用if-return?
如果你只是取到值就跑,用if-return,如果你想取完所有的值才跑,那应该换成if-continue,并且总是考虑两种情况中,情况最简单的那种(能够尽快返回值或跳出循环)。 - 多分支结构怎么办?if-elseif-elseif-else?
Nope~ 如果你想保持多分支结构,避免if-else方式,采用switch,如果你想转换为平行结构,则可以采用表驱动,并不是说一定要用分离思想,表驱动也是很好的处理多分支的方式。 - 我认为你说的是在放p。/我就是喜欢各种嵌套,怎么滴啦?
右上角。 - 分支结构和顺序结构如何选择?
看你喜欢和个人风格。不是强制性的。不过,虽然高质量的代码不一定是平直的,但是绝对不是s型的。