07/09/2018, 18:00

PSR-2: Chuẩn trình bày code PHP đẹp

PSR-2: Coding Style Guide Bộ quy tắc này được tạo ra nhằm giảm bới những khó khăn trong việc đọc code của người khác, trình bày theo quy tắc ở đây áp dụng cho tất cả các Project, giúp cho code sáng sủa, dễ hiểu, dễ bảo trì hơn. Bài viết này yêu cầu bạn xem qua PSR-1: Chuẩn viết code PHP cơ bản ...

PSR-2: Coding Style Guide Bộ quy tắc này được tạo ra nhằm giảm bới những khó khăn trong việc đọc code của người khác, trình bày theo quy tắc ở đây áp dụng cho tất cả các Project, giúp cho code sáng sủa, dễ hiểu, dễ bảo trì hơn. Bài viết này yêu cầu bạn xem qua PSR-1: Chuẩn viết code PHP cơ bản bởi vì chuẩn PSR-2 dựa trên PSR-1 và mở rộng thêm

1. Nguyên tắc chung

1.1. Tuân thủ PSR-1

PSR-2 dựa trên PSR-1 và mở rộng thêm cho nên tuân thủ theo PSR-1 là điều hoàn toàn dễ hiểu phải không nào, đọc ngay PSR-1 tại đây: PSR-1: Chuẩn viết code PHP cơ bản

1.2. Đối với file php

  1. Mọi PHP files phải dùng Unix LF (linefeed) line ending.
  2. Mọi PHP files phải kết thúc bằng một dòng trống.
  3. Trong một file chỉ bao gồm code PHP thì không được viết tag đóng ?> nhé.

 Nếu bạn dùng Editor/IDE, bạn nên cài EditorConfig để Editor/IDE giúp bạn trong việc này nhé, đọc ở đây Chuẩn hóa code style trên Editor/IDE bằng EditorConfig, trên sublime text Editor sẽ là end_of_line = lf và insert_final_newline = true

1.3. Lines - Về các dòng code

  • Không có hard limit về độ dài của một dòng. Tức là bạn có thể code 1 dòng dài đến tận cùng thế giới vẫn được.
  • Soft limit của độ dài một dòng phải là 120 chữ. Chương trình check style tự động phải báo warning nhưng không được báo error khi vượt quá soft limit.
  • Một dòng nên có không quá 80 chữ. Dòng mà dài quá 80 chữ thì nên chia nhỏ ra thành nhiều dòng với độ dài mỗi dòng không quá 80 chữ.
    Trong Sublime Text, bạn có thể chỉnh như sau để biết mình quá 80 ký tự hay không nha, ở trên thanh menu các bạn chọn View ➡Ruler➡80
  • Một dòng mà có ký tự thì không được dư khoảng trắng ở cuối dòng.
    public function foo()
    {
        return true;・・・・
    }
    
    // ・・・・ chính là khoảng trắng​
  • Không được phép có quá một statement (lệnh) trên một dòng.
    // sai quá sai
    $website = 'https://chungnguyen.xyz'; $name = 'Chung Nguyễn Blog';
    
    // phải như vầy
    $website = 'https://chungnguyen.xyz';
    $name = 'Chung Nguyễn Blog';​

1.4. Indenting - Canh lề

Canh lề không dùng tab mà phải dùng 4 dấu cách. Các Editor/IDE thông minh sẽ tự convert nút tab trên bàn phím thành dấu cách, các bạn search google sẽ ra nhé. Hình dưới là cách cấu hình cho sublime text

1.5. Keywords và True/False/Null

Những keywords của PHP phải được viết thường. (không viết hoa)

Những constants của PHP là true, false, và null cũng cần phải viết thường. TRUE, True  gì cơ bản là sai nguyên tắc hết nhé.

2. Khai báo Namespace và Use

  1. Cần phải có một dòng trắng phía sau khai báo namespace.
  2. Những phần khai báo use phải được đặt phía sau phần khai báo namespace.
  3. Phải dùng một từ use cho mỗi khao báo.
  4. Phải có một dòng trắng phía sau đoạn code use.

Ví dụ:

<?php
namespace VendorPackage;

use FooClass;
use BarClass as Bar;
use OtherVendorOtherPackageBazClass;
use Auth, View, Session; // sai, phải tách thành 3 dòng use

// ... additional PHP code ...

3. Classes, Properties, and Methods (Lớp, Thuộc tính và Phương thức - hàm)

Từ class ở đây được hiểu là cả những class bình thường, hay cả interfaces và traits.

3.1. Extends và Implements

Từ khoá extends và implements phải được viết cùng dòng với tên class.

Dấu mở ngoặc nhọn của class phải đứng trên một dòng riêng. Dấu đóng ngoặc phải được viết ở dòng sau của phần body.

<?php
namespace VendorPackage;

use FooClass;
use BarClass as Bar;
use OtherVendorOtherPackageBazClass;

class ClassName extends ParentClass implements ArrayAccess, Countable
{
    // constants, properties, methods
}

Danh sách những interface được implements có thể được viết trên nhiều dòng, trong đó mỗi dòng theo sau được indent (canh lề) 1 lần. Khi thực hiện việc đó thì tên interface đầu tiên phải được đặt trên 1 dòng mới, và mỗi dòng chỉ được phép chứa tên 1 interface.

Ví dụ

<?php
namespace VendorPackage;

use FooClass;
use BarClass as Bar;
use OtherVendorOtherPackageBazClass;

class ClassName extends ParentClass implements
    ArrayAccess,
    Countable,
    Serializable
{
    // constants, properties, methods
}

3.2. Properties - thuộc tính

Tính Visibility (public, protected, private) phải được khai báo ở mọi properties.

Không được dùng từ khoá var để khai báo một property.

Trên một dòng thì không được khai báo quá một property.

Tên property không nên được prefix bởi dấu gạch dưới _ để biểu thị tính protected hay private.

Khai báo property giống như sau.

<?php
namespace VendorPackage;

class ClassName
{
    public $foo = null;
}

3.3. Methods

Tương tự với property, tính Visibility phải được khao báo ở mọi methods

Tên Method không nên được prefix bởi dấu gạch dưới _ để biểu thị tính protected hay private.

Khi khai báo tên method thì không được để một khoảng trắng ở phía sau tên method. Dấu mở ngoặc nhọn phải được nằm trên một dòng riêng, và dấu đóng ngoặc phải được nằm trên dòng ngay sau phần thân của method. Không được có khoảng trắng sau dấu mở ngoặc tròn, và không được có khoảng trắng phía trước dấu đóng ngoặc tròn.

Khai báo một hàm giống như sau. Chú ý đến vị trí của dấu ngặc đơn, dấu phẩy, khoảng trắng và dấu ngoặc nhọn.

<?php
namespace VendorPackage;

class ClassName
{
    public function fooBarBaz($arg1, &$arg2, $arg3 = [])
    {
        // method body
    }
}

3.4. Method Arguments - Tham số của phương thức

Trong danh sách argument (tham số - đối số) thì không được có khoảng trắng trước mỗi dấu phẩy, và phải có một khoảng trắng sau mỗi dấu phẩy. Giống y như chính tả của ta vậy.

Những tham số mà có giá trị mặc định phải được đặt ở cuối của danh sách tham số. Ví du:

<?php
namespace VendorPackage;

class ClassName
{
    public function foo($arg1, &$arg2, $arg3 = [], $arg4 = true)
    {
        // method body
    }
}

Danh sách argument có thể được tách thành nhiều dòng, trong đó mỗi dòng theo sau được indent một lần. Khi làm vậy thì argument đầu tiên trong danh sách phải được đặt ở trên một dòng mới, và mỗi dòng chỉ được phép có một argument.

Khi mà danh sách argument được chia làm nhiều dòng, thì dấu đóng ngoặc tròn và dấu mở ngoặc nhọn phải được đặt cùng nhau trên một dòng, với một khoảng trắng ở giữa.

<?php
namespace VendorPackage;

class ClassName
{
    public function aVeryLongMethodName(
        ClassTypeHint $arg1,
        &$arg2,
        array $arg3 = [],
        $arg4 = true
    ) {
        // method body
    }
}

3.5. abstract, final, và static

Khi được sử dụng, abstract và final phải được đặt trước phần khai báo visibility.

Khi được sử dụng, static phải được đặt sau phần khai báo visibility.

<?php
namespace VendorPackage;

abstract class ClassName
{
    protected static $foo;

    abstract protected function zim();

    final public static function bar()
    {
        // method body
    }
}

3.6. Gọi Method và Function

Khi gọi một method hay một function thì

  1. không được phép có khoảng trắng giữa tên của method hay function và dấu mở ngoặc tròn.
  2. Không được phép có khoảng trắng sau dấu mở ngoặc tròn.
  3. Và không được phép có khoảng trắng trước dấu đóng ngoặc tròn.
  4. Trong danh sách argument, không được phép có khoảng trắng trước mỗi dấu phẩy, và phải có một khoảng trắng sau mỗi dấu phẩy.
<?php
bar (); // sai cái số 1
bar() ; // sai cái số 2
bar( ); // sai cái số 3
bar($arg1 , $arg2); // sai cái số 4

// đúng phải như vầy
bar();
$foo->bar($arg1);
Foo::bar($arg2, $arg3);

Danh sách tham số có thể được tách ra thành nhiều dòng, trong đó mỗi dòng theo sau được indent một lần. Khi làm như vậy thì tham số đầu tiên phải được đặt trên một dòng mới, và mỗi dòng chỉ được phép chứa một tham số.

<?php
$foo->bar($firstArgument // sai vì tham số đầu tiên phải ở dòng mới
$longArgument, // sai vì k có 1 canh lề
    $longerArgument, $longerArgument2, // sai vì có 2 tham số trên 1 dòng
    $muchLongerArgument
);

// chuẩn
$foo->bar(
    $longArgument,
    $longerArgument,
    $muchLongerArgument
);

4. Control Structures - cấu trúc điều khiển

Những quy tắc chung khi viết Control Structures bao gồm:

  • Phải có một khoảng trắng sau control structure keyword
  • Không được có một khoảng trắng sau dấu mở ngoặc tròn
  • Không được có một khoảng trắng trước dấu đóng ngoặc tròn
  • Phải có một khoảng trắng sau đấu đóng ngoặc tròn và trước dấu mở ngoặc nhọn
  • Phần thân của structure phải được indent một lần
  • Dấu đóng ngoặc nhọn phỉa được đặt trên một dòng mới sau phần thân

Phần thân của mỗi structure phải được đặt trong dấu đóng mở ngoặc kép. Điều này sẽ làm tiêu chuẩn hoá cách viết structures, và làm giảm thiểu việc phát sinh ra lỗi khi mà có những dòng mới được thêm vào phần thân.

5.1. if, elseif, else

Một if structure được viết như sau. Hãy chú ý đến vị trí của dấu ngoặc tròn, khoảng trắng, dấu ngoặc nhọn. else và elseif được đặt trên cùng một dòng với dấu đóng ngoặc nhọn của phần body phía trước.

<?php
if ($expr1) {
    // if body
} elseif ($expr2) {
    // elseif body
} else {
    // else body;
}

5.2. switch, case

Một switch structure được viết như sau. Hãy chú ý đến vị trí của dấu ngoặc tròn, khoảng trắng và dấu ngoặc nhọn. Phần case phải được indent một lần so với switch, và break keyword (hay các keyword ngắt khác) phải được indent giống với phần thân của case. Phải có một comment kiểu như // no break nếu phần thân của case không trống, và được cố tình cho qua (không có break)

<?php
switch ($expr) {
    case 0:
        echo 'First case, with a break';
        break;
    case 1:
        echo 'Second case, which falls through';
        // no break
    case 2:
    case 3:
    case 4:
        echo 'Third case, return instead of break';
        return;
    default:
        echo 'Default case';
        break;
}

5.3. while, do while

Một câu lệnh while được viết như sau. Hãy chú ý vào vị trí của dấu ngoặc tròn, khoảng trắng và dấu ngoặc nhọn.

<?php
while ($expr) {
    // structure body
}

Tương tự như vậy, một câu lệnh do while được viết như sau. Hãy chú ý vào vị trí của dấu ngoặc tròn, khoảng trắng và dấu ngoặc nhọn.

<?php
do {
    // structure body;
} while ($expr);

5.4. for

Một câu lệnh for được viết như sau. Hãy chú ý vào vị trí của dấu chấm phẩy, dấu ngoặc tròn, khoảng trắng và dấu ngoặc nhọn.

<?php
for ($i = 0; $i < 10; $i++) {
    // for body
}

5.5. foreach

Một câu lệnh foreach được viết như sau. Hãy chú ý vào vị trí của =>, dấu ngoặc tròn, khoảng trắng và dấu ngoặc nhọn.

<?php
foreach ($iterable as $key => $value) {
    // foreach body
}

5.6. try, catch

Một block try catch được viết như sau. Hãy chú ý vào vị trí của dấu ngoặc tròn, khoảng trắng và dấu ngoặc nhọn.

<?php
try {
    // try body
} catch (FirstExceptionType $e) {
    // catch body
} catch (OtherExceptionType $e) {
    // catch body
}

5. Closures

Closures phải được định nghĩa mới một khoảng trắng phía sau keywork function, và một khoảng trắng ở phía trước cũng như phía sau của keywork use.

Dấu mở ngoặc ngọn phải được đặt ở cùng dòng, và dấu đóng ngoặc nhọn phải được đặt ở một dòng mời phía sau phần thân.

Không được phép có một khoảng trắng ở phía sau dấu mở ngoặc tròn của phần khai báo danh sách argument hay variable, và không được phép có một khoảng trắng ở phía trước dấu đóng ngoặc tròn của phần khai báo danh sách argument hay variable.

Trong danh sách arugment hay variable, không được phép có khoảng trắng trước mỗi dấu phẩy, và phải có một khoảng trắng phía sau mỗi dấu phẩy.

Arguments của Closure mà có giá trị mặc định thì phải được đặt ở cuối của danh sách argument.

Cách định nghĩa một closure trông như sau.

A closure declaration looks like the following. Hãy chú ý vào vị trí của dấu ngoặc tròn, dấu phẩy, khoảng trắng và dấu ngoặc nhọn.

Danh sách argument và danh sách variable có thể được tách ra làm nhiều dòng, trong đó mỗi dòng theo sau được indent một lần. Khi làm như vậy thì argument hay variable đầu tiên phải được đặt ở trên một dòng mới, và mỗi dòng chỉ được phép chứa một argument hay một variable.

Khi mà kết thúc của danh sách (kể cả arguments hay variables) được chia thành nhiều dòng, thì dấu đóng ngoặc tròn và dấu mở ngoặc nhọn phải được đặt cùng nhau trên một dòng, với một khoảng trắng ở giữa.

Dưới đây là những ví dụ về các closures có và không có danh sách argument hay variable được chia thành nhiều dòng.

Chú ý rằng những quy tắc trên còn được áp dụng khi một closure được sử dụng trục tiếp như một argument trong một lời gọi hàm hay method.

6. Kết luận

Có rất nhiều yếu tố về style hay practice khác được cố tình bỏ qua trong hướng dẫn này. Có thể kể ra như:

  • Khai báo biến global (global variables) hay hằng global (global constants)

  • Khai báo hàm (functions)

  • Toán tử và phép gán

  • Inter-line alignment

  • Khối Comments và Documentation

  • Tiền tố và hậu tố trong tên Class

  • Best practices

Những recommendations sau này có thể xem xét lại và mở rộng hướng dẫn này để đề cập đến những yếu tố về style hay practice ở trên hay hoàn toàn khác.

Chúc các bạn nhớ hết các nguyên tắc này nhé

0