Funktion


Funktion

1. Funktionsparameter (vorzugsweise weniger als 2)

2. Die Funktion sollte nur eine Sache tun

3. Der Funktionsname sollte widerspiegeln, was er tut

Die Funktion sollte nur eine Abstraktionsebene enthalten

Nicht Flag als Funktion verwenden Die Parameter von

6. Vermeiden Sie Nebenwirkungen

7. Schreiben Sie keine globalen Funktionen

8. Verwenden Sie kein Singleton-Muster

9. Kapseln Sie bedingte Aussagen

10. Vermeiden Sie die Verwendung von antonymen bedingten Urteilen

11. Vermeiden Sie bedingte Urteile

12. Typprüfung vermeiden (Teil 1)

13. Typprüfung vermeiden (Teil 2)

14. Zombie-Code entfernen

1. Funktionsparameter (vorzugsweise weniger als 2)

Es ist äußerst wichtig, die Anzahl der Funktionsparameter zu begrenzen, damit Sie Ihre Funktion einfacher testen können. Wenn Sie über mehr als drei optionale Parameter verfügen, kommt es zu einer explosionsartigen Kombinationsvielfalt, und Sie können jede Menge unabhängige Parameterszenarien testen.

Keine Parameter sind die ideale Situation. 1 oder 2 sind in Ordnung, 3 sollte man am besten vermeiden. Noch mehr und es braucht Verstärkung. Wenn Ihre Funktion mehr als zwei Parameter hat, bedeutet das normalerweise, dass sie zu viel zu verarbeiten hat. Wenn viele Daten übergeben werden müssen, empfiehlt es sich, ein High-Level-Objekt als Parameter zu kapseln.

Schlecht:

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

Gut:

 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. Funktionen sollten nur eine Sache tun

Dies ist mit Abstand die wichtigste Regel im Software-Engineering. Wenn eine Funktion mehr als eine Aufgabe erfüllt, ist es schwierig, sie zu implementieren, zu testen und zu verstehen. Wenn Sie eine Funktion auf nur eine Funktion aufteilen, lassen sie sich einfacher umgestalten und Ihr Code liest sich sauberer. Wenn Sie diese Regel einfach befolgen, sind Sie den meisten Entwicklern voraus.

Schlecht:

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

Gut:

 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. Der Funktionsname sollte widerspiegeln, was er tut

Schlecht:

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

Gut:

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

4. Die Funktion sollte nur eine Abstraktionsebene enthalten

Wenn Sie zu viele Abstraktionsebenen haben, verarbeitet die Funktion zu viele Dinge. Die Aufteilungsfunktionalität ist erforderlich, um die Wiederverwendbarkeit und Benutzerfreundlichkeit zu verbessern und das Testen zu vereinfachen. (Anmerkung des Übersetzers: Dem Beispielcode nach zu urteilen, sollte dies auf zu viel Verschachtelung hinweisen)

Schlecht:

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

Schlecht:

Wir haben einige Methoden aus der Schleife extrahiert, aber parseBetterJSAlternative()die Methoden sind immer noch kompliziert und nicht zum Testen geeignet.

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

Gut:

Die beste Lösung besteht darin, die Abhängigkeit der Methode parseBetterJSAlternative() zu entfernen.

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

Auf diese Weise können wir mock die Abhängigkeit bearbeiten und testen, ob BetterJSAlternative::parse() sie wie erwartet funktioniert.

5. Flag nicht als Funktionsparameter verwenden

Flag sagt allen, dass diese Methode viele Dinge erledigt. Wie bereits erwähnt, sollte eine Funktion nur eine Sache tun. Teilen Sie den Code für verschiedene Flags in mehrere Funktionen auf.

Schlecht:

 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);
}

Nebenwirkungen vermeiden

Eine Funktion kann mehr, als nur einen Wert abzurufen und einen anderen zurückzugeben Der Wert oder die Werte haben Nebenwirkungen, wenn. Nebenwirkungen können das Schreiben in eine Datei, das Ändern einiger globaler Variablen oder die versehentliche Weitergabe Ihres gesamten Geldes an einen Fremden sein.

Nun müssen Sie in einem Programm oder einer Situation Nebenwirkungen haben. Wie im vorherigen Beispiel müssen Sie möglicherweise eine Datei schreiben. Sie möchten die Orte, an denen Sie dies tun, zentralisieren. Verwenden Sie nicht mehrere Funktionen und Klassen, um in eine bestimmte Datei zu schreiben. Machen Sie es mit einem Dienst und nur einem.

Der Schwerpunkt liegt auf der Vermeidung häufiger Fallstricke wie der gemeinsamen Nutzung unstrukturierter Daten zwischen Objekten, der Verwendung veränderlicher Datentypen, die in alles geschrieben werden können, und der Vermeidung einer Zentralisierung, wo Nebenwirkungen auftreten. Wenn Sie dies tun, werden Sie glücklicher sein als die meisten Programmierer.

Schlecht:

 // 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'];

Gut:

 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. Schreiben Sie keine globalen Funktionen

Das Verschmutzen globaler Variablen ist in den meisten Sprachen eine schlechte Praxis, da es zu Konflikten mit anderen Bibliotheken kommen kann und die Leute, die Ihre API aufrufen, erst merken, dass Sie in Schwierigkeiten sind Sie fangen die Ausnahme ein. Betrachten wir ein Szenario: Wenn Sie ein Array konfigurieren möchten, schreiben Sie möglicherweise eine globale Funktion config(), die jedoch möglicherweise mit anderen Bibliotheken in Konflikt steht, die dasselbe versuchen.

Schlecht:

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

Gut:

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',
]);

Jetzt müssen Sie eine Instanz von Configuration in Ihrem Programm

verwenden 7. Verwenden Sie nicht das Singleton-Muster

Singleton ist ein Anti-Muster. Hier ist die Erklärung: Umgeschrieben von Brian Button:

  1. wird immer als Global verwendet Instanz. Sie werden im Allgemeinen als globale Instanz verwendet. Warum ist das so schlimm, weil Sie die Abhängigkeiten Ihrer Anwendung in Ihrem Code verbergen, anstatt sie über die Schnittstellen offenzulegen, um eine Weitergabe zu vermeiden? >

  2. Sie verstoßen gegen das Prinzip der Einzelverantwortung: dadurch, dass sie ihre eigene Schöpfung kontrollieren und Lebenszyklus.

  3. Sie führen von Natur aus zu einer engen Kopplung des Codes, was es in vielen Fällen ziemlich schwierig macht, sie im Test vorzutäuschen.

  4. Immer mitnehmen Status während der gesamten Laufzeit Ihres Programms. Sie tragen den Status während der gesamten Lebensdauer der Anwendung bei sich, da es vorkommen kann, dass Tests angeordnet werden müssen, was für Unit-Tests ein großes Nein ist. Warum sollte dies der Fall sein? .

  5. Hier ist ein sehr guter Artikel, der die [grundlegenden Probleme des Singleton-Musters ((http://misko.hevery.com/2008/08/25/root-cause-of-singletons/)的文章,是MiskoHevery Geschrieben. Instanz und Übergabe des DSN Konfiguration.

Jetzt müssen Sie Instanzen von in Ihrem Programm verwenden

8. Kapselung bedingter Anweisungen

DBConnection

Schlecht: $connection = new DBConnection($dsn);

 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();

DBConnection Gut:

 class DBConnection
{
    public function __construct(string $dsn)
    {
        // ...
    }
 
     // ...
}
9. Vermeiden Sie die Verwendung von Antonymen, um

schlecht:

 if ($article->state === 'published') {
    // ...
}
gut:

 if ($article->isPublished()) {
    // ...
}
zu beurteilen 10. Vermeiden Sie bedingte Urteile

Dies scheint eine unmögliche Aufgabe zu sein. Wenn die Leute diesen Satz zum ersten Mal hören, werden sie sagen: „Was kann ich ohne eine if-Anweisung tun?“ um die gleiche Aufgabe in mehreren Szenarien zu erreichen. Die zweite Frage ist sehr häufig: „Es ist in Ordnung, aber warum sollte ich es tun?“ Die Antwort ist ein Clean-Code-Prinzip, das wir zuvor gelernt haben: Eine Funktion sollte nur Eines tun. Wenn Sie viele Klassen und Funktionen mit if-Anweisungen haben, erledigen Ihre Funktionen mehr als eine Aufgabe. Denken Sie daran, nur eines zu tun. >11. Vermeiden Sie Typprüfungen (Teil 1)

PHP ist schwach typisiert, was bedeutet, dass Ihre Funktionen Parameter jeglichen Typs empfangen können. Manchmal leiden Sie unter dieser Freiheit und versuchen nach und nach die Typprüfung in Ihren Funktionen. Es gibt viele Möglichkeiten, dies zu vermeiden. Die erste Möglichkeit besteht darin, die API zu vereinheitlichen 2)

Wenn Sie grundlegende Grundwerte wie Zeichenfolgen, Ganzzahlen und Arrays verwenden, die erforderliche Version PHP 7 ohne Polymorphismus ist und eine Typprüfung erfordert, sollten Sie die Typdeklaration in Betracht ziehen oder strikter Modus. Bietet statische Typisierung basierend auf der Standard-PHP-Syntax. Das Problem bei der manuellen Typprüfung besteht darin, dass sie viel Unsinn erfordert, was auf Kosten der Wartung Ihres PHP geht. Seien Sie aufgeräumt, schreiben Sie gute Tests und führen Sie Codeüberprüfungen durch, um die Sicherheit zu gewährleisten >13. Zombie-Code entfernen Zombie-Code ist genauso schlimm wie doppelter Code. Es gibt keinen Grund, es in Ihrer Codebasis zu behalten. Wenn es noch nie aufgerufen wurde, löschen Sie es! Da es sich noch im Code-Repository befindet, ist es sicher.

Schlecht:

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

Gut:

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