From 3328d4e2da44104749af2eb76e45a5cc3a88a78b Mon Sep 17 00:00:00 2001 From: zouyi Date: Thu, 19 Apr 2018 09:42:46 +0800 Subject: [PATCH 1/6] update --- README.md | 189 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 123 insertions(+), 66 deletions(-) diff --git a/README.md b/README.md index 5f2841ab..ccc6a999 100644 --- a/README.md +++ b/README.md @@ -6,17 +6,16 @@ 2. [变量](#变量) * [使用见字知意的变量名](#使用见字知意的变量名) * [同一个实体要用相同的变量名](#同一个实体要用相同的变量名) - * [使用便于搜索的名称 (part 1)](#使用便于搜索的名称part-1) - * [使用便于搜索的名称 (part 2)](#使用便于搜索的名称part-2) - * [使用自解释型变量](#使用自解释型变量) + * [使用便于搜索的名称 (part 1)](#使用便于搜索的名称-part-1) + * [使用便于搜索的名称 (part 2)](#使用便于搜索的名称-part-2) * [使用自解释型变量](#使用自解释型变量) * [避免深层嵌套,尽早返回 (part 1)](#避免深层嵌套尽早返回-part-1) * [避免深层嵌套,尽早返回 (part 2)](#避免深层嵌套尽早返回-part-2) * [少用无意义的变量名](#少用无意义的变量名) * [不要添加不必要上下文](#不要添加不必要上下文) * [合理使用参数默认值,没必要在方法里再做默认值检测](#合理使用参数默认值没必要在方法里再做默认值检测) - 3. [Comparaison](#comparaison) - * [Use identical comparison](#identical_comparison) + 3. [Comparison](#comparison) + * [Use identical comparison](#use-identical-comparison) 4. [函数](#函数) * [函数参数(最好少于2个)](#函数参数-最好少于2个) * [函数应该只做一件事](#函数应该只做一件事) @@ -38,6 +37,7 @@ 6. [类](#类) * [组合优于继承](#组合优于继承) * [避免连贯接口](#避免连贯接口) + * [Prefer `final` classes](#prefer-final-classes) 7. [类的SOLID原则 SOLID](#solid) * [S: 职责单一原则 Single Responsibility Principle (SRP)](#职责单一原则-single-responsibility-principle-srp) * [O: 开闭原则 Open/Closed Principle (OCP)](#开闭原则-openclosed-principle-ocp) @@ -396,30 +396,34 @@ function createMicrobrewery(string $breweryName = 'Hipster Brew Co.'): void **不好:** +简易对比会将字符串转为整形 + ```php $a = '42'; $b = 42; -// 简易对比会将字符串转为整形 - if( $a != $b ) { //这里始终执行不到 } - ``` -对比 $a != $b 返回了 false 但应该返回 true ! + +对比 $a != $b 返回了 `FALSE` 但应该返回 `TRUE` ! 字符串 '42' 跟整数 42 不相等 **好:** 使用恒等判断检查类型和数据 + ```php -if( $a !== $b ) { - //The expression is verified +$a = '42'; +$b = 42; + +if ($a !== $b) { + // The expression is verified } ``` -The comparison $a !== $b return true. +The comparison `$a !== $b` returns `TRUE`. **[⬆ 返回顶部](#目录)** @@ -1416,6 +1420,74 @@ $car->dump(); **[⬆ 返回顶部](#目录)** +### Prefer final classes + +The `final` should be used whenever possible: + +1. It prevents uncontrolled inheritance chain. +2. It encourages [composition](#prefer-composition-over-inheritance). +3. It encourages the [Single Responsibility Pattern](#single-responsibility-principle-srp). +4. It encourages developers to use your public methods instead of extending the class to get access on protected ones. +5. It allows you to change your code without any break of applications that use your class. + +The only condition is that your class should implement an interface and no other public methods are defined. + +For more informations you can read [the blog post](https://ocramius.github.io/blog/when-to-declare-classes-final/) on this topic written by [Marco Pivetta (Ocramius)](https://ocramius.github.io/). + +**Bad:** + +```php +final class Car +{ + private $color; + + public function __construct($color) + { + $this->color = $color; + } + + /** + * @return string The color of the vehicle + */ + public function getColor() + { + return $this->color; + } +} +``` + +**Good:** + +```php +interface Vehicle +{ + /** + * @return string The color of the vehicle + */ + public function getColor(); +} + +final class Car implements Vehicle +{ + private $color; + + public function __construct($color) + { + $this->color = $color; + } + + /** + * {@inheritdoc} + */ + public function getColor() + { + return $this->color; + } +} +``` + +**[⬆ 返回顶部](#目录)** + ## SOLID **SOLID** 是Michael Feathers推荐的便于记忆的首字母简写,它代表了Robert Martin命名的最重要的五个面对对象编码设计原则 @@ -1636,11 +1708,6 @@ class Rectangle protected $width = 0; protected $height = 0; - public function render(int $area): void - { - // ... - } - public function setWidth(int $width): void { $this->width = $width; @@ -1670,48 +1737,44 @@ class Square extends Rectangle } } -/** - * @param Rectangle[] $rectangles - */ -function renderLargeRectangles(array $rectangles): void +function printArea(Rectangle $rectangle): void { - foreach ($rectangles as $rectangle) { - $rectangle->setWidth(4); - $rectangle->setHeight(5); - $area = $rectangle->getArea(); // BAD: Will return 25 for Square. Should be 20. - $rectangle->render($area); - } + $rectangle->setWidth(4); + $rectangle->setHeight(5); + + // BAD: Will return 25 for Square. Should be 20. + echo sprintf('%s has area %d.', get_class($rectangle), $rectangle->getArea()).PHP_EOL; } -$rectangles = [new Rectangle(), new Rectangle(), new Square()]; -renderLargeRectangles($rectangles); +$rectangles = [new Rectangle(), new Square()]; + +foreach ($rectangles as $rectangle) { + printArea($rectangle); +} ``` **好:** -```php -abstract class Shape -{ - protected $width = 0; - protected $height = 0; +The best way is separate the quadrangles and allocation of a more general subtype for both shapes. - abstract public function getArea(): int; +Despite the apparent similarity of the square and the rectangle, they are different. +A square has much in common with a rhombus, and a rectangle with a parallelogram, but they are not subtype. +A square, a rectangle, a rhombus and a parallelogram are separate shapes with their own properties, albeit similar. - public function render(int $area): void - { - // ... - } +```php +interface Shape +{ + public function getArea(): int; } -class Rectangle extends Shape +class Rectangle implements Shape { - public function setWidth(int $width): void - { - $this->width = $width; - } + private $width = 0; + private $height = 0; - public function setHeight(int $height): void + public function __construct(int $width, int $height) { + $this->width = $width; $this->height = $height; } @@ -1721,41 +1784,31 @@ class Rectangle extends Shape } } -class Square extends Shape +class Square implements Shape { private $length = 0; - public function setLength(int $length): void + public function __construct(int $length) { $this->length = $length; } public function getArea(): int { - return pow($this->length, 2); - } +        return $this->length ** 2; +    } } -/** - * @param Rectangle[] $rectangles - */ -function renderLargeRectangles(array $rectangles): void +function printArea(Shape $shape): void { - foreach ($rectangles as $rectangle) { - if ($rectangle instanceof Square) { - $rectangle->setLength(5); - } elseif ($rectangle instanceof Rectangle) { - $rectangle->setWidth(4); - $rectangle->setHeight(5); - } - - $area = $rectangle->getArea(); - $rectangle->render($area); - } + echo sprintf('%s has area %d.', get_class($shape), $shape->getArea()).PHP_EOL; } -$shapes = [new Rectangle(), new Rectangle(), new Square()]; -renderLargeRectangles($shapes); +$shapes = [new Rectangle(4, 5), new Square(5)]; + +foreach ($shapes as $shape) { + printArea($shape); +} ``` **[⬆ 返回顶部](#目录)** @@ -2051,5 +2104,9 @@ function showList(array $employees): void * [panuwizzle/clean-code-php](https://github.com/panuwizzle/clean-code-php) * :fr: **French:** * [errorname/clean-code-php](https://github.com/errorname/clean-code-php) +* :vietnam: **Vietnamese** + * [viethuongdev/clean-code-php](https://github.com/viethuongdev/clean-code-php) +* :kr: **Korean:** + * [yujineeee/clean-code-php](https://github.com/yujineeee/clean-code-php) **[⬆ 返回顶部](#目录)** From 94b031009943daddfb99e588054fafff54b837db Mon Sep 17 00:00:00 2001 From: zouyi Date: Thu, 19 Apr 2018 10:15:08 +0800 Subject: [PATCH 2/6] update --- README.md | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index ccc6a999..28a1d808 100644 --- a/README.md +++ b/README.md @@ -14,8 +14,8 @@ * [少用无意义的变量名](#少用无意义的变量名) * [不要添加不必要上下文](#不要添加不必要上下文) * [合理使用参数默认值,没必要在方法里再做默认值检测](#合理使用参数默认值没必要在方法里再做默认值检测) - 3. [Comparison](#comparison) - * [Use identical comparison](#use-identical-comparison) + 3. [表达式](#表达式) + * [使用恒等式](#使用恒等式) 4. [函数](#函数) * [函数参数(最好少于2个)](#函数参数-最好少于2个) * [函数应该只做一件事](#函数应该只做一件事) @@ -37,7 +37,7 @@ 6. [类](#类) * [组合优于继承](#组合优于继承) * [避免连贯接口](#避免连贯接口) - * [Prefer `final` classes](#prefer-final-classes) + * [推荐使用 final 类](#推荐使用-final-类) 7. [类的SOLID原则 SOLID](#solid) * [S: 职责单一原则 Single Responsibility Principle (SRP)](#职责单一原则-single-responsibility-principle-srp) * [O: 开闭原则 Open/Closed Principle (OCP)](#开闭原则-openclosed-principle-ocp) @@ -390,9 +390,9 @@ function createMicrobrewery(string $breweryName = 'Hipster Brew Co.'): void **[⬆ 返回顶部](#目录)** -## Comparison +## 表达式 -### Use [identical comparison](http://php.net/manual/en/language.operators.comparison.php) +### [使用恒等式](http://php.net/manual/en/language.operators.comparison.php) **不好:** @@ -1420,15 +1420,15 @@ $car->dump(); **[⬆ 返回顶部](#目录)** -### Prefer final classes +### 推荐使用 final 类 -The `final` should be used whenever possible: +能用时尽量使用 `final` 关键字: -1. It prevents uncontrolled inheritance chain. -2. It encourages [composition](#prefer-composition-over-inheritance). -3. It encourages the [Single Responsibility Pattern](#single-responsibility-principle-srp). -4. It encourages developers to use your public methods instead of extending the class to get access on protected ones. -5. It allows you to change your code without any break of applications that use your class. +1. 阻止不受控的继承链 +2. 鼓励 [组合](#prefer-composition-over-inheritance). +3. 鼓励 [单一职责模式](#single-responsibility-principle-srp). +4. 鼓励开发者用你的公开方法而非通过继承类获取受保护方法的访问权限. +5. 使得在不破坏使用你的类的应用的情况下修改代码成为可能. The only condition is that your class should implement an interface and no other public methods are defined. @@ -1755,11 +1755,11 @@ foreach ($rectangles as $rectangle) { **好:** -The best way is separate the quadrangles and allocation of a more general subtype for both shapes. +最好是将这两种四边形分别对待,用一个适合两种类型的更通用子类型来代替。 -Despite the apparent similarity of the square and the rectangle, they are different. -A square has much in common with a rhombus, and a rectangle with a parallelogram, but they are not subtype. -A square, a rectangle, a rhombus and a parallelogram are separate shapes with their own properties, albeit similar. +尽管正方形和长方形看起来很相似,但他们是不同的。 +正方形更接近菱形,而长方形更接近平行四边形。但他们不是子类型。 +尽管相似,正方形、长方形、菱形、平行四边形都是有自己属性的不同形状。 ```php interface Shape From 91cc9daeedcc49bd706c82b0825f3bb15aa8111f Mon Sep 17 00:00:00 2001 From: zouyikb Date: Wed, 28 Nov 2018 14:08:23 +0800 Subject: [PATCH 3/6] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=88=B0=E6=9C=80?= =?UTF-8?q?=E6=96=B0=E7=89=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 97 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 55 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index 28a1d808..26cfa1c0 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ 4. [函数](#函数) * [函数参数(最好少于2个)](#函数参数-最好少于2个) * [函数应该只做一件事](#函数应该只做一件事) - * [函数名应该是有意义的动词(或表明具体做了什么事)](#函数名应该是有意义的动词或表明具体做了什么事) + * [函数名应体现他做了什么事](#函数名应体现他做了什么事) * [函数里应当只有一层抽象abstraction](#函数里应当只有一层抽象abstraction) * [不要用flag作为函数的参数](#不要用flag作为函数的参数) * [避免副作用](#避免副作用) @@ -33,17 +33,17 @@ * [移除僵尸代码](#移除僵尸代码) 5. [对象和数据结构 Objects and Data Structures](#对象和数据结构) * [使用 getters 和 setters Use object encapsulation](#使用-getters-和-setters) - * [对象属性多使用private/protected限定](#对象属性多使用privateprotected限定) + * [给对象使用私有或受保护的成员变量](#给对象使用私有或受保护的成员变量) 6. [类](#类) - * [组合优于继承](#组合优于继承) + * [少用继承多用组合](#少用继承多用组合) * [避免连贯接口](#避免连贯接口) * [推荐使用 final 类](#推荐使用-final-类) 7. [类的SOLID原则 SOLID](#solid) - * [S: 职责单一原则 Single Responsibility Principle (SRP)](#职责单一原则-single-responsibility-principle-srp) - * [O: 开闭原则 Open/Closed Principle (OCP)](#开闭原则-openclosed-principle-ocp) - * [L: 里氏替换原则 Liskov Substitution Principle (LSP)](#里氏替换原则-liskov-substitution-principle-lsp) - * [I: 接口隔离原则 Interface Segregation Principle (ISP)](#接口隔离原则-interface-segregation-principle-isp) - * [D: 依赖反转原则 Dependency Inversion Principle (DIP)](#依赖反转原则-dependency-inversion-principle-dip) + * [S: 单一职责原则 Single Responsibility Principle (SRP)](#单一职责原则) + * [O: 开闭原则 Open/Closed Principle (OCP)](#开闭原则) + * [L: 里氏替换原则 Liskov Substitution Principle (LSP)](#里氏替换原则) + * [I: 接口隔离原则 Interface Segregation Principle (ISP)](#接口隔离原则) + * [D: 依赖倒置原则 Dependency Inversion Principle (DIP)](#依赖倒置原则) 8. [别写重复代码 (DRY)](#别写重复代码-dry) 9. [翻译](#翻译) @@ -427,7 +427,7 @@ The comparison `$a !== $b` returns `TRUE`. **[⬆ 返回顶部](#目录)** -## **函数** +## 函数 ### 函数参数(最好少于2个) @@ -511,7 +511,7 @@ function isClientActive(int $client): bool **[⬆ 返回顶部](#目录)** -### 函数名应该是有意义的动词(或表明具体做了什么事) +### 函数名应体现他做了什么事 **坏:** @@ -527,7 +527,7 @@ class Email } $message = new Email(...); -// 啥?handle处理一个消息干嘛了?是往一个文件里写码? +// 啥?handle处理一个消息干嘛了?是往一个文件里写吗? $message->handle(); ``` @@ -690,8 +690,8 @@ class BetterJSAlternative **[⬆ 返回顶部](#目录)** - ### 不要用flag作为函数的参数 + flag就是在告诉大家,这个方法里处理很多事。前面刚说过,一个函数应当只做一件事。 把不同flag的代码拆分到多个函数里。 **坏:** @@ -1108,7 +1108,7 @@ inventoryTracker('apples', $request, 'www.inventory-awesome.io'); * 继承当前类时,可以复写默认的方法功能 * 当对象属性是从远端服务器获取时,get*,set*易于使用延迟加载 -此外,这样的方式也符合OOP开发中的[开闭原则](#openclosed-principle-ocp) +此外,这样的方式也符合OOP开发中的[开闭原则](#开闭原则) **坏:** @@ -1167,7 +1167,7 @@ $balance = $bankAccount->getBalance(); **[⬆ 返回顶部](#目录)** -### 对象属性多使用private/protected限定 +### 给对象使用私有或受保护的成员变量 * 对`public`方法和属性进行修改非常危险,因为外部代码容易依赖他,而你没办法控制。**对之修改影响所有这个类的使用者。** `public` methods and properties are most dangerous for changes, because some outside code may easily rely on them and you can't control what code relies on them. **Modifications in class are dangerous for all users of class.** * 对`protected`的修改跟对`public`修改差不多危险,因为他们对子类可用,他俩的唯一区别就是可调用的位置不一样,**对之修改影响所有集成这个类的地方。** `protected` modifier are as dangerous as public, because they are available in scope of any child class. This effectively means that difference between public and protected is only in access mechanism, but encapsulation guarantee remains the same. **Modifications in class are dangerous for all descendant classes.** @@ -1220,7 +1220,7 @@ echo 'Employee name: '.$employee->getName(); // Employee name: John Doe ## 类 -### 组合优于继承 +### 少用继承多用组合 正如 the Gang of Four 所著的[*设计模式*](https://en.wikipedia.org/wiki/Design_Patterns)之前所说, 我们应该尽量优先选择组合而不是继承的方式。使用继承和组合都有很多好处。 @@ -1252,8 +1252,8 @@ class Employee } -// 不好,因为Employees "有" taxdata -// 而EmployeeTaxData不是Employee类型的 +// 不好,因为 Employees "有" taxdata +// 而 EmployeeTaxData 不是 Employee 类型的 class EmployeeTaxData extends Employee @@ -1425,8 +1425,8 @@ $car->dump(); 能用时尽量使用 `final` 关键字: 1. 阻止不受控的继承链 -2. 鼓励 [组合](#prefer-composition-over-inheritance). -3. 鼓励 [单一职责模式](#single-responsibility-principle-srp). +2. 鼓励 [组合](#少用继承多用组合). +3. 鼓励 [单一职责模式](#单一职责模式). 4. 鼓励开发者用你的公开方法而非通过继承类获取受保护方法的访问权限. 5. 使得在不破坏使用你的类的应用的情况下修改代码成为可能. @@ -1492,14 +1492,16 @@ final class Car implements Vehicle **SOLID** 是Michael Feathers推荐的便于记忆的首字母简写,它代表了Robert Martin命名的最重要的五个面对对象编码设计原则 - * [S: 职责单一原则 (SRP)](#职责单一原则-single-responsibility-principle-srp) - * [O: 开闭原则 (OCP)](#开闭原则-openclosed-principle-ocp) - * [L: 里氏替换原则 (LSP)](#里氏替换原则-liskov-substitution-principle-lsp) - * [I: 接口隔离原则 (ISP)](#接口隔离原则-interface-segregation-principle-isp) - * [D: 依赖反转原则 (DIP)](#依赖反转原则-dependency-inversion-principle-dip) + * [S: 单一职责原则 (SRP)](#职责原则) + * [O: 开闭原则 (OCP)](#开闭原则) + * [L: 里氏替换原则 (LSP)](#里氏替换原则) + * [I: 接口隔离原则 (ISP)](#接口隔离原则) + * [D: 依赖倒置原则 (DIP)](#依赖倒置原则) + +### 单一职责原则 -### 职责单一原则 Single Responsibility Principle (SRP) +Single Responsibility Principle (SRP) 正如在Clean Code所述,"修改一个类应该只为一个理由"。 人们总是易于用一堆方法塞满一个类,如同我们只能在飞机上 @@ -1575,9 +1577,11 @@ class UserSettings **[⬆ 返回顶部](#目录)** -### 开闭原则 Open/Closed Principle (OCP) +### 开闭原则 -正如Bertrand Meyer所述,"软件的工件(classes, modules, functions,等) +Open/Closed Principle (OCP) + +正如Bertrand Meyer所述,"软件的工件( classes, modules, functions 等) 应该对扩展开放,对修改关闭。" 然而这句话意味着什么呢?这个原则大体上表示你 应该允许在不改变已有代码的情况下增加新的功能 @@ -1688,7 +1692,10 @@ class HttpRequester **[⬆ 返回顶部](#目录)** -### 里氏替换原则 Liskov Substitution Principle (LSP) +### 里氏替换原则 + +Liskov Substitution Principle (LSP) + 这是一个简单的原则,却用了一个不好理解的术语。它的正式定义是 "如果S是T的子类型,那么在不改变程序原有既定属性(检查、执行 任务等)的前提下,任何T类型的对象都可以使用S类型的对象替代 @@ -1813,7 +1820,9 @@ foreach ($shapes as $shape) { **[⬆ 返回顶部](#目录)** -### 接口隔离原则 Interface Segregation Principle (ISP) +### 接口隔离原则 + +Interface Segregation Principle (ISP) 接口隔离原则表示:"调用方不应该被强制依赖于他不需要的接口" @@ -1831,7 +1840,7 @@ interface Employee public function eat(): void; } -class Human implements Employee +class HumanEmployee implements Employee { public function work(): void { @@ -1844,7 +1853,7 @@ class Human implements Employee } } -class Robot implements Employee +class RobotEmployee implements Employee { public function work(): void { @@ -1877,7 +1886,7 @@ interface Employee extends Feedable, Workable { } -class Human implements Employee +class HumanEmployee implements Employee { public function work(): void { @@ -1891,7 +1900,7 @@ class Human implements Employee } // robot can only work -class Robot implements Workable +class RobotEmployee implements Workable { public function work(): void { @@ -1902,16 +1911,18 @@ class Robot implements Workable **[⬆ 返回顶部](#目录)** -### 依赖反转原则 Dependency Inversion Principle (DIP) +### 依赖倒置原则 + +Dependency Inversion Principle (DIP) 这条原则说明两个基本的要点: 1. 高阶的模块不应该依赖低阶的模块,它们都应该依赖于抽象 2. 抽象不应该依赖于实现,实现应该依赖于抽象 -这条起初看起来有点晦涩难懂,但是如果你使用过php框架(例如 Symfony),你应该见过 -依赖注入(DI)对这个概念的实现。虽然它们不是完全相通的概念,依赖倒置原则使高阶模块 -与低阶模块的实现细节和创建分离。可以使用依赖注入(DI)这种方式来实现它。更多的好处 -是它使模块之间解耦。耦合会导致你难于重构,它是一种非常糟糕的的开发模式 +这条起初看起来有点晦涩难懂,但是如果你使用过 PHP 框架(例如 Symfony),你应该见过 +依赖注入(DI),它是对这个概念的实现。虽然它们不是完全相等的概念,依赖倒置原则使高阶模块 +与低阶模块的实现细节和创建分离。可以使用依赖注入(DI)这种方式来实现它。最大的好处 +是它使模块之间解耦。耦合会导致你难于重构,它是一种非常糟糕的的开发模式。 **坏:** @@ -2007,10 +2018,10 @@ class Manager 分相同的方法,移除重复的代码意味着用一个function/module/class创 建一个能处理差异的抽象。 -正确的抽象是非常关键的,这正是为什么你必须学习遵守在[Classes](#classes)章节展开 -的SOLID原则,不合理的抽象比复制代码更糟糕,所有务必谨慎!说到这么多, -如果你能设计一个合理的抽象,实现它!不要重复,否则你会发现任何时候当你 -想修改一个逻辑时你必须修改多个地方。 +用对抽象非常关键,这正是为什么你必须学习遵守在[类](#类)章节写 +的SOLID原则,不合理的抽象比复制代码更糟糕,所以务必谨慎!说了这么多, +如果你能设计一个合理的抽象,那就这么干!别写重复代码,否则你会发现 +任何时候当你想修改一个逻辑时你必须修改多个地方。 **坏:** @@ -2108,5 +2119,7 @@ function showList(array $employees): void * [viethuongdev/clean-code-php](https://github.com/viethuongdev/clean-code-php) * :kr: **Korean:** * [yujineeee/clean-code-php](https://github.com/yujineeee/clean-code-php) +* :tr: **Turkish:** + * [anilozmen/clean-code-php](https://github.com/anilozmen/clean-code-php) **[⬆ 返回顶部](#目录)** From 7d05644b40c32a94334f47f81bdf7e2bb5583fe5 Mon Sep 17 00:00:00 2001 From: zouyikb Date: Wed, 4 Sep 2019 16:21:27 +0800 Subject: [PATCH 4/6] update --- README.md | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 26cfa1c0..dd06343a 100644 --- a/README.md +++ b/README.md @@ -112,7 +112,7 @@ getUser(); **坏:** ```php -// What the heck is 448 for? +// 448 ™ 干啥的? $result = $serializer->serialize($data, 448); ``` @@ -127,10 +127,19 @@ $json = $serializer->serialize($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT **坏:** ```php -// What the heck is 4 for? +class User +{ + // 7 ™ 干啥的? + public $access = 7; +} + +// 4 ™ 干啥的? if ($user->access & 4) { // ... } + +// 这里会发生什么? +$user->access ^= 2; ``` **好:** @@ -142,11 +151,17 @@ class User const ACCESS_CREATE = 2; const ACCESS_UPDATE = 4; const ACCESS_DELETE = 8; + + // 默认情况下用户 具有读、写和更新权限 + public $access = self::ACCESS_READ | self::ACCESS_CREATE | self::ACCESS_UPDATE; } if ($user->access & User::ACCESS_UPDATE) { // do edit ... } + +// 禁用创建权限 +$user->access ^= User::ACCESS_CREATE; ``` **[⬆ 返回顶部](#目录)** @@ -271,7 +286,7 @@ function fibonacci(int $n): int return $n; } - if ($n > 50) { + if ($n >= 50) { throw new \Exception('Not supported'); } @@ -1020,7 +1035,7 @@ function travelToTexas($vehicle): void **好:** ```php -function travelToTexas(Traveler $vehicle): void +function travelToTexas(Vehicle $vehicle): void { $vehicle->travelTo(new Location('texas')); } From f5134a6a353b9e73ff195002c0ab82233a803002 Mon Sep 17 00:00:00 2001 From: zouyi Date: Mon, 26 Oct 2020 10:34:07 +0800 Subject: [PATCH 5/6] update --- .travis-build.php | 23 +++--- README.md | 180 ++++++++++++++++++++++++++-------------------- 2 files changed, 118 insertions(+), 85 deletions(-) diff --git a/.travis-build.php b/.travis-build.php index 93333509..17a63fee 100644 --- a/.travis-build.php +++ b/.travis-build.php @@ -25,14 +25,21 @@ } $tableOfContentsStarted = false; - $chaptersFound[] = sprintf('%s [%s](#%s)', - strlen($matches['depth']) === 2 - ? sprintf(' %s.', ++$manIndex) - : ' *' - , - $matches['title'], - preg_replace(['/ /', '/[^-\w]+/'], ['-', ''], strtolower($matches['title'])) - ); + if (strlen($matches['depth']) === 2) { + $depth = sprintf(' %s.', ++$manIndex); + } else { + $depth = sprintf(' %s*', str_repeat(' ', strlen($matches['depth']) - 1)); + } + + // ignore links in title + $matches['title'] = preg_replace('/\[([^\]]+)\]\((?:[^\)]+)\)/u', '$1', $matches['title']); + + $link = $matches['title']; + $link = strtolower($link); + $link = str_replace(' ', '-', $link); + $link = preg_replace('/[^-\w]+/u', '', $link); + + $chaptersFound[] = sprintf('%s [%s](#%s)', $depth, $matches['title'], $link); } if ($tableOfContentsStarted === true && isset($line[0])) { $currentTableOfContentsChapters[] = $line; diff --git a/README.md b/README.md index dd06343a..9ebd8654 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ ## 翻译说明 -翻译完成度100%,最后更新时间2017-12-25。本文由 php-cpm 基于 [yangweijie版本](https://github.com/yangweijie/clean-code-php) 的[clean-code-php](https://github.com/jupeter/clean-code-php)翻译并同步大量原文内容。 +翻译完成度100%,最后更新时间2020-10-26。本文由 php-cpm 基于 [yangweijie版本](https://github.com/yangweijie/clean-code-php) 的[clean-code-php](https://github.com/jupeter/clean-code-php)翻译并同步大量原文内容。 原文更新频率较高,我的翻译方法是直接用文本比较工具逐行对比。优先保证文字内容是最新的,再逐步提升翻译质量。 @@ -147,10 +147,10 @@ $user->access ^= 2; ```php class User { - const ACCESS_READ = 1; - const ACCESS_CREATE = 2; - const ACCESS_UPDATE = 4; - const ACCESS_DELETE = 8; + public const ACCESS_READ = 1; + public const ACCESS_CREATE = 2; + public const ACCESS_UPDATE = 4; + public const ACCESS_DELETE = 8; // 默认情况下用户 具有读、写和更新权限 public $access = self::ACCESS_READ | self::ACCESS_CREATE | self::ACCESS_UPDATE; @@ -442,62 +442,53 @@ The comparison `$a !== $b` returns `TRUE`. **[⬆ 返回顶部](#目录)** -## 函数 - -### 函数参数(最好少于2个) - -限制函数参数个数极其重要,这样测试你的函数容易点。有超过3个可选参数参数导致一个爆炸式组合增长,你会有成吨独立参数情形要测试。 +### Null coalescing operator -无参数是理想情况。1个或2个都可以,最好避免3个。再多就需要加固了。通常如果你的函数有超过两个参数,说明他要处理的事太多了。 如果必须要传入很多数据,建议封装一个高级别对象作为参数。 +Null coalescing is a new operator [introduced in PHP 7](https://www.php.net/manual/en/migration70.new-features.php). The null coalescing operator `??` has been added as syntactic sugar for the common case of needing to use a ternary in conjunction with `isset()`. It returns its first operand if it exists and is not `null`; otherwise it returns its second operand. -**坏:** +**Bad:** ```php -function createMenu(string $title, string $body, string $buttonText, bool $cancellable): void -{ - // ... +if (isset($_GET['name'])) { + $name = $_GET['name']; +} elseif (isset($_POST['name'])) { + $name = $_POST['name']; +} else { + $name = 'nobody'; } ``` -**好:** - +**Good:** ```php -class MenuConfig -{ - public $title; - public $body; - public $buttonText; - public $cancellable = false; -} +$name = $_GET['name'] ?? $_POST['name'] ?? 'nobody'; +``` -$config = new MenuConfig(); -$config->title = 'Foo'; -$config->body = 'Bar'; -$config->buttonText = 'Baz'; -$config->cancellable = true; +**[⬆ back to top](#table-of-contents)** -function createMenu(MenuConfig $config): void -{ - // ... -} -``` +## 函数 -**[⬆ 返回顶部](#目录)** +### 函数参数(最好少于2个) -### 函数应该只做一件事 +限制函数参数个数极其重要,这样测试你的函数容易点。有超过3个可选参数参数导致一个爆炸式组合增长,你会有成吨独立参数情形要测试。 -这是迄今为止软件工程里最重要的一个规则。当一个函数做超过一件事的时候,他们就难于实现、测试和理解。当你把一个函数拆分到只剩一个功能时,他们就容易被重构,然后你的代码读起来就更清晰。如果你光遵循这条规则,你就领先于大多数开发者了。 +无参数是理想情况。1个或2个都可以,最好避免3个。再多就需要加固了。通常如果你的函数有超过两个参数,说明他要处理的事太多了。 如果必须要传入很多数据,建议封装一个高级别对象作为参数。 **坏:** ```php -function emailClients(array $clients): void +class Questionnaire { - foreach ($clients as $client) { - $clientRecord = $db->find($client); - if ($clientRecord->isActive()) { - email($client); - } + public function __construct( + string $firstname, + string $lastname, + string $patronymic, + string $region, + string $district, + string $city, + string $phone, + string $email + ) { + // ... } } ``` @@ -505,22 +496,58 @@ function emailClients(array $clients): void **好:** ```php -function emailClients(array $clients): void +class Name { - $activeClients = activeClients($clients); - array_walk($activeClients, 'email'); + private $firstname; + private $lastname; + private $patronymic; + + public function __construct(string $firstname, string $lastname, string $patronymic) + { + $this->firstname = $firstname; + $this->lastname = $lastname; + $this->patronymic = $patronymic; + } + + // getters ... } -function activeClients(array $clients): array +class City { - return array_filter($clients, 'isClientActive'); + private $region; + private $district; + private $city; + + public function __construct(string $region, string $district, string $city) + { + $this->region = $region; + $this->district = $district; + $this->city = $city; + } + + // getters ... } -function isClientActive(int $client): bool +class Contact { - $clientRecord = $db->find($client); + private $phone; + private $email; - return $clientRecord->isActive(); + public function __construct(string $phone, string $email) + { + $this->phone = $phone; + $this->email = $email; + } + + // getters ... +} + +class Questionnaire +{ + public function __construct(Name $name, City $city, Contact $contact) + { + // ... + } } ``` @@ -574,7 +601,7 @@ $message->send(); **坏:** ```php -function parseBetterJSAlternative(string $code): void +function parseBetterPHPAlternative(string $code): void { $regexes = [ // ... @@ -631,7 +658,7 @@ function lexer(array $tokens): array return $ast; } -function parseBetterJSAlternative(string $code): void +function parseBetterPHPAlternative(string $code): void { $tokens = tokenize($code); $ast = lexer($tokens); @@ -643,7 +670,7 @@ function parseBetterJSAlternative(string $code): void **好:** -最好的解决方案是把 `parseBetterJSAlternative()`方法的依赖移除。 +最好的解决方案是把 `parseBetterPHPAlternative()`方法的依赖移除。 ```php class Tokenizer @@ -679,7 +706,7 @@ class Lexer } } -class BetterJSAlternative +class BetterPHPAlternative { private $tokenizer; private $lexer; @@ -701,8 +728,6 @@ class BetterJSAlternative } ``` -这样我们可以对依赖做mock,并测试`BetterJSAlternative::parse()`运行是否符合预期。 - **[⬆ 返回顶部](#目录)** ### 不要用flag作为函数的参数 @@ -811,7 +836,8 @@ class Configuration public function get(string $key): ?string { - return isset($this->configuration[$key]) ? $this->configuration[$key] : null; + // null coalescing operator + return $this->configuration[$key] ?? null; } } ``` @@ -1252,7 +1278,7 @@ echo 'Employee name: '.$employee->getName(); // Employee name: John Doe **糟糕的:** ```php -class Employee +class Employee { private $name; private $email; @@ -1271,11 +1297,11 @@ class Employee // 而 EmployeeTaxData 不是 Employee 类型的 -class EmployeeTaxData extends Employee +class EmployeeTaxData extends Employee { private $ssn; private $salary; - + public function __construct(string $name, string $email, string $ssn, string $salary) { parent::__construct($name, $email); @@ -1291,7 +1317,7 @@ class EmployeeTaxData extends Employee **好:** ```php -class EmployeeTaxData +class EmployeeTaxData { private $ssn; private $salary; @@ -1305,7 +1331,7 @@ class EmployeeTaxData // ... } -class Employee +class Employee { private $name; private $email; @@ -1317,9 +1343,9 @@ class Employee $this->email = $email; } - public function setTaxData(string $ssn, string $salary) + public function setTaxData(EmployeeTaxData $taxData) { - $this->taxData = new EmployeeTaxData($ssn, $salary); + $this->taxData = $taxData; } // ... @@ -1455,16 +1481,16 @@ For more informations you can read [the blog post](https://ocramius.github.io/bl final class Car { private $color; - + public function __construct($color) { $this->color = $color; } - + /** * @return string The color of the vehicle */ - public function getColor() + public function getColor() { return $this->color; } @@ -1485,16 +1511,16 @@ interface Vehicle final class Car implements Vehicle { private $color; - + public function __construct($color) { $this->color = $color; } - + /** * {@inheritdoc} */ - public function getColor() + public function getColor() { return $this->color; } @@ -1555,7 +1581,7 @@ class UserSettings **好:** ```php -class UserAuth +class UserAuth { private $user; @@ -1563,19 +1589,19 @@ class UserAuth { $this->user = $user; } - + public function verifyCredentials(): bool { // ... } } -class UserSettings +class UserSettings { private $user; private $auth; - public function __construct(User $user) + public function __construct(User $user) { $this->user = $user; $this->auth = new UserAuth($user); @@ -1763,7 +1789,7 @@ function printArea(Rectangle $rectangle): void { $rectangle->setWidth(4); $rectangle->setHeight(5); - + // BAD: Will return 25 for Square. Should be 20. echo sprintf('%s has area %d.', get_class($rectangle), $rectangle->getArea()).PHP_EOL; } @@ -2136,5 +2162,5 @@ function showList(array $employees): void * [yujineeee/clean-code-php](https://github.com/yujineeee/clean-code-php) * :tr: **Turkish:** * [anilozmen/clean-code-php](https://github.com/anilozmen/clean-code-php) - + **[⬆ 返回顶部](#目录)** From 0c71f30a71826f138b975bad54ac45ad597cff69 Mon Sep 17 00:00:00 2001 From: zouyi Date: Thu, 18 Nov 2021 11:29:49 +0800 Subject: [PATCH 6/6] update translation --- .github/workflows/coding_standard.yaml | 21 +++ .gitignore | 2 + .travis-build.php | 77 --------- .travis.yml | 11 -- README.md | 225 +++++++++++++------------ composer.json | 12 ++ ecs.php | 27 +++ 7 files changed, 178 insertions(+), 197 deletions(-) create mode 100644 .github/workflows/coding_standard.yaml create mode 100644 .gitignore delete mode 100644 .travis-build.php delete mode 100644 .travis.yml create mode 100644 composer.json create mode 100644 ecs.php diff --git a/.github/workflows/coding_standard.yaml b/.github/workflows/coding_standard.yaml new file mode 100644 index 00000000..262b528b --- /dev/null +++ b/.github/workflows/coding_standard.yaml @@ -0,0 +1,21 @@ +name: Coding Standard + +on: + pull_request: null + push: null + +jobs: + coding_standard: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + # see https://github.com/shivammathur/setup-php + - uses: shivammathur/setup-php@v2 + with: + php-version: 8.0 + coverage: none + + - run: composer install --no-progress --ansi + + - run: vendor/bin/ecs check-markdown README.md --ansi diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..49c63d28 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +composer.lock +/vendor \ No newline at end of file diff --git a/.travis-build.php b/.travis-build.php deleted file mode 100644 index 17a63fee..00000000 --- a/.travis-build.php +++ /dev/null @@ -1,77 +0,0 @@ -setFlags(SplFileObject::DROP_NEW_LINE); - -$cliRedBackground = "\033[37;41m"; -$cliReset = "\033[0m"; -$exitStatus = 0; - -$indentationSteps = 3; -$manIndex = 0; -$linesWithSpaces = []; -$tableOfContentsStarted = null; -$currentTableOfContentsChapters = []; -$chaptersFound = []; -foreach ($readMeFile as $lineNumber => $line) { - if (preg_match('/\s$/', $line)) { - $linesWithSpaces[] = sprintf('%5s: %s', 1 + $lineNumber, $line); - } - if (preg_match('/^(?##+)\s(?.+)/', $line, $matches)) { - if (null === $tableOfContentsStarted) { - $tableOfContentsStarted = true; - continue; - } - $tableOfContentsStarted = false; - - if (strlen($matches['depth']) === 2) { - $depth = sprintf(' %s.', ++$manIndex); - } else { - $depth = sprintf(' %s*', str_repeat(' ', strlen($matches['depth']) - 1)); - } - - // ignore links in title - $matches['title'] = preg_replace('/\[([^\]]+)\]\((?:[^\)]+)\)/u', '$1', $matches['title']); - - $link = $matches['title']; - $link = strtolower($link); - $link = str_replace(' ', '-', $link); - $link = preg_replace('/[^-\w]+/u', '', $link); - - $chaptersFound[] = sprintf('%s [%s](#%s)', $depth, $matches['title'], $link); - } - if ($tableOfContentsStarted === true && isset($line[0])) { - $currentTableOfContentsChapters[] = $line; - } -} - -if (count($linesWithSpaces)) { - fwrite(STDERR, sprintf("${cliRedBackground}The following lines end with a space character:${cliReset}\n%s\n\n", - implode(PHP_EOL, $linesWithSpaces) - )); - $exitStatus = 1; -} - -$currentTableOfContentsChaptersFilename = __DIR__ . '/current-chapters'; -$chaptersFoundFilename = __DIR__ . '/chapters-found'; - -file_put_contents($currentTableOfContentsChaptersFilename, implode(PHP_EOL, $currentTableOfContentsChapters)); -file_put_contents($chaptersFoundFilename, implode(PHP_EOL, $chaptersFound)); - -$tableOfContentsDiff = shell_exec(sprintf('diff --unified %s %s', - escapeshellarg($currentTableOfContentsChaptersFilename), - escapeshellarg($chaptersFoundFilename) -)); - -@ unlink($currentTableOfContentsChaptersFilename); -@ unlink($chaptersFoundFilename); - -if (!empty($tableOfContentsDiff)) { - fwrite(STDERR, sprintf("${cliRedBackground}The table of contents is not aligned:${cliReset}\n%s\n\n", - $tableOfContentsDiff - )); - $exitStatus = 1; -} - -exit($exitStatus); diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index e4ea3575..00000000 --- a/.travis.yml +++ /dev/null @@ -1,11 +0,0 @@ -language: php - -sudo: false - -php: - - nightly - -script: php .travis-build.php - -notifications: - email: false diff --git a/README.md b/README.md index 9ebd8654..0c57115a 100644 --- a/README.md +++ b/README.md @@ -12,11 +12,11 @@ * [避免深层嵌套,尽早返回 (part 1)](#避免深层嵌套尽早返回-part-1) * [避免深层嵌套,尽早返回 (part 2)](#避免深层嵌套尽早返回-part-2) * [少用无意义的变量名](#少用无意义的变量名) - * [不要添加不必要上下文](#不要添加不必要上下文) - * [合理使用参数默认值,没必要在方法里再做默认值检测](#合理使用参数默认值没必要在方法里再做默认值检测) - 3. [表达式](#表达式) + * [不要添加不必要上下文](#不要添加不必要上下文) 3. [表达式](#表达式) * [使用恒等式](#使用恒等式) + * [Null合并运算符](#null合并运算符) 4. [函数](#函数) + * [合理使用参数默认值,没必要在方法里再做默认值检测](#合理使用参数默认值没必要在方法里再做默认值检测) * [函数参数(最好少于2个)](#函数参数-最好少于2个) * [函数应该只做一件事](#函数应该只做一件事) * [函数名应体现他做了什么事](#函数名应体现他做了什么事) @@ -148,8 +148,11 @@ $user->access ^= 2; class User { public const ACCESS_READ = 1; + public const ACCESS_CREATE = 2; + public const ACCESS_UPDATE = 4; + public const ACCESS_DELETE = 8; // 默认情况下用户 具有读、写和更新权限 @@ -223,15 +226,12 @@ function isShopOpen($day): bool return true; } elseif ($day === 'sunday') { return true; - } else { - return false; } - } else { return false; } - } else { return false; } + return false; } ``` @@ -244,9 +244,7 @@ function isShopOpen(string $day): bool return false; } - $openingDays = [ - 'friday', 'saturday', 'sunday' - ]; + $openingDays = ['friday', 'saturday', 'sunday']; return in_array(strtolower($day), $openingDays, true); } @@ -265,15 +263,12 @@ function fibonacci(int $n) if ($n !== 0) { if ($n !== 1) { return fibonacci($n - 1) + fibonacci($n - 2); - } else { - return 1; } - } else { - return 0; + return 1; } - } else { - return 'Not supported'; + return 0; } + return 'Not supported'; } ``` @@ -287,7 +282,7 @@ function fibonacci(int $n): int } if ($n >= 50) { - throw new \Exception('Not supported'); + throw new Exception('Not supported'); } return fibonacci($n - 1) + fibonacci($n - 2); @@ -345,7 +340,9 @@ foreach ($locations as $location) { class Car { public $carMake; + public $carModel; + public $carColor; //... @@ -358,7 +355,9 @@ class Car class Car { public $make; + public $model; + public $color; //... @@ -367,43 +366,6 @@ class Car **[⬆ 返回顶部](#目录)** -### 合理使用参数默认值,没必要在方法里再做默认值检测 - -**不好:** - -不好,`$breweryName` 可能为 `NULL`. - -```php -function createMicrobrewery($breweryName = 'Hipster Brew Co.'): void -{ -    // ... -} -``` - -**还行:** - -比上一个好理解一些,但最好能控制变量的值 - -```php -function createMicrobrewery($name = null): void -{ -    $breweryName = $name ?: 'Hipster Brew Co.'; - // ... -} -``` - -**好:** - -如果你的程序只支持 PHP 7+, 那你可以用 [type hinting](http://php.net/manual/en/functions.arguments.php#functions.arguments.type-declaration) 保证变量 `$breweryName` 不是 `NULL`. - -```php -function createMicrobrewery(string $breweryName = 'Hipster Brew Co.'): void -{ -    // ... -} -``` - -**[⬆ 返回顶部](#目录)** ## 表达式 @@ -417,7 +379,7 @@ function createMicrobrewery(string $breweryName = 'Hipster Brew Co.'): void $a = '42'; $b = 42; -if( $a != $b ) { +if ($a != $b) { //这里始终执行不到 } ``` @@ -442,11 +404,11 @@ The comparison `$a !== $b` returns `TRUE`. **[⬆ 返回顶部](#目录)** -### Null coalescing operator +### Null合并运算符 -Null coalescing is a new operator [introduced in PHP 7](https://www.php.net/manual/en/migration70.new-features.php). The null coalescing operator `??` has been added as syntactic sugar for the common case of needing to use a ternary in conjunction with `isset()`. It returns its first operand if it exists and is not `null`; otherwise it returns its second operand. +Null合并运算符是 [PHP 7新特性](https://www.php.net/manual/en/migration70.new-features.php). Null合并运算符 `??` 是用来简化判断`isset()`的语法糖。如果第一个操作数存在且不为`null`则返回;否则返回第二个操作数。 -**Bad:** +**不好:** ```php if (isset($_GET['name'])) { @@ -458,15 +420,54 @@ if (isset($_GET['name'])) { } ``` -**Good:** +**好:** ```php $name = $_GET['name'] ?? $_POST['name'] ?? 'nobody'; ``` -**[⬆ back to top](#table-of-contents)** +**[⬆ 返回顶部](#目录)** + ## 函数 +### 合理使用参数默认值,没必要在方法里再做默认值检测 + +**不好:** + +不好,`$breweryName` 可能为 `NULL`. + +```php +function createMicrobrewery($breweryName = 'Hipster Brew Co.'): void +{ +    // ... +} +``` + +**还行:** + +比上一个好理解一些,但最好能控制变量的值 + +```php +function createMicrobrewery($name = null): void +{ + $breweryName = $name ?: 'Hipster Brew Co.'; + // ... +} +``` + +**好:** + +如果你的程序只支持 PHP 7+, 那你可以用 [type hinting](http://php.net/manual/en/functions.arguments.php#functions.arguments.type-declaration) 保证变量 `$breweryName` 不是 `NULL`. + +```php +function createMicrobrewery(string $breweryName = 'Hipster Brew Co.'): void +{ + // ... +} +``` + +**[⬆ 返回顶部](#目录)** + ### 函数参数(最好少于2个) 限制函数参数个数极其重要,这样测试你的函数容易点。有超过3个可选参数参数导致一个爆炸式组合增长,你会有成吨独立参数情形要测试。 @@ -499,7 +500,9 @@ class Questionnaire class Name { private $firstname; + private $lastname; + private $patronymic; public function __construct(string $firstname, string $lastname, string $patronymic) @@ -515,7 +518,9 @@ class Name class City { private $region; + private $district; + private $city; public function __construct(string $region, string $district, string $city) @@ -531,6 +536,7 @@ class City class Contact { private $phone; + private $email; public function __construct(string $phone, string $email) @@ -576,7 +582,7 @@ $message->handle(); **好:** ```php -class Email +class Email { //... @@ -739,7 +745,7 @@ flag就是在告诉大家,这个方法里处理很多事。前面刚说过, function createFile(string $name, bool $temp = false): void { if ($temp) { - touch('./temp/'.$name); + touch('./temp/' . $name); } else { touch($name); } @@ -756,7 +762,7 @@ function createFile(string $name): void function createTempFile(string $name): void { - touch('./temp/'.$name); + touch('./temp/' . $name); } ``` **[⬆ 返回顶部](#目录)** @@ -785,7 +791,8 @@ function splitIntoFirstAndLastName(): void splitIntoFirstAndLastName(); -var_dump($name); // ['Ryan', 'McDermott']; +var_dump($name); +// ['Ryan', 'McDermott']; ``` **好:** @@ -799,8 +806,11 @@ function splitIntoFirstAndLastName(string $name): array $name = 'Ryan McDermott'; $newName = splitIntoFirstAndLastName($name); -var_dump($name); // 'Ryan McDermott'; -var_dump($newName); // ['Ryan', 'McDermott']; +var_dump($name); +// 'Ryan McDermott'; + +var_dump($newName); +// ['Ryan', 'McDermott']; ``` **[⬆ 返回顶部](#目录)** @@ -816,9 +826,9 @@ var_dump($newName); // ['Ryan', 'McDermott']; ```php function config(): array { - return [ + return [ 'foo' => 'bar', - ] + ]; } ``` @@ -836,7 +846,7 @@ class Configuration public function get(string $key): ?string { - // null coalescing operator + // null coalescing operator return $this->configuration[$key] ?? null; } } @@ -876,7 +886,7 @@ class DBConnection // ... } - public static function getInstance(): DBConnection + public static function getInstance(): self { if (self::$instance === null) { self::$instance = new self(); @@ -901,7 +911,7 @@ class DBConnection // ... } - // ... + // ... } ``` @@ -940,13 +950,12 @@ if ($article->isPublished()) { **坏:** ```php -function isDOMNodeNotPresent(\DOMNode $node): bool +function isDOMNodeNotPresent(DOMNode $node): bool { // ... } -if (!isDOMNodeNotPresent($node)) -{ +if (! isDOMNodeNotPresent($node)) { // ... } ``` @@ -954,7 +963,7 @@ if (!isDOMNodeNotPresent($node)) **好:** ```php -function isDOMNodePresent(\DOMNode $node): bool +function isDOMNodePresent(DOMNode $node): bool { // ... } @@ -1081,8 +1090,8 @@ function travelToTexas(Vehicle $vehicle): void ```php function combine($val1, $val2): int { - if (!is_numeric($val1) || !is_numeric($val2)) { - throw new \Exception('Must be of type Number'); + if (! is_numeric($val1) || ! is_numeric($val2)) { + throw new Exception('Must be of type Number'); } return $val1 + $val2; @@ -1232,7 +1241,8 @@ class Employee } $employee = new Employee('John Doe'); -echo 'Employee name: '.$employee->name; // Employee name: John Doe +// Employee name: John Doe +echo 'Employee name: ' . $employee->name; ``` **好:** @@ -1254,7 +1264,8 @@ class Employee } $employee = new Employee('John Doe'); -echo 'Employee name: '.$employee->getName(); // Employee name: John Doe +// Employee name: John Doe +echo 'Employee name: ' . $employee->getName(); ``` **[⬆ 返回顶部](#目录)** @@ -1281,6 +1292,7 @@ echo 'Employee name: '.$employee->getName(); // Employee name: John Doe class Employee { private $name; + private $email; public function __construct(string $name, string $email) @@ -1300,6 +1312,7 @@ class Employee class EmployeeTaxData extends Employee { private $ssn; + private $salary; public function __construct(string $name, string $email, string $ssn, string $salary) @@ -1320,6 +1333,7 @@ class EmployeeTaxData extends Employee class EmployeeTaxData { private $ssn; + private $salary; public function __construct(string $ssn, string $salary) @@ -1334,7 +1348,9 @@ class EmployeeTaxData class Employee { private $name; + private $email; + private $taxData; public function __construct(string $name, string $email) @@ -1343,7 +1359,7 @@ class Employee $this->email = $email; } - public function setTaxData(EmployeeTaxData $taxData) + public function setTaxData(EmployeeTaxData $taxData): void { $this->taxData = $taxData; } @@ -1382,7 +1398,9 @@ more often it comes at some costs: class Car { private $make = 'Honda'; + private $model = 'Accord'; + private $color = 'white'; public function setMake(string $make): self @@ -1416,10 +1434,10 @@ class Car } $car = (new Car()) - ->setColor('pink') - ->setMake('Ford') - ->setModel('F-150') - ->dump(); + ->setColor('pink') + ->setMake('Ford') + ->setModel('F-150') + ->dump(); ``` **好:** @@ -1428,7 +1446,9 @@ $car = (new Car()) class Car { private $make = 'Honda'; + private $model = 'Accord'; + private $color = 'white'; public function setMake(string $make): void @@ -1517,9 +1537,6 @@ final class Car implements Vehicle $this->color = $color; } - /** - * {@inheritdoc} - */ public function getColor() { return $this->color; @@ -1599,6 +1616,7 @@ class UserAuth class UserSettings { private $user; + private $auth; public function __construct(User $user) @@ -1754,6 +1772,7 @@ Liskov Substitution Principle (LSP) class Rectangle { protected $width = 0; + protected $height = 0; public function setWidth(int $width): void @@ -1791,7 +1810,7 @@ function printArea(Rectangle $rectangle): void $rectangle->setHeight(5); // BAD: Will return 25 for Square. Should be 20. - echo sprintf('%s has area %d.', get_class($rectangle), $rectangle->getArea()).PHP_EOL; + echo sprintf('%s has area %d.', get_class($rectangle), $rectangle->getArea()) . PHP_EOL; } $rectangles = [new Rectangle(), new Square()]; @@ -2073,11 +2092,7 @@ function showDeveloperList(array $developers): void $expectedSalary = $developer->calculateExpectedSalary(); $experience = $developer->getExperience(); $githubLink = $developer->getGithubLink(); - $data = [ - $expectedSalary, - $experience, - $githubLink - ]; + $data = [$expectedSalary, $experience, $githubLink]; render($data); } @@ -2089,11 +2104,7 @@ function showManagerList(array $managers): void $expectedSalary = $manager->calculateExpectedSalary(); $experience = $manager->getExperience(); $githubLink = $manager->getGithubLink(); - $data = [ - $expectedSalary, - $experience, - $githubLink - ]; + $data = [$expectedSalary, $experience, $githubLink]; render($data); } @@ -2109,11 +2120,7 @@ function showList(array $employees): void $expectedSalary = $employee->calculateExpectedSalary(); $experience = $employee->getExperience(); $githubLink = $employee->getGithubLink(); - $data = [ - $expectedSalary, - $experience, - $githubLink - ]; + $data = [$expectedSalary, $experience, $githubLink]; render($data); } @@ -2128,11 +2135,7 @@ function showList(array $employees): void function showList(array $employees): void { foreach ($employees as $employee) { - render([ - $employee->calculateExpectedSalary(), - $employee->getExperience(), - $employee->getGithubLink() - ]); + render([$employee->calculateExpectedSalary(), $employee->getExperience(), $employee->getGithubLink()]); } } ``` @@ -2156,11 +2159,15 @@ function showList(array $employees): void * [panuwizzle/clean-code-php](https://github.com/panuwizzle/clean-code-php) * :fr: **French:** * [errorname/clean-code-php](https://github.com/errorname/clean-code-php) -* :vietnam: **Vietnamese** +* :vietnam: **Vietnamese:** * [viethuongdev/clean-code-php](https://github.com/viethuongdev/clean-code-php) * :kr: **Korean:** * [yujineeee/clean-code-php](https://github.com/yujineeee/clean-code-php) * :tr: **Turkish:** * [anilozmen/clean-code-php](https://github.com/anilozmen/clean-code-php) +* :iran: **Persian:** + * [amirshnll/clean-code-php](https://github.com/amirshnll/clean-code-php) +* :bangladesh: **Bangla:** + * [nayeemdev/clean-code-php](https://github.com/nayeemdev/clean-code-php) **[⬆ 返回顶部](#目录)** diff --git a/composer.json b/composer.json new file mode 100644 index 00000000..9c258aa3 --- /dev/null +++ b/composer.json @@ -0,0 +1,12 @@ +{ + "name": "jupeter/clean-code-php", + "description": "Clean Code concepts adapted for PHP", + "require": { + "php": ">=7.2", + "symplify/easy-coding-standard": "^9.3" + }, + "scripts": { + "check-cs": "vendor/bin/ecs check-markdown README.md", + "fix-cs": "vendor/bin/ecs check-markdown README.md --fix" + } +} diff --git a/ecs.php b/ecs.php new file mode 100644 index 00000000..b2e209ef --- /dev/null +++ b/ecs.php @@ -0,0 +1,27 @@ +<?php + +declare(strict_types=1); + +use PhpCsFixer\Fixer\PhpTag\BlankLineAfterOpeningTagFixer; +use PhpCsFixer\Fixer\Strict\DeclareStrictTypesFixer; +use PhpCsFixer\Fixer\Strict\StrictComparisonFixer; +use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; +use Symplify\EasyCodingStandard\ValueObject\Option; +use Symplify\EasyCodingStandard\ValueObject\Set\SetList; + +return static function (ContainerConfigurator $containerConfigurator): void +{ + $containerConfigurator->import(SetList::COMMON); + $containerConfigurator->import(SetList::CLEAN_CODE); + $containerConfigurator->import(SetList::PSR_12); + $containerConfigurator->import(SetList::SYMPLIFY); + + $parameters = $containerConfigurator->parameters(); + $parameters->set(Option::PATHS, [__DIR__ . '/src', __DIR__ . '/config', __DIR__ . '/ecs.php']); + + $parameters->set(Option::SKIP, [ + BlankLineAfterOpeningTagFixer::class => null, + StrictComparisonFixer::class => null, + DeclareStrictTypesFixer::class => null, + ]); +};