fonction


Fonction

1. Paramètres de fonction (de préférence inférieurs à 2)

2. La fonction ne doit faire qu'une seule chose

3. Il ne devrait y avoir qu'une seule couche d'abstraction dans la fonction

5. N'utilisez pas de drapeau comme paramètre de la fonction

6. Évitez les effets secondaires

7. 8. N'utilisez pas de modèle Singleton

9. Encapsulez les déclarations conditionnelles

10. Évitez d'utiliser des jugements conditionnels opposés

11. 1)

13. Évitez la vérification de type (partie 2)

14. Supprimez le code zombie

1. Paramètres de fonction (de préférence inférieurs à 2)

Il est extrêmement important de limiter les paramètres de fonction. nombre de paramètres de fonction, donc tester votre fonction est plus facile. Avoir plus de 3 paramètres facultatifs entraîne une explosion de combinaisons et vous aurez des tonnes de scénarios de paramètres indépendants à tester.

Aucun paramètre n’est la situation idéale. 1 ou 2 suffisent, il vaut mieux éviter 3. Plus et il faudra le renforcer. Habituellement, si votre fonction a plus de deux paramètres, cela signifie qu'elle a trop de choses à gérer. Si beaucoup de données doivent être transmises, il est recommandé d'encapsuler un objet de haut niveau en tant que paramètre.

Mauvais :

 function createMenu(string $title, string $body, string $buttonText, bool $cancellable): void
{
    // ...
}
Bon :

 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
{
    // ...
}

2 Les fonctions ne doivent faire qu'une seule chose

C'est de loin la règle la plus importante en génie logiciel. Lorsqu’une fonction fait plusieurs choses, elles sont difficiles à implémenter, tester et comprendre. Lorsque vous divisez une fonction en une seule fonction, elles sont plus faciles à refactoriser et votre code est plus propre. Si vous suivez simplement cette règle, vous serez en avance sur la plupart des développeurs.

Mauvais :

 function emailClients(array $clients): void
{
    foreach ($clients as $client) {
        $clientRecord = $db->find($client);
        if ($clientRecord->isActive()) {
            email($client);
        }
    }
}

Bon :
 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();
}

3. Le nom de la fonction doit refléter ce qu'elle fait

Mauvais :

 class Email
{
    //...
 
    public function handle(): void
    {
        mail($this->to, $this->subject, $this->body);
    }
}
 
$message = new Email(...);
// 啥?handle处理一个消息干嘛了?是往一个文件里写吗?
$message->handle();

Bon :

 class Email
{
    //...
 
    public function send(): void
    {
        mail($this->to, $this->subject, $this->body);
    }
}
 
$message = new Email(...);
// 简单明了
$message->send();

4. Il ne devrait y avoir qu'une seule couche d'abstraction dans la fonction

Lorsque vous avez trop de niveaux d'abstraction, la fonction gère trop de choses. La fonctionnalité de fractionnement est nécessaire pour améliorer la réutilisabilité et la facilité d'utilisation afin de simplifier les tests. (Note du traducteur : à en juger par l'exemple de code ici, il devrait faire référence à trop d'imbrication)

Mauvais :

 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...
    }
}

Mauvais :Nous avons extrait certaines méthodes de la boucle, mais parseBetterJSAlternative() < /code>La méthode est encore très compliquée et peu propice aux tests.

 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) {
        // 解析逻辑...
    }
}

Bon :

La meilleure solution est de supprimer la dépendance de la méthode 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) {
            // 解析逻辑...
        }
    }
}

De cette façon, nous pouvons simuler les dépendances et tester si BetterJSAlternative::parse() fonctionne comme prévu. mock,并测试BetterJSAlternative::parse()运行是否符合预期。

5. 不要用flag作为函数的参数

flag就是在告诉大家,这个方法里处理很多事。前面刚说过,一个函数应当只做一件事。 把不同flag的代码拆分到多个函数里。

坏:

 function createFile(string $name, bool $temp = false): void
{
    if ($temp) {
        touch('./temp/'.$name);
    } else {
        touch($name);
    }
}
好:
 
function createFile(string $name): void
{
    touch($name);
}
 
function createTempFile(string $name): void
{
    touch('./temp/'.$name);
}

避免副作用

一个函数做了比获取一个值然后返回另外一个值或值们会产生副作用如果。副作用可能是写入一个文件,修改某些全局变量或者偶然的把你全部的钱给了陌生人。

 

现在,你的确需要在一个程序或者场合里要有副作用,像之前的例子,你也许需要写一个文件。你想要做的是把你做这些的地方集中起来。不要用几个函数和类来写入一个特定的文件。用一个服务来做它,一个只有一个。

 

重点是避免常见陷阱比如对象间共享无结构的数据,使用可以写入任何的可变数据类型,不集中处理副作用发生的地方。如果你做了这些你就会比大多数程序员快乐。

坏:

 // Global variable referenced by following function.
// If we had another function that used this name, now it'd be an array and it could break it.
$name = 'Ryan McDermott';
 
function splitIntoFirstAndLastName(): void
{
    global $name;
 
    $name = explode(' ', $name);
}
 
splitIntoFirstAndLastName();
 
var_dump($name); // ['Ryan', 'McDermott'];

好:

 function splitIntoFirstAndLastName(string $name): array
{
    return explode(' ', $name);
}
 
$name = 'Ryan McDermott';
$newName = splitIntoFirstAndLastName($name);
 
var_dump($name); // 'Ryan McDermott';
var_dump($newName); // ['Ryan', 'McDermott'];

6. 不要写全局函数

在大多数语言中污染全局变量是一个坏的实践,因为你可能和其他类库冲突 并且调用你api的人直到他们捕获异常才知道踩坑了。让我们思考一种场景: 如果你想配置一个数组,你可能会写一个全局函数config(),但是他可能 和试着做同样事的其他类库冲突。

坏:

 function config(): array
{
    return  [
        'foo' => 'bar',
    ]
}

好:

class Configuration
{
    private $configuration = [];
 
    public function __construct(array $configuration)
    {
        $this->configuration = $configuration;
    }
 
    public function get(string $key): ?string
    {
        return isset($this->configuration[$key]) ? $this->configuration[$key] : null;
    }
}
加载配置并创建 Configuration 类的实例
 
$configuration = new Configuration([
    'foo' => 'bar',
]);

现在你必须在程序中用 Configuration

5. N'utilisez pas flag comme paramètre de fonctionflag dit à tout le monde que cette méthode gère beaucoup de choses. Comme mentionné précédemment, une fonction ne doit faire qu’une seule chose. Divisez le code de différents indicateurs en plusieurs fonctions.

Mauvais :
  1.  class DBConnection
    {
        private static $instance;
     
        private function __construct(string $dsn)
        {
            // ...
        }
     
        public static function getInstance(): DBConnection
        {
            if (self::$instance === null) {
                self::$instance = new self();
            }
     
            return self::$instance;
        }
     
        // ...
    }
     $singleton = DBConnection::getInstance();

    Éviter les effets secondaires

  2. Une fonction qui fait plus que récupérer une valeur et renvoyer une ou plusieurs autres valeurs aura des effets secondaires si. Les effets secondaires pourraient être l’écriture dans un fichier, la modification de certaines variables globales ou le fait de donner accidentellement tout votre argent à un inconnu.

  3. Maintenant, vous devez avoir des effets secondaires dans un programme ou une situation. Comme dans l'exemple précédent, vous devrez peut-être écrire un fichier. Ce que vous voulez faire, c'est centraliser les endroits où vous faites cela. N'utilisez pas plusieurs fonctions et classes pour écrire dans un fichier spécifique. Faites-le avec un service et un seul.

  4. L'objectif est d'éviter les pièges courants tels que le partage de données non structurées entre des objets, l'utilisation de types de données mutables qui peuvent être écrits sur n'importe quoi, et de ne pas se concentrer sur l'endroit où les effets secondaires se produisent. Si vous faites cela, vous serez plus heureux que la plupart des programmeurs.

    🎜🎜Mauvais :🎜🎜
     class DBConnection
    {
        public function __construct(string $dsn)
        {
            // ...
        }
     
         // ...
    }
    🎜🎜Bon :🎜🎜
     if ($article->state === 'published') {
        // ...
    }
    🎜🎜🎜6. N'écrivez pas de fonctions globales🎜🎜🎜Polluer des variables globales est une mauvaise pratique dans la plupart des langages car Vous pourriez être en conflit avec d'autres bibliothèques et les personnes appelant votre API ne sauront pas qu'elles ont des problèmes jusqu'à ce qu'elles détectent l'exception. Considérons un scénario : si vous souhaitez configurer un tableau, vous pouvez écrire une fonction globale config(), mais elle pourrait entrer en conflit avec d'autres bibliothèques essayant de faire la même chose. 🎜🎜Mauvais :🎜
     if ($article->isPublished()) {
        // ...
    }
    🎜Bon :🎜
     function isDOMNodeNotPresent(\DOMNode $node): bool
    {
        // ...
    }
     
    if (!isDOMNodeNotPresent($node))
    {
        // ...
    }
    🎜Maintenant, vous devez utiliser une instance de Configuration dans votre programme🎜🎜🎜🎜🎜7. N'utilisez pas le modèle singleton🎜🎜🎜Un singleton est. a Anti-modèle Voici l'explication : Paraphrasé de Brian Button : 🎜🎜🎜🎜 est toujours utilisé comme une instance globale. Ils sont généralement utilisés comme instance globale, pourquoi est-ce si grave ? Parce que vous cachez les dépendances de votre application dans votre code, au lieu de les exposer via les interfaces. Créer quelque chose de global pour éviter de le transmettre est une odeur de code.🎜🎜. 🎜🎜Ils violent le principe de responsabilité unique : du fait qu'ils contrôlent leur propre création et leur propre cycle de vie.🎜🎜🎜🎜Ils provoquent intrinsèquement un couplage étroit du code, ce qui rend leur simulation plutôt difficile dans de nombreux cas 🎜. 🎜🎜🎜Toujours porter l'état tout au long de la vie du programme. Ils transportent l'état pendant toute la durée de vie de l'application. Un autre problème pour les tests, car vous pouvez vous retrouver dans une situation où des tests doivent être commandés, ce qui est un grand non pour les tests unitaires. Pourquoi ? .🎜
  5. Voici un très bon article traitant de la cause profonde du modèle singleton ((http://misko.hevery.com/2008/08/25/root-cause-of-singletons/) par Misko Hevery Written.

Mauvais :

 function isDOMNodePresent(\DOMNode $node): bool
{
    // ...
}
 
if (isDOMNodePresent($node)) {
    // ...
}

Bon :

 class Airplane
{
    // ...
 
    public function getCruisingAltitude(): int
    {
        switch ($this->type) {
            case '777':
                return $this->getMaxAltitude() - $this->getPassengerCount();
            case 'Air Force One':
                return $this->getMaxAltitude();
            case 'Cessna':
                return $this->getMaxAltitude() - $this->getFuelExpenditure();
        }
    }
}

Créez une instance de la classe DBConnection et configurez-la via DSN.DBConnection 类的实例并通过 DSN 配置.

$connection = new DBConnection($dsn);

现在你必须在程序中 使用 DBConnection

$connection = new DBConnection($ dsn) ;

Maintenant, vous devez utiliser une instance de DBConnection dans votre programme

8 Encapsulation des instructions conditionnelles

Mauvais :

interface Airplane
{
    // ...
 
    public function getCruisingAltitude(): int;
}
 
class Boeing777 implements Airplane
{
    // ...
 
    public function getCruisingAltitude(): int
    {
        return $this->getMaxAltitude() - $this->getPassengerCount();
    }
}
 
class AirForceOne implements Airplane
{
    // ...
 
    public function getCruisingAltitude(): int
    {
        return $this->getMaxAltitude();
    }
}
 
class Cessna implements Airplane
{
    // ...
 
    public function getCruisingAltitude(): int
    {
        return $this->getMaxAltitude() - $this->getFuelExpenditure();
    }
}

Bon : .
 function travelToTexas($vehicle): void
{
    if ($vehicle instanceof Bicycle) {
        $vehicle->pedalTo(new Location('texas'));
    } elseif ($vehicle instanceof Car) {
        $vehicle->driveTo(new Location('texas'));
    }
}

9. Évitez les jugements conditionnels

Mauvais :

 function travelToTexas(Vehicle $vehicle): void
{
    $vehicle->travelTo(new Location('texas'));
}

Bon :
 function combine($val1, $val2): int
{
    if (!is_numeric($val1) || !is_numeric($val2)) {
        throw new \Exception('Must be of type Number');
    }
 
    return $val1 + $val2;
}

10. Tâche. Quand les gens entendent cette phrase pour la première fois. , disent-ils : « Que puis-je faire sans instruction if ? » La réponse est que vous pouvez utiliser le polymorphisme pour réaliser la même tâche dans plusieurs scénarios. « C'est bien de faire cela, mais pourquoi devrais-je le faire ? est un principe du Clean Code que nous avons appris plus tôt : une fonction ne doit faire qu'une seule chose

Mauvais : .

 function combine(int $val1, int $val2): int
{
    return $val1 + $val2;
}

Bon :

function oldRequestModule(string $url): void
{
    // ...
}
 
function newRequestModule(string $url): void
{
    // ...
}
 
$request = newRequestModule($requestUrl);
inventoryTracker('apples', $request, 'www.inventory-awesome.io');

11. Éviter la vérification de type (partie 1)

PHP est faiblement typé, ce qui signifie que votre fonction peut accepter des paramètres de n'importe quel type. Parfois, vous souffrez de cette liberté et essayez de le faire. vérifiez le type de vos fonctions. La première consiste à unifier l'API

Mauvais :

 function requestModule(string $url): void
{
    // ...
}
 
$request = requestModule($requestUrl);
inventoryTracker('apples', $request, 'www.inventory-awesome.io');

Bon :

rrreee

12. valeurs primitives telles que des chaînes, des entiers et des tableaux, la version requise est PHP 7+, qui ne nécessite pas de polymorphisme et nécessite une détection de type, alors vous devriez envisager la déclaration de type ou le mode strict Le problème avec la fourniture de types statiques basés sur PHP standard. la syntaxe est qu'il faut beaucoup de bêtises pour le faire correctement, ce qui semble être juste pour des raisons de sécurité. Indépendamment de la perte de lisibilité, gardez votre PHP propre, écrivez de bons tests et effectuez des révisions de code. Déclarations de type strict PHP et mode strict pour garantir la sécurité

rrreee

Bon :

rrreee

13. Supprimer le code zombie

Le code zombie est tout aussi mauvais qu'un code en double. ça!, donc c'est sûr. Mauvais :

rrreee

Bon :

rrreee