您现在的位置是:网站首页> 编程资料编程资料

PHP 代码简洁之道(小结)_php实例_

2023-05-25 414人已围观

简介 PHP 代码简洁之道(小结)_php实例_

介绍

Robert C.Martin's 的 软件工程师准则 Clean Code 同样适用于 PHP。它并不是一个编码风格指南,它指导我们用 PHP 写出具有可读性,可复用性且可分解的代码。

并非所有的准则都必须严格遵守,甚至一些已经成为普遍的约定。这仅仅作为指导方针,其中许多都是 Clean Code 作者们多年来的经验。

灵感来自于 clean-code-javascript

尽管许多开发者依旧使用 PHP 5 版本,但是这篇文章中绝大多数例子都是只能在 PHP 7.1 + 版本下运行。

变量

使用有意义的且可读的变量名

不友好的:

 $ymdstr = $moment->format('y-m-d'); 

友好的:

 $currentDate = $moment->format('y-m-d');

对同类型的变量使用相同的词汇

不友好的:

 getUserInfo(); getUserData(); getUserRecord(); getUserProfile(); 

友好的:

 getUser();

使用可搜索的名称(第一部分)

我们阅读的代码超过我们写的代码。所以我们写出的代码需要具备可读性、可搜索性,这一点非常重要。要我们去理解程序中没有名字的变量是非常头疼的。让你的变量可搜索吧!

不具备可读性的代码:

 // 见鬼的 448 是什么意思? $result = $serializer->serialize($data, 448); 

具备可读性的:

 $json = $serializer->serialize($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); 

使用可搜索的名称(第二部分)

不好的:

 // 见鬼的 4 又是什么意思? if ($user->access & 4) { // ... } 

好的方式:

 class User { const ACCESS_READ = 1; const ACCESS_CREATE = 2; const ACCESS_UPDATE = 4; const ACCESS_DELETE = 8; } if ($user->access & User::ACCESS_UPDATE) { // do edit ... } 

使用解释性变量

不好:

 $address = 'One Infinite Loop, Cupertino 95014'; $cityZipCodeRegex = '/^[^,]+,\s*(.+?)\s*(\d{5})$/'; preg_match($cityZipCodeRegex, $address, $matches); saveCityZipCode($matches[1], $matches[2]); 

一般:

这个好点,但我们仍严重依赖正则表达式。

 $address = 'One Infinite Loop, Cupertino 95014'; $cityZipCodeRegex = '/^[^,]+,\s*(.+?)\s*(\d{5})$/'; preg_match($cityZipCodeRegex, $address, $matches); [, $city, $zipCode] = $matches; saveCityZipCode($city, $zipCode); 

很棒:

通过命名子模式减少对正则表达式的依赖。

 $address = 'One Infinite Loop, Cupertino 95014'; $cityZipCodeRegex = '/^[^,]+,\s*(?.+?)\s*(?\d{5})$/'; preg_match($cityZipCodeRegex, $address, $matches); saveCityZipCode($matches['city'], $matches['zipCode']); 

避免嵌套太深和提前返回 (第一部分)

使用太多 if else 表达式会导致代码难以理解。

明确优于隐式。

不好:

 function isShopOpen($day): bool { if ($day) { if (is_string($day)) { $day = strtolower($day); if ($day === 'friday') { return true; } elseif ($day === 'saturday') { return true; } elseif ($day === 'sunday') { return true; } else { return false; } } else { return false; } } else { return false; } } 

很棒:

 function isShopOpen(string $day): bool { if (empty($day)) { return false; } $openingDays = [ 'friday', 'saturday', 'sunday' ]; return in_array(strtolower($day), $openingDays, true); } 

避免嵌套太深和提前返回 (第二部分)

不好:

 function fibonacci(int $n) { if ($n < 50) { if ($n !== 0) { if ($n !== 1) { return fibonacci($n - 1) + fibonacci($n - 2); } else { return 1; } } else { return 0; } } else { return 'Not supported'; } } 

很棒:

 function fibonacci(int $n): int { if ($n === 0 || $n === 1) { return $n; } if ($n > 50) { throw new \Exception('Not supported'); } return fibonacci($n - 1) + fibonacci($n - 2); } 

避免心理映射

不要迫使你的代码阅读者翻译变量的意义。

明确优于隐式。

不好:

 $l = ['Austin', 'New York', 'San Francisco']; for ($i = 0; $i < count($l); $i++) { $li = $l[$i]; doStuff(); doSomeOtherStuff(); // ... // ... // ... // Wait, what is `$li` for again? dispatch($li); } 

很棒:

 $locations = ['Austin', 'New York', 'San Francisco']; foreach ($locations as $location) { doStuff(); doSomeOtherStuff(); // ... // ... // ... dispatch($location); } 

不要增加不需要的上下文

如果类名或对象名告诉你某些东西后,请不要在变量名中重复。

小坏坏:

 class Car { public $carMake; public $carModel; public $carColor; //... } 

好的方式:

 class Car { public $make; public $model; public $color; //... } 

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

不好的做法:

这是不太好的因为 $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 $
                
                

-六神源码网