Hướng đối tượng và lập trình PHP phần 2

Giới thiệu

Ở phần trước chúng ta đã đi tìm hiểu về OOP và thể hiện của nó trong PHP có thể xem ở đây: https://viblo.asia/p/huong-doi-tuong-va-lap-trinh-php-phan-1-YWOZryO7KQ0. Tiếp nối phần trước phần này sẽ tìm hiểu về Trait, Namespaces, magic functionscác quy tắc trong PSR2.

Vấn đề

  • Thế nào là Traits?
  • Thế nào là Namespaces?
  • Thế nào là magic functions?
  • Tìm hiểu về các quy tắc trong PSR2?

Nội dung

1. Thế nào là Traits?

PHP, Java hay Ruby đều là những ngôn ngữ hướng đối tượng chỉ hỗ trợ single inheritance(đơn kế thừa). Để khắc phục những giới hạn của đơn kế thừa trong việc sử dụng lại source code, từ PHP 5.4 trở đi PHP hỗ trợ Traits là cơ chế giúp cho lập trình viên có thể sử dụng lại các phương thức từ các class khác nhau một cách dễ dàng hơn. Cùng làm ví dụ sau để hiểu hơn về Traits và có thể sử dụng nó trong các dự án của bạn nhé 😃)) Hôm 23/01/2018, Việt Nam có chiến thắng lịch sử trước U23 Iraq để vào chung kết U23 Châu Á gặp U23 Uzbekistan sẽ diễn ra vào ngày 27/01/2018 sắp tới. Giả sử chúng ta có class AsianCup, class Iraq và class Uzbekistan

class AsianCup
{
    public function call()
    {
        return "Việt nam vô địch!";
    }
}

class Iraq
{

}

class Uzbekistan
{

}

Vậy làm thế nào để hai class là IraqUzbekistan có thể gọi to (call()) dòng chữ ***"Việt Nam vô địch"***. Đơn giản chúng ta thường làm như thế này =)))

class AsianCup
{
    public function call()
    {
        return "Việt nam vô địch!";
    }
}

class Iraq extends AsianCup
{
    public function lose()
    {
        $this->call();
    }
}

class Uzbekistan extends AsianCup
{
    public function fear()
    {
        $this->call();
    }
}

Như vậy, Iraq và Uzbekistan đã hô to "Việt Nam vô địch" dù theo hai trạng thái và cảm xúc khác nhau 😉))). Trong trường hợp này, mới chỉ có hai nước extends, nếu có nhiều nước cùng extends thì sẽ khiến class của chúng ta trở nên công kềng và đương nhiên việc xử lý cũng sẽ chậm đi. Chính vì vậy, Trait giúp chúng ta giải quyết vấn đề này:

trait AsianCup
{
    public function call()
    {
        return "Việt nam vô địch!";
    }
}

class Iraq
{
    use AsianCup;
    public function lose()
    {
        $this->call();
    }
}

class Uzbekistan
{
    use AsianCup;
    public function fear()
    {
        $this->call();
    }
}

Câu hỏi được đặt ra là: "có thể sử dụng được nhiều Trait trong cùng 1 class không?". Đương nhiên là được chứ, cùng xem tiếp ví dụ dưới để hiểu hơn nhé.

trait AsianCup
{
    public function call()
    {
        return "Việt nam vô địch!";
    }
}

trait Final
{
   public function champion()
    {
        return "Việt nam chiến thắng!";
    }
}

class VietNam
{
    use AsianCup, Final; 
    public function __construct()
    {
        $this->champion();
    }

    public function win()
    {
        $this->call();
    }
}

2. Thế nào là Namespaces?

Namespace được xuất hiện trong khá nhiều ngôn ngữ lập trình. Trong đó có thể kể đến: C++, C#, Java,...Và trong PHP namespacecũng là một điều gì đó mà không thể thiếu được.

Vậy trong PHP Namespace là gì? Tại sao Namespace lại quan trọng đến thế? Namespace là khái niệm không quá xa lạ với những ai đang theo đuổi ngôn ngữ lập trình này.Namespace giúp tạo ra một không gian tên cho hàm và lớp trong lập trình nói chung và trong PHP nói riêng.

VD: Chúng ta có 2 file mỗi file đều chứa một class và 2 class này lại có một điểm chung là trùng tên. Giờ đây khi bạn nhúng cả 2 file này vào và gọi class thì ngay lập tức chương trình sẽ báo lỗi. Để khắc phục điều đó thì chúng ta cần khai báo namespace cho hai class đó (đọc tiếp để xem cách khai báo). Đã bao giờ các bạn nhìn thấy 2 file cùng tên file, tên class khi được gọi chúng ra 1 file nào đó, khi khởi tạo đối tượng sẽ không bị thông báo lỗi nào chưa. Tất cả là nhờ Namespace

Nếu ứng dụng của bạn chỉ nằm trong 1 bài toán nhỏ? có thể bạn không cần dùng đến nó. Nhưng khi bạn gặp 1 ứng dụng lớn, đòi hỏi khả năng Update & Upgrade thường xuyên, lúc đó bạn sẽ thấy được tầm quan trọng của nó. Tại sao? bởi vì lúc đó ứng dụng của bạn sẽ có hàng trăm hay hàng ngàn lớp khác nhau. Làm sao để bạn có thể ghi nhớ hết tất các tên lớp mà không để nó trùng nhau.

namespace app\controllers;

class NewsController
{
    public function index() 
    {
        echo __NAMESPACE__;
    }
}

3. Thế nào là magic functions?

Magic methods là các hàm đặc biệt được tự động thực hiện khi thực hiện một số hành động nhất định lên đối tượng của class đó. Magic methods luôn có dạng__<method_name>, tất cả method dạng__<method_name> đều là từ khóa được reseved của PHP Các magic methods: __construct(): constructor __destruct(): destructor __get(),__set(),__unset(): Khi cố gắng truy cập, thay đổi, xóa thuộc tính không có sẵn __call(), __callStatic(): Khi gọi hàm không có sẵn __toString(): Khi được sử dụng như string __invoke(): Khi đối tượng được sử dụng như một hàm __sleep(), __awake(): Khi gọi hàm serialize, unserialize lên đối tượng __clone(): Khi clone đối tượng __set_state(), __debugInfo(): Khi gọi var_export, var_dump lên đối tượng

4. Tìm hiểu về các quy tắc trong PSR2?

Viết code theo tiêu chuẩn PSR: PSR là tiêu chuẩn code được áp dụng vào các dự án lớn hoặc framework PHP (Cakephp, Composer, Phalcon, Magento,…). PSR bao gồm 7 phần (http://www.php-fig.org/psr/) từ PSR-1, PSR-2, PSR-3, PSR-4, PSR-6, PSR-7. Các tiêu chuẩn thành phần hoàn chỉnh của PSR đó gồm:

  • Basic Coding Standard: Tiêu chuẩn cơ bản khi viết code PHP
  • Coding Style Guide: Tiêu chuẩn trình bày code
  • Logger Interface: Giao diện logger
  • Autoloading Standard: Tiêu chuẩn về tự động nạp
  • Caching Interface: Giao diện về Caching
  • HTTP Message Interface: Tiêu chuẩn Giao diện thông điệp HTTP

Lý do bạn nên viết code theo tiêu chuẩn PSR: Viết code chuẩn giúp bạn và đồng đội dễ dàng hiểu code của nhau. Thống nhất chung về cách thức viết code, tổ chức các class,… Dễ dàng đọc, hiểu, trình bày khỏi mất công bản thân “tự chế” kiểu code không giống ai. 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.

Các quy tắc trong PSR2:

  • Code phải tuân thủ PSR-1
  • Code phải sử dụng 4 ký tự space để lùi khối (không dùng tab)
  • Mỗi dòng code phải dưới 120 ký tự, NÊN dưới 80 ký tự.
  • Phải có 1 dòng trắng sau namespace, và Phải có một dòng trắng sau mỗi khối code.
  • Ký tự mở lớp { Phải ở dòng tiếp theo, và đóng lớp } Phải ở dòng tiếp theo của thân class.
  • Ký tự { cho hàm Phải ở dòng tiếp theo, và ký tự } kết thúc hàm phải ở dòng tiếp theo của thân hàm.
  • Các visibility (public, private, protected) phải được khai báo cho tất cả các hàm và các thuộc tính của lớp;
  • Các từ khóa điều khiển khối(if, elseif, else) Phải có một khoảng trống sau chúng; hàm và lớp thì KHÔNG ĐƯỢC làm như vậy.
  • Mở khối { cho cấu trúc điều khiển phải trên cùng một dòng; và đóng khối này với } ở dòng tiếp theo của thân khối.
  • Hằng số true, false, null Phải viết với chữ thường.
  • Từ khóa extends và implements Phải cùng dòng với class
  • Implements nhiều lớp, thì mỗi lớp trên một dòng
  • Keyword var KHÔNG ĐƯỢC dùng sử dụng khai báo property.
  • Tên property KHÔNG NÊN có tiền tố _ nhằm thể hiện thuộc tính protect hay private.
  • Tham số cho hàm, phương thức: KHÔNG được thêm space vào trước dấu , và phải có một space sau ,. Các tham số CÓ THỂ trên nhiều dòng, nếu làm như vậy thì phải mỗi dòng 1 tham số.
  • Abstract, final phải đứng trước visibility, còn static phải đi sau.

Kết luận

Đọc đến đây thì cũng đã hết phần 2 rồi =))), các bạn hãy xem phần 3 ở đây nhé: