PHP 代码简洁之道 ( PHP Clean Code)(第二部分)

PHP 代码简洁之道 ( PHP Clean Code)(第一部分)

使用默认参数而不是使用短路运算或者是条件判断

不好的做法:

这是不太好的因为 $breweryName 可以是 NULL.

function createMicrobrewery($breweryName = 'Hipster Brew Co.'): void

{

    // ...

}

还算可以的做法:

这个做法比上面的更加容易理解,但是它需要很好的去控制变量的值.

function createMicrobrewery($name = null): void

{

    $breweryName = $name ?: 'Hipster Brew Co.';

    // ...

}

好的做法:

你可以使用 类型提示 而且可以保证 $breweryName 不会为空 NULL.

function createMicrobrewery(string $breweryName = 'Hipster Brew Co.'): void

{

    // ...

}

}

对比

使用 相等运算符

不好的做法:

$a = '42';

$b = 42;

使用简单的相等运算符会把字符串类型转换成数字类型

if( $a != $b ) {

  //这个条件表达式总是会通过

}

表达式 $a != $b 会返回 false 但实际上它应该是 true !

字符串类型 '42' 是不同于数字类型的 42

好的做法:

使用全等运算符会对比类型和值

if( $a !== $b ) {

    //这个条件是通过的

}

表达式 $a !== $b 会返回 true。

函数

函数参数(2 个或更少)

限制函数参数个数极其重要

这样测试你的函数容易点。有超过 3 个可选参数会导致一个爆炸式组合增长,你会有成吨独立参数情形要测试。

无参数是理想情况。1 个或 2 个都可以,最好避免 3 个。

再多就需要加固了。通常如果你的函数有超过两个参数,说明他要处理的事太多了。 如果必须要传入很多数据,建议封装一个高级别对象作为参数。

不友好的:

function createMenu(string $title, string $body, string $buttonText, bool $cancellable): void

{

    // ...

}

友好的:

class MenuConfig

{

    public $title;

    public $body;

    public $buttonText;

    public $cancellable = false;

}

$config = new MenuConfig();

$config->title = 'Foo';

$config->body = 'Bar';

$config->buttonText = 'Baz';

$config->cancellable = true;

function createMenu(MenuConfig $config): void

{

    // ...

}

函数应该只做一件事情

这是迄今为止软件工程最重要的原则。函数做了超过一件事情时,它们将变得难以编写、测试、推导。 而函数只做一件事情时,重构起来则非常简单,同时代码阅读起来也非常清晰。掌握了这个原则,你就会领先许多其他的开发者。

不好的:

function emailClients(array $clients): void

{

    foreach ($clients as $client) {

        $clientRecord = $db->find($client);

        if ($clientRecord->isActive()) {

            email($client);

        }

    }

}

好的:

function emailClients(array $clients): void

{

    $activeClients = activeClients($clients);

    array_walk($activeClients, 'email');

}

function activeClients(array $clients): array

{

    return array_filter($clients, 'isClientActive');

}

function isClientActive(int $client): bool

{

    $clientRecord = $db->find($client);

    return $clientRecord->isActive();

}

函数的名称要说清楚它做什么

不好的例子:

class Email

{

    //...

    public function handle(): void

    {

        mail($this->to, $this->subject, $this->body);

    }

}

$message = new Email(...);

// What is this? A handle for the message? Are we writing to a file now?

$message->handle();

很好的例子:

class Email

{

    //...

    public function send(): void

    {

        mail($this->to, $this->subject, $this->body);

    }

}

$message = new Email(...);

// Clear and obvious

$message->send();

函数只能是一个抽象级别

当你有多个抽象层次时,你的函数功能通常是做太多了。 分割函数功能使得重用性和测试更加容易。.

不好:

function parseBetterJSAlternative(string $code): void

{

    $regexes = [

        // ...

    ];

    $statements = explode(' ', $code);

    $tokens = [];

    foreach ($regexes as $regex) {

        foreach ($statements as $statement) {

            // ...

        }

    }

    $ast = [];

    foreach ($tokens as $token) {

        // lex...

    }

    foreach ($ast as $node) {

        // parse...

    }

}

同样不是很好:

我们已经完成了一些功能,但是 parseBetterJSAlternative() 功能仍然非常复杂,测试起来也比较麻烦。

function tokenize(string $code): array

{

    $regexes = [

        // ...

    ];

    $statements = explode(' ', $code);

    $tokens = [];

    foreach ($regexes as $regex) {

        foreach ($statements as $statement) {

            $tokens[] = /* ... */;

        }

    }

    return $tokens;

}

function lexer(array $tokens): array

{

    $ast = [];

    foreach ($tokens as $token) {

        $ast[] = /* ... */;

    }

    return $ast;

}

function parseBetterJSAlternative(string $code): void

{

    $tokens = tokenize($code);

    $ast = lexer($tokens);

    foreach ($ast as $node) {

        // parse...

    }

}

很好的:

最好的解决方案是取出 parseBetterJSAlternative() 函数的依赖关系.

class Tokenizer

{

    public function tokenize(string $code): array

    {

        $regexes = [

            // ...

        ];

        $statements = explode(' ', $code);

        $tokens = [];

        foreach ($regexes as $regex) {

            foreach ($statements as $statement) {

                $tokens[] = /* ... */;

            }

        }

        return $tokens;

    }

}

class Lexer

{

    public function lexify(array $tokens): array

    {

        $ast = [];

        foreach ($tokens as $token) {

            $ast[] = /* ... */;

        }

        return $ast;

    }

}

class BetterJSAlternative

{

    private $tokenizer;

    private $lexer;

    public function __construct(Tokenizer $tokenizer, Lexer $lexer)

    {

        $this->tokenizer = $tokenizer;

        $this->lexer = $lexer;

    }

    public function parse(string $code): void

    {

        $tokens = $this->tokenizer->tokenize($code);

        $ast = $this->lexer->lexify($tokens);

        foreach ($ast as $node) {

            // parse...

        }

    }

}

更多学习内容请访问:

腾讯T3-T4标准精品PHP架构师教程目录大全,只要你看完保证薪资上升一个台阶(持续更新)​zhuanlan.zhihu.com

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,864评论 6 494
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,175评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,401评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,170评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,276评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,364评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,401评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,179评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,604评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,902评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,070评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,751评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,380评论 3 319
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,077评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,312评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,924评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,957评论 2 351

推荐阅读更多精彩内容

  • 前言 前几天在GitHub看到一篇写PHP简洁之道的译文,觉得还不错,所以转在了自己的博客中,只不过有一些地方好像...
    guanguans阅读 596评论 3 6
  • Ba la la la ~ 读者朋友们,你们好啊,又到了冷锋时间,话不多说,发车! 一、变量 使用有准确...
    王饱饱阅读 267评论 0 3
  • 把当前目录作为Root Document只需要这条命令即可:php -S localhost:3300 也可以指定...
    绚烂的时光阅读 730评论 0 1
  • core package 概要:Core是所有其他包的基础包.它提供了大部分功能包括metadata,templa...
    LOVE小狼阅读 2,564评论 0 3
  • 写在开头 最近在看原则一本书,发现生活中和工作中很多都是有规律有原则的,代码的世界里也一样,代码其实是写给人看的,...
    i5yue阅读 718评论 0 0