Clean code trong PHP

18/03/2021 - lượt xem
Chia sẻ
 
Rate this post

Vấn đề Clean Code đã được nhắc tới từ trong cuốn sách cùng tên của C. Martin. Cuốn sách này cũng được Code từ tâm nhắc đến trong các bài viết trước đây. Các bạn có thể tham khảo chuỗi bài Clean code tiếng việt.

Trong bài viết này sẽ đi cụ thể hơn về Clean Code với PHP. Bài viết được trên bài viết gốc tại https://github.com/jupeter/clean-code-php

Đặt tên biến

Đặt tên biến có ý nghĩa và có thể đọc hiểu được

Mã kém

declare(strict_types=1);

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

Mã tốt

declare(strict_types=1);

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

Thống nhất cách đặt trên cho cùng 1 loại biến

Kém

declare(strict_types=1);

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

Tốt

declare(strict_types=1);

getUser();

Sử dụng tên có thể tìm kiếm được

Thường thì chúng ta sẽ cần phải đọc, tìm lại code sau 1 khoảng thời gian. Để việc này không mất thời gian thì việc đặt tên cho các hằng số, biến là điều cần thiết.

Kém

declare(strict_types=1);

// 448 có nghĩa là gì?
$result = $serializer->serialize($data, 448);

Tốt

declare(strict_types=1);

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

Một ví dụ khác

Kém

declare(strict_types=1);

class User
{
    // 7 ở đây ý nghĩa là gì
    public $access = 7;
}

// 4 có ý nghĩa gì?
if ($user->access & 4) {
    // ...
}

// Đoạn mã này thực sự đang muốn làm gì?
$user->access ^= 2;

Tốt

declare(strict_types=1);

class User
{
    public const ACCESS_READ = 1;

    public const ACCESS_CREATE = 2;

    public const ACCESS_UPDATE = 4;

    public const ACCESS_DELETE = 8;

    // Quyền mặc định sẽ là đọc, khởi tạo, cập nhật
    public $access = self::ACCESS_READ | self::ACCESS_CREATE | self::ACCESS_UPDATE;
}

if ($user->access & User::ACCESS_UPDATE) {
    // do edit ...
}

// Hủy bỏ quyền khởi tạo (create)
$user->access ^= User::ACCESS_CREATE;

Sử dụng các biến có ý nghĩa

Kém

declare(strict_types=1);

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

saveCityZipCode($matches[1], $matches[2]);

Tạm chấp nhận

declare(strict_types=1);

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

[, $city, $zipCode] = $matches;
saveCityZipCode($city, $zipCode);

Tốt

Đặt tên cho các sub pattern

declare(strict_types=1);

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

saveCityZipCode($matches['city'], $matches['zipCode']);

Tránh việc lồng thẻ quá sâu và return liên tục

Việc thực hiện if else liên tục chỉ làm cho code bạn phức tạp hơn mà thôi

Kém

declare(strict_types=1);

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;
            }
            return false;
        }
        return false;
    }
    return false;
}

Tốt

declare(strict_types=1);

function isShopOpen(string $day): bool
{
    if (empty($day)) {
        return false;
    }

    $openingDays = ['friday', 'saturday', 'sunday'];

    return in_array(strtolower($day), $openingDays, true);
}

Một ví dụ khác vì việc lồng cấp

Kém

declare(strict_types=1);

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

Tốt

declare(strict_types=1);

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

Đừng bắt người đọc phải dịch nghĩa tên biến của bạn

Kém

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

Tốt

declare(strict_types=1);

$locations = ['Austin', 'New York', 'San Francisco'];

foreach ($locations as $location) {
    doStuff();
    doSomeOtherStuff();
    // ...
    // ...
    // ...
    dispatch($location);
}

Không thêm ngữ cảnh không cần thiết

Nếu tên class, đối tượng của bạn đã có ý nghĩa rồi, thì không nhất thiết phải lặp lại chúng trong tên biến

Kém

declare(strict_types=1);

class Car
{
    public $carMake;

    public $carModel;

    public $carColor;

    //...
}

Tốt

declare(strict_types=1);

class Car
{
    public $make;

    public $model;

    public $color;

    //...
}

Sử dụng giá trị mặc định cho tham số hàm

Không tốt

Trước đây chúng ta hay dùng như ví dụ dưới đây. Tuy vậy khi gọi hàm này, giá trị truyền vào có thể là NULL. Do đó chưa được tốt lắm!

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

Không tồi

Việc check giá trị như ví dụ dưới đây cũng tạm chấp nhận. Tuy vậy chúng ta mất thêm công sức để check giá trị của biến trước khi sử dụng.

function createMicrobrewery($name = null): void
{
    $breweryName = $name ?: 'Hipster Brew Co.';
    // ...
}

Tốt

Hãy sử dụng thêm kiểu dữ liệu tham số truyền vào (type hinting) để chắc chắn dữ liệu truyền vào là chuẩn xác

Như ví dụ dưới đây, giá trị truyền vào không thể là NULL.

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

So sánh

Tham khảo thêm https://www.php.net/manual/en/language.operators.comparison.php

Không tốt

So sánh thông thường sẽ chuyển từ string thành integer

Hàm if dưới đây sẽ return FALSE, mặc dù bản chất phải là TRUE

declare(strict_types=1);

$a = '42';
$b = 42;

if ($a != $b) {
    // The expression will always pass
}

Tốt

Hãy so sánh cả kiểu dữ liệu của các biến.

declare(strict_types=1);

$a = '42';
$b = 42;

if ($a !== $b) {
    // The expression is verified
}

Toán tử kiểm tra Null

Toán tử kiểm tra null ?? được giới thiệu từ PHP 7. Toán tử này trả về giá trị biến đầu nếu không null và trả vế biến thứ 2 nếu biến đầu tiên bị null.

Kém

declare(strict_types=1);

if (isset($_GET['name'])) {
    $name = $_GET['name'];
} elseif (isset($_POST['name'])) {
    $name = $_POST['name'];
} else {
    $name = 'nobody';
}

Tốt

declare(strict_types=1);

$name = $_GET['name'] ?? $_POST['name'] ?? 'nobody';

Clean code với Function

Số lượng tham số Function (lý tưởng là 2 hoặc ít hơn)

Việc có số lượng tham số ít sẽ giúp code trông sạch sẽ hơn. Đồng thời việc kiểm tra tính đúng đắn hoặc kiểm tra dữ liệu đầu vào cũng ngắn gọn hơn.

Hàm không có tham số là trường hợp tốt nhất, Một hoặc 2 tham số là khá tốt. Ba tham số thì tạm chấp được. Nhưng nhiều hơn thì bạn nên xem xét tới việc tối ưu lại. Ví dụ như quá nhiều tham số đầu vào có thể chuyển đổi hàm đó về dạng class.

Kém

declare(strict_types=1);

class Questionnaire
{
    public function __construct(
        string $firstname,
        string $lastname,
        string $patronymic,
        string $region,
        string $district,
        string $city,
        string $phone,
        string $email
    ) {
        // ...
    }
}

Tốt

declare(strict_types=1);

class Name
{
    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 ...
}

class City
{
    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 ...
}

class Contact
{
    private $phone;

    private $email;

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

Tên Function nên nói rõ ý nghĩa của nó

Kém

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

Tốt

class Email
{
    //...

    public function send(): void
    {
        mail($this->to, $this->subject, $this->body);
    }
}

$message = new Email(...);
// Clear and obvious
$message->send();

 

Function chỉ nên có 1 cấp độ trừu tượng

Khi bạn có nhiều hơn nghiệp vụ cần xử lý thì là lúc bạn cần tới việc chia nhỏ để đạt được hiệu quả sử dụng và test.

Kém

declare(strict_types=1);

function parseBetterPHPAlternative(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...
    }
}

Không tồi

Mặc dù đã tối ưu nhưng hàm parseBetterPHPAlternative vẫn còn khá phức tạp.

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 parseBetterPHPAlternative(string $code): void
{
    $tokens = tokenize($code);
    $ast = lexer($tokens);
    foreach ($ast as $node) {
        // parse...
    }
}

Tốt

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

Không sử dụng các biến cờ (biến boolean) để làm tham số

Kém

declare(strict_types=1);

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

Tốt

declare(strict_types=1);

function createFile(string $name): void
{
    touch($name);
}

function createTempFile(string $name): void
{
    touch('./temp/' . $name);
}

Tránh tác dụng phụ

Một hàm có tác dụng phụ nếu như nó thực hiện nhiều hơn một nhiệm vụ trong hàm đó. Tác dụng phụ đó có thể như là ghi file, chỉnh sửa biến global, …

Kém

declare(strict_types=1);

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

Tốt

declare(strict_types=1);

function splitIntoFirstAndLastName(string $name): array
{
    return explode(' ', $name);
}

$name = 'Ryan McDermott';
$newName = splitIntoFirstAndLastName($name);

var_dump($name);
// 'Ryan McDermott';

var_dump($newName);
// ['Ryan', 'McDermott'];

Không viết các hàm global

Việc này có thể tạo ra sự xung đột với các hàm cùng tên trong các thư viện khác. Chính vì vậy chúng ta nên hạn chế việc sử dụng các hàm global.

Kém

declare(strict_types=1);

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

Tốt

declare(strict_types=1);

class Configuration
{
    private $configuration = [];

    public function __construct(array $configuration)
    {
        $this->configuration = $configuration;
    }

    public function get(string $key): ?string
    {
        // null coalescing operator
        return $this->configuration[$key] ?? null;
    }
}

Khi đó lấy config thông qua class Configuration

declare(strict_types=1);

$configuration = new Configuration([
    'foo' => 'bar',
]);

Hãy cẩn thận khi sử dụng Singleton

Bởi lẽ Singleton là một anti-pattern với các lý do

+ Pattern này sẽ ẩn đi các phụ thuộc của ứng dụng bên trong mã code của bạn tya vì thông qua các interface.

+ Vi phạm nguyên tắc đơn chức năng trong SOLID vì thực tế là với Singleton tự điều khiển vòng đời của nó.

+ Làm test khó khăn hơn

Chưa tốt

declare(strict_types=1);

class DBConnection
{
    private static $instance;

    private function __construct(string $dsn)
    {
        // ...
    }

    public static function getInstance(): self
    {
        if (self::$instance === null) {
            self::$instance = new self();
        }

        return self::$instance;
    }

    // ...
}

$singleton = DBConnection::getInstance();

Tốt hơn

declare(strict_types=1);

class DBConnection
{
    public function __construct(string $dsn)
    {
        // ...
    }

    // ...
}

Khi này, bạn tạo đối tượng của DBConnection và sử dụng

declare(strict_types=1);

$connection = new DBConnection($dsn);

Đóng gói các điều kiện

Kém

declare(strict_types=1);

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

Tốt

declare(strict_types=1);

if ($article->isPublished()) {
    // ...
}

Loại bỏ các điều kiện phủ định

Kém

declare(strict_types=1);

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

if (! isDOMNodeNotPresent($node)) {
    // ...
}

Tốt

declare(strict_types=1);

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

if (isDOMNodePresent($node)) {
    // ...
}

Tránh câu lệnh rẽ nhánh liên tục

Thay vì sử dụng câu lệnh if kiểm tra liên tục, bạn có thể sử dụng tính đa hình để làm việc đó.

Kém

declare(strict_types=1);

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

Tốt

declare(strict_types=1);

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

Tránh các câu lệnh kiểm tra kiểu dữ liệu

PHP là ngôn ngữ không kiểu dữ liệu, mặc dù điều này được cải thiện ở các phiên bản PHP mới. Điều này có nghĩa là các function có thể nhận bất kì kiểu dữ liệu nào. Để giải quyết vấn đề này chúng ta có thể giải quyết bằng cách sử dụng tính chất kế thừa, đa hình.

Kém

declare(strict_types=1);

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

Tốt

declare(strict_types=1);

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

Đối với các kiểu dữ liệu nguyên thủy như int, array, string… thì việc sử dụng tính đa hình là không thể. Do vậy hãy chỉ đích danh kiểu dữ liệu của biến.

Kém

declare(strict_types=1);

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

    return $val1 + $val2;
}

Tốt

declare(strict_types=1);

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

Xóa bỏ các dead code

Dead code cũng tệ như việc duplicate code vậy. Hãy loại bỏ chúng!

Kém

declare(strict_types=1);

function oldRequestModule(string $url): void
{
    // ...
}

function newRequestModule(string $url): void
{
    // ...
}

$request = newRequestModule($requestUrl);
inventoryTracker('apples', $request, 'www.inventory-awesome.io');

Tốt

declare(strict_types=1);

function requestModule(string $url): void
{
    // ...
}

$request = requestModule($requestUrl);
inventoryTracker('apples', $request, 'www.inventory-awesome.io');

Các đối tượng và cấu trúc dữ liệu

Trong PHP, bạn sử dụng public, private, protected để điều khiển quyền truy cập vào một đối tượng.

Kém

declare(strict_types=1);

class BankAccount
{
    public $balance = 1000;
}

$bankAccount = new BankAccount();

// Buy shoes...
$bankAccount->balance -= 100;

Tốt

class BankAccount
{
    private $balance;

    public function __construct(int $balance = 1000)
    {
      $this->balance = $balance;
    }

    public function withdraw(int $amount): void
    {
        if ($amount > $this->balance) {
            throw new \Exception('Amount greater than available balance.');
        }

        $this->balance -= $amount;
    }

    public function deposit(int $amount): void
    {
        $this->balance += $amount;
    }

    public function getBalance(): int
    {
        return $this->balance;
    }
}

$bankAccount = new BankAccount();

// Buy shoes...
$bankAccount->withdraw($shoesPrice);

// Get balance
$balance = $bankAccount->getBalance();

Một ví dụ khác

Kém

declare(strict_types=1);

class Employee
{
    public $name;

    public function __construct(string $name)
    {
        $this->name = $name;
    }
}

$employee = new Employee('John Doe');
// Employee name: John Doe
echo 'Employee name: ' . $employee->name;

Tốt

declare(strict_types=1);

class Employee
{
    private $name;

    public function __construct(string $name)
    {
        $this->name = $name;
    }

    public function getName(): string
    {
        return $this->name;
    }
}

$employee = new Employee('John Doe');
// Employee name: John Doe
echo 'Employee name: ' . $employee->getName();

 

Classes

Ưu tiên sử dụng Composition hơn là Kế thừa.

Bạn nên xác định xem khi nào nên sử dụng kế thừa, khi nào nên sử dụng Composition. Trong mỗi hoàn cảnh khác khác thì các cách này sẽ tạo ra lợi ích nhất định.

Việc kế thừa sẽ có những lợi ích như

+ Kế thừa thể hiện được mối quan hệ “is – a” và không phải là mối quan hệ “has – a” (Hunmain -> Animal với User -> UserDetails)

+ Sử dụng code từ các lớp cha.

+ Thay đổi code ở lớp dẫn xuất thì toàn bộ các lớp kế thừa đều có tác dụng

Tuy vậy Composition sẽ có hiệu quả hơn trong trường hợp ứng dụng có độ phức tạp cao hơn. Hãy tưởng tượng nếu số lượng class kế thừa lớn, sẽ làm phức tạp ứng dụng, giảm hiệu năng…

Kém

declare(strict_types=1);

class Employee
{
    private $name;

    private $email;

    public function __construct(string $name, string $email)
    {
        $this->name = $name;
        $this->email = $email;
    }

    // ...
}

// Bad because Employees "have" tax data.
// EmployeeTaxData is not a type of Employee

class EmployeeTaxData extends Employee
{
    private $ssn;

    private $salary;

    public function __construct(string $name, string $email, string $ssn, string $salary)
    {
        parent::__construct($name, $email);

        $this->ssn = $ssn;
        $this->salary = $salary;
    }

    // ...
}

Tốt

declare(strict_types=1);

class EmployeeTaxData
{
    private $ssn;

    private $salary;

    public function __construct(string $ssn, string $salary)
    {
        $this->ssn = $ssn;
        $this->salary = $salary;
    }

    // ...
}

class Employee
{
    private $name;

    private $email;

    private $taxData;

    public function __construct(string $name, string $email)
    {
        $this->name = $name;
        $this->email = $email;
    }

    public function setTaxData(EmployeeTaxData $taxData): void
    {
        $this->taxData = $taxData;
    }

    // ...
}

 

Tránh fluent interface

Fluent Interface là một API hướng đối tượng nhằm mục đích cải thiện khả năng đọc của mã nguồn bằng cách sử dụng Method chaining.

Kém

declare(strict_types=1);

class Car
{
    private $make = 'Honda';

    private $model = 'Accord';

    private $color = 'white';

    public function setMake(string $make): self
    {
        $this->make = $make;

        // NOTE: Returning this for chaining
        return $this;
    }

    public function setModel(string $model): self
    {
        $this->model = $model;

        // NOTE: Returning this for chaining
        return $this;
    }

    public function setColor(string $color): self
    {
        $this->color = $color;

        // NOTE: Returning this for chaining
        return $this;
    }

    public function dump(): void
    {
        var_dump($this->make, $this->model, $this->color);
    }
}

$car = (new Car())
    ->setColor('pink')
    ->setMake('Ford')
    ->setModel('F-150')
    ->dump();

Tốt

declare(strict_types=1);

class Car
{
    private $make = 'Honda';

    private $model = 'Accord';

    private $color = 'white';

    public function setMake(string $make): void
    {
        $this->make = $make;
    }

    public function setModel(string $model): void
    {
        $this->model = $model;
    }

    public function setColor(string $color): void
    {
        $this->color = $color;
    }

    public function dump(): void
    {
        var_dump($this->make, $this->model, $this->color);
    }
}

$car = new Car();
$car->setColor('pink');
$car->setMake('Ford');
$car->setModel('F-150');
$car->dump();

Nên sử dụng final class

Từ khóa final nên sử dụng khi có thể, vì:

+ Ngăn chặn việc kế thừa không thể kiểm soát

+ Khuyến khích sử dụng Composition thay vì kế thừa

+ Khuyến khích nguyên tắc đơn chức năng trong Solid

+ Khuyến khích các lập trình viên khác tận dụng sử dụng các hàm public thay vì cố gắng mở rộng class và thiệp vào class đó

+ Bạn có thể thay đổi code của mình mà ít ảnh hưởng đến ứng dụng – các phần đang sử dụng class của bạn.

Điều kiện để triển khai là, bạn nên implement một 1 interface và không có thêm public method nào khác.

Kém

declare(strict_types=1);

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

Tốt

declare(strict_types=1);

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

    public function getColor()
    {
        return $this->color;
    }
}

Để đảm bảo có được một ứng dụng web sạch sẽ và tốt bạn nên áp dụng các gợi ý Clean code trong Php trên đây. Mặc dù các tiêu chí này không phải là bắt buộc nhưng là điều cần thiết trước khi phát triển ứng dụng bằng PHP.

Ngoài các tiêu chí clean code trong php này bạn nên tuân thủ theo nguyên tắc SOLID để đảm bảo chương trình được tối ưu và đạt hiệu quả tốt khi phát triển và vận hành. Trong suốt quá trình phát triển nên hạn chế tối đa việc lặp lại code không cần thiết. Điều này còn biết đến với tên là Nguyên tắc DRY (Dont Repeat yourself)!

    Liên hệ với chúng tôi

    Để lại thông tin để nhận được các bài viết khác

    Rate this post

    Xem thêm nhiều bài tin mới nhất về Clean code

    Xem thêm